from __future__ import print_function
from __future__ import unicode_literals
from __future__ import division
from __future__ import absolute_import


from builtins import int
from future import standard_library

standard_library.install_aliases()
import os
import os.path
import stat
import urllib.parse
import paramiko
import traceback
import osaka.utils

"""
A backend used to handle stfp using parimiko

@author starchmd
"""


class SFTP(object):
    """
     SFTP handling for Osaka
    """

    def __init__(self, params={}):
        """
        Constructor
        """
        self.keyfile = params["keyfile"] if "keyfile" in params else None

    def connect(self, host=None, port=None, user=None, password=None, secure=False):
        """
        Connect to this storage medium.  All data is parsed out of the url and may be None
            scheme:
        @param host - may be None, host to connect to
                      implementor must handle defaulting
        @param port - may be None, port to connect to
                      implementor must handle a None port
        @param user - may be None, user to connect as
                      implementor must handle a None user
        @param password - may be None, password to connect with
                      implementor must handle a None password
        """
        self.client = paramiko.client.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.client.connect(
            host,
            port=22 if port is None else int(port),
            username=user,
            password=password,
            key_filename=self.keyfile,
            timeout=15,
        )
        self.sftp = self.client.open_sftp()

    @classmethod
    def getSchemes(clazz):
        """
        Returns a list of schemes this handler handles
        Note: handling the scheme of another handler produces unknown results
        @returns list of handled schemes
        """
        return ["sftp"]

    def put(self, path, url):
        """
        Put the given path to the given url
        @param path - local path of file/folder to put
        @param url - url to put file/folder to
        """
        rpath = urllib.parse.urlparse(url).path.lstrip("/")
        print("\n\n\n\nUploading:", path)
        if not os.path.isdir(path):
            print("As file")
            try:
                self.sftp.mkdir(os.path.dirname(rpath))
            except IOError:
                pass
            dest = rpath
            try:
                if stat.S_ISDIR(self.sftp.stat(rpath).st_mode) != 0:
                    dest = os.path.join(rpath, os.path.basename(path))
            except:
                pass
            return self.upload(path, dest)
        print("As Dir")
        try:
            self.sftp.mkdir(rpath)
        except IOError:
            pass
        for dirpath, dirname, filenames in os.walk(path):
            extra = os.path.relpath(dirpath, os.path.dirname(path))
            try:
                self.sftp.mkdir(os.path.join(rpath, extra))
            except IOError:
                pass
            for filename in filenames:
                self.upload(
                    os.path.join(dirpath, filename),
                    os.path.join(rpath, extra, filename),
                )

    def upload(self, path, rpath):
        """
        Uploads a file to remote path
        @param path - path to upload
        @param rpath - remote path to upload to
        """
        self.sftp.put(path, rpath)
        return True

    def get(self, url, path):
        """
        Get the url (file/folder) to local path
        @param url - url to get file/folder from
        @param path - path to place fetched files
        """
        rpath = urllib.parse.urlparse(url).path
        try:
            self.sftp.get(rpath, path)
        except Exception as e:
            osaka.utils.LOGGER.warning(
                "Encountered exception: {}\n{}".format(e, traceback.format_exc())
            )
            raise osaka.utils.OsakaFileNotFound("File {} doesn't exist.".format(url))

    def rm(self, url):
        """
        Remove the item
        @param url - url to remove
        """
        rpath = urllib.parse.urlparse(url).path
        self.sftp.remove(rpath)

    def close(self):
        """
        Close this connection
        """
        self.client.close()

[((10, 0, 10, 34), 'future.standard_library.install_aliases', 'standard_library.install_aliases', ({}, {}), '()', False, 'from future import standard_library\n'), ((50, 22, 50, 49), 'paramiko.client.SSHClient', 'paramiko.client.SSHClient', ({}, {}), '()', False, 'import paramiko\n'), ((97, 43, 97, 56), 'os.walk', 'os.walk', ({(97, 51, 97, 55): 'path'}, {}), '(path)', False, 'import os\n'), ((51, 48, 51, 72), 'paramiko.AutoAddPolicy', 'paramiko.AutoAddPolicy', ({}, {}), '()', False, 'import paramiko\n'), ((79, 15, 79, 34), 'os.path.isdir', 'os.path.isdir', ({(79, 29, 79, 33): 'path'}, {}), '(path)', False, 'import os\n'), ((98, 45, 98, 66), 'os.path.dirname', 'os.path.dirname', ({(98, 61, 98, 65): 'path'}, {}), '(path)', False, 'import os\n'), ((54, 41, 54, 50), 'builtins.int', 'int', ({(54, 45, 54, 49): 'port'}, {}), '(port)', False, 'from builtins import int\n'), ((82, 32, 82, 54), 'os.path.dirname', 'os.path.dirname', ({(82, 48, 82, 53): 'rpath'}, {}), '(rpath)', False, 'import os\n'), ((100, 32, 100, 58), 'os.path.join', 'os.path.join', ({(100, 45, 100, 50): 'rpath', (100, 52, 100, 57): 'extra'}, {}), '(rpath, extra)', False, 'import os\n'), ((105, 20, 105, 51), 'os.path.join', 'os.path.join', ({(105, 33, 105, 40): 'dirpath', (105, 42, 105, 50): 'filename'}, {}), '(dirpath, filename)', False, 'import os\n'), ((106, 20, 106, 56), 'os.path.join', 'os.path.join', ({(106, 33, 106, 38): 'rpath', (106, 40, 106, 45): 'extra', (106, 47, 106, 55): 'filename'}, {}), '(rpath, extra, filename)', False, 'import os\n'), ((88, 47, 88, 69), 'os.path.basename', 'os.path.basename', ({(88, 64, 88, 68): 'path'}, {}), '(path)', False, 'import os\n'), ((129, 58, 129, 80), 'traceback.format_exc', 'traceback.format_exc', ({}, {}), '()', False, 'import traceback\n')]