import os
import sys
import random
import string
import logging
import itertools
import cStringIO
from xml.dom import minidom
from encoder import EncoderFile
from xml.parsers.expat import ExpatError

import pmm_config
import plesk_config
from pmm_api_xml_protocols import DumpsStorageCredentials, DumpSpecification


mswindows = (sys.platform == "win32")


_logger = logging.getLogger("pmmcli.dump_formatter")


def containsAny(seq, aset):
    for item in itertools.ifilter(aset.__contains__, seq):
        return True
    return False


class DumpsStorageCredentialsFormatException(Exception):
    def __init__(self, dump_storage_credentials, message):
        Exception.__init__(self, message)
        self.__message = message
        self.__dump_storage_credentials = dump_storage_credentials
        _logger.info("DumpsStorageCredentialsFormatException generated: " + str(self))

    def get_message(self):
        return self.__message

    def __str__(self):
        return "<" + str(self.__dump_storage_credentials) + ", " + self.__message + ">"


def getLocalDumpsStorageCredentialsFormatter():
    dumps_storage_credentials = DumpsStorageCredentials( storage_type = 'local', hostname = 'localhost')
    local_dump_directory = plesk_config.get("DUMP_D")
    dumps_storage_credentials.set_root_dir(local_dump_directory)
    return DumpsStorageCredentialsFormatter(dumps_storage_credentials)


def getTempFileDumpsStorageCredentialsFormatter():
    dumps_storage_credentials = DumpsStorageCredentials( storage_type = 'file', hostname = 'localhost')
    temp_file_dump_directory = pmm_config.tmp_directory()
    dumps_storage_credentials.set_root_dir(temp_file_dump_directory)
    temp_file_name = "".join([random.choice(string.letters+string.digits) for item in range(1, 9)])
    dumps_storage_credentials.set_file_name(temp_file_name)
    return DumpsStorageCredentialsFormatter(dumps_storage_credentials)


class DumpsStorageCredentialsFormatter:
    def __init__(self, dumps_storage_credentials):
        self.__login = None
        self.__password = None
        self.__storage_type = None
        self.__use_passive_ftp_mode = "false"
        self.__hostname = None
        self.__root_dir = None
        self.__file_name = None
        self.__ignore_backup_sign = None

        if isinstance(dumps_storage_credentials,DumpsStorageCredentialsFormatter):
            self.__login = dumps_storage_credentials.get_login()
            self.__password = dumps_storage_credentials.get_password()
            self.__storage_type = dumps_storage_credentials.get_storage_type()
            self.__use_passive_ftp_mode = dumps_storage_credentials.get_use_passive_ftp_mode()
            self.__hostname = dumps_storage_credentials.get_hostname()
            self.__root_dir = dumps_storage_credentials.get_root_dir()
            self.__file_name = dumps_storage_credentials.get_file_name()
            self.__ignore_backup_sign = dumps_storage_credentials.get_ignore_backup_sign()
        else:
            self.parse(dumps_storage_credentials)

    def __verify_login(self, login):
        return login

    def __verify_password(self, password):
        return password

    def __verify_storage_type(self, storage_type):
        if not storage_type in ['local','file','foreign-ftp']:
            raise DumpsStorageCredentialsFormatException(storage_type,'storage_type has invalid format: ' + storage_type)
        return storage_type

    def __verify_use_passive_ftp_mode(self, use_passive_ftp_mode):
        if use_passive_ftp_mode == 'true':
            return 'true'
        else:
            return 'false'

    def __verify_ignore_backup_sign(self, value):
        if value == 'true':
            return 'true'
        else:
            return 'false'

    def __verify_hostname(self, hostname):
        if '/' in hostname:
            raise DumpsStorageCredentialsFormatException(hostname,'hostname has invalid format')
        return hostname

    def __verify_root_dir(self, root_dir):
        if root_dir != '':
            if self.__storage_type != 'foreign-ftp':
                return os.path.normpath(root_dir).strip('/\\')
            else:
                if root_dir == '/':
                    return root_dir
                else:
                    return root_dir.rstrip('/\\')
        else:
            return root_dir

    def __verify_file_name(self, file_name):
        if file_name != '':
            return os.path.normpath(file_name).lstrip('/\\')
        else:
            return file_name

    def parse(self, dumps_storage_credentials):
        if isinstance(dumps_storage_credentials,DumpsStorageCredentials):
            self.__login = self.__verify_login(dumps_storage_credentials.get_login())
            self.__password = self.__verify_password(dumps_storage_credentials.get_password())
            self.__storage_type = self.__verify_storage_type(dumps_storage_credentials.get_storage_type())
            self.__use_passive_ftp_mode = self.__verify_use_passive_ftp_mode(dumps_storage_credentials.get_use_passive_ftp_mode())
            self.__hostname = self.__verify_hostname(dumps_storage_credentials.get_hostname())
            self.__root_dir = self.__verify_root_dir(dumps_storage_credentials.get_root_dir())
            self.__file_name = self.__verify_file_name(dumps_storage_credentials.get_file_name())
            self.__ignore_backup_sign = self.__verify_ignore_backup_sign(dumps_storage_credentials.get_ignore_backup_sign())
        else:
            try:
                d_s_c = DumpsStorageCredentials.factory()
                d_s_c.build(minidom.parseString(dumps_storage_credentials).childNodes[0])
                self.__login = self.__verify_login(d_s_c.get_login())
                self.__password = self.__verify_password(d_s_c.get_password())
                self.__storage_type = self.__verify_storage_type(d_s_c.get_storage_type())
                self.__use_passive_ftp_mode = self.__verify_use_passive_ftp_mode(d_s_c.get_use_passive_ftp_mode())
                self.__hostname = self.__verify_hostname(d_s_c.get_hostname())
                self.__root_dir = self.__verify_root_dir(d_s_c.get_root_dir())
                self.__file_name = self.__verify_file_name(d_s_c.get_file_name())
                self.__ignore_backup_sign = self.__verify_ignore_backup_sign(d_s_c.get_ignore_backup_sign())
            except ExpatError:
                raise DumpsStorageCredentialsFormatException(dumps_storage_credentials,'Unable to initialize DumpsStorageCredentialsFormatter: input has invalid format')

    def buildXml(self):
        return DumpsStorageCredentials(storage_type = self.__storage_type, use_passive_ftp_mode = self.__use_passive_ftp_mode, login = self.__login, password = self.__password, hostname = self.__hostname, root_dir = self.__root_dir, file_name = self.__file_name)

    def buildString(self):
        dumps_storage_credentials = self.buildXml()
        resp_str = cStringIO.StringIO()
        resp_encoded = EncoderFile(resp_str, "utf-8")
        dumps_storage_credentials.export(resp_encoded, 0, name_ = 'dumps-storage-credentials')
        return resp_str.getvalue()

    def getDumpStorageNoLogin(self):
        path = ''
        if self.__storage_type == 'foreign-ftp':
            path = 'ftp://' + self.__hostname + '/'
            if self.__root_dir != '':
                path = path + self.__root_dir + '/'
        else:
            if not mswindows:
                path = '/'
                if self.__root_dir != '':
                    path = path + self.__root_dir + '/'
            else:
                path = self.__root_dir + '\\'
        return path

    def getDumpStorage(self):
        path = ''
        if self.__storage_type == 'foreign-ftp':
            path = 'ftp://' + self.__login + '@' + self.__hostname + '/'
            if self.__root_dir != '':
                if self.__root_dir == '/':
                    path = path + '/'
                else:
                    path = path + self.__root_dir + '/'
        else:
            if not mswindows:
                path = '/'
                if self.__root_dir != '':
                    path = path + self.__root_dir + '/'
            else:
                path = self.__root_dir + '\\'
        return path

    def getFileDumpStorage(self):
        path = self.getDumpStorage()
        if self.__storage_type == 'foreign-ftp' and self.__file_name != '':
            path = path + self.__file_name
        if self.__storage_type == 'file' and self.__file_name != '':
            path = os.path.join( path, self.__file_name)
        return path

    def get_login(self):
        return self.__login

    def get_password(self):
        return self.__password

    def get_storage_type(self):
        return self.__storage_type

    def get_use_passive_ftp_mode(self):
        return self.__use_passive_ftp_mode

    def get_hostname(self):
        return self.__hostname

    def get_root_dir(self):
        return self.__root_dir

    def get_file_name(self):
        return self.__file_name

    def get_ignore_backup_sign(self):
        return self.__ignore_backup_sign

    def set_ignore_backup_sign(self, value):
        self.__ignore_backup_sign = value

class DumpSpecificationFormatException(Exception):
    def __init__(self, dump_specification, message):
        Exception.__init__(self, message)
        self.__message = message
        self.__dump_specification = dump_specification
        _logger.info("DumpSpecificationFormatException generated: " + str(self))

    def get_message(self):
        return self.__message

    def __str__(self):
        return "<" + str(self.__dump_specification) + ", " + self.__message + ">"


def getLocalDumpSpecificationFormatter(relative_filename):
    dumps_storage_credentials_object = getLocalDumpsStorageCredentialsFormatter()
    local_dump_specification = DumpSpecification( dumps_storage_credentials = dumps_storage_credentials_object, name_of_info_xml_file = relative_filename)
    return DumpSpecificationFormatter(local_dump_specification)


def getTempFileDumpSpecificationFormatter():
    dumps_storage_credentials_object = getTempFileDumpsStorageCredentialsFormatter()
    temp_file_dump_specification = DumpSpecification( dumps_storage_credentials = dumps_storage_credentials_object)
    return DumpSpecificationFormatter(temp_file_dump_specification)


class DumpSpecificationFormatter:
    def __init__(self, dump_specification):
        self.__name_of_info_xml_file = None
        self.__dumps_storage_credentials_formatter = None
        
        if isinstance(dump_specification,DumpSpecificationFormatter):
            self.__name_of_info_xml_file = dump_specification.get_name_of_xml_file()
            self.__dumps_storage_credentials_formatter = dump_specification.get_dumps_storage_credentials_formatter()
        else:
            self.parse(dump_specification)

    def __verify_name_of_info_xml_file(self, name_of_info_xml_file):
        name = name_of_info_xml_file.lstrip('/')
        return name

    def parse(self, dump_specification):
        if isinstance(dump_specification,DumpSpecification):
            self.__dumps_storage_credentials_formatter = DumpsStorageCredentialsFormatter(dump_specification.get_dumps_storage_credentials())
            self.__name_of_info_xml_file = self.__verify_name_of_info_xml_file(dump_specification.get_name_of_info_xml_file())
        else:
            try:
                d_s = DumpSpecification.factory()
                d_s.build(minidom.parseString(dump_specification).childNodes[0])
                self.__dumps_storage_credentials_formatter = DumpsStorageCredentialsFormatter(d_s.get_dumps_storage_credentials())
                self.__name_of_info_xml_file = self.__verify_name_of_info_xml_file(d_s.get_name_of_info_xml_file())
            except ExpatError:
                raise DumpSpecificationFormatException(dump_specification,'Unable to initialize DumpSpecificationFormatter: input has invalid format')

    def buildXml(self):
        return DumpSpecification(dumps_storage_credentials = self.__dumps_storage_credentials_formatter.buildXml(), name_of_info_xml_file = self.__name_of_info_xml_file)

    def buildString(self):
        dump_specification = self.buildXml()
        resp_str = cStringIO.StringIO()
        resp_encoded = EncoderFile(resp_str, "utf-8")
        dump_specification.export(resp_encoded, 0, name_ = 'dump-specification')
        return resp_str.getvalue()

    def get_dumps_storage_credentials_formatter(self):
        return self.__dumps_storage_credentials_formatter

    def get_name_of_xml_file(self):
        return self.__name_of_info_xml_file

    def set_name_of_xml_file(self, name_of_info_xml_file):
        self.__name_of_info_xml_file = name_of_info_xml_file

    def get_destination_file(self):
        if self.__dumps_storage_credentials_formatter.get_storage_type() == 'local' and self.__name_of_info_xml_file != '':
            return os.path.join(self.__dumps_storage_credentials_formatter.getFileDumpStorage(), self.__name_of_info_xml_file)
        else:
            return self.__dumps_storage_credentials_formatter.getFileDumpStorage()
