import posixpath

from parallels.core import messages
from parallels.core.utils.paths import web_paths
from parallels.core.utils.paths.copy_web_content import BaseWebPathConverter
from parallels.core.utils.plesk_utils import convert_wildcard_to_path


class UnixTargetWebPathConverter(BaseWebPathConverter):
    """Class to convert abstract path descriptor to concrete absolute path on target Plesk server"""

    def expand(self, path, server):
        """Convert abstract path descriptor to concrete absolute path on target Plesk server

        :type path: parallels.core.utils.web_paths.WebHostingPath
        :type server: parallels.plesk.connections.target_server.PleskTargetServer
        :rtype: str | unicode
        """
        if isinstance(path, web_paths.AbsolutePath):
            return path.absolute_path
        elif isinstance(path, web_paths.WebspacePath):
            return self._expand_webspace_path(path, server)
        elif isinstance(path, web_paths.SitePath):
            return self._expand_site_path(path, server)
        else:
            assert False, messages.UNSUPPORTED_TARGET_WEB_PATH_TYPE

    def _expand_webspace_path(self, path, server):
        """
        :type path: parallels.core.utils.web_paths.WebspacePath
        :type server: parallels.plesk.connections.target_server.PleskTargetServer
        :rtype: str | unicode
        """
        target_path = path.webspace.name.encode('idna')
        if server.get_plesk_version()[:2] >= (17, 9):
            target_path = target_path.lower()
        webspace_root_path = posixpath.join(
            server.vhosts_dir, target_path
        )
        webpace_wwwroot_path = posixpath.join(webspace_root_path, path.webspace.www_root)
        webspace_system_path = posixpath.join(
            server.vhosts_dir, 'system', target_path
        )
        if isinstance(path, web_paths.WebspaceRoot):
            return webspace_root_path
        elif isinstance(path, web_paths.WebspaceDocumentRoot):
            return webpace_wwwroot_path
        elif isinstance(path, web_paths.WebspaceCGIBin):
            return posixpath.join(webpace_wwwroot_path, 'cgi-bin')
        elif isinstance(path, web_paths.WebspaceStatistics):
            return posixpath.join(webspace_system_path, 'statistics')
        elif isinstance(path, web_paths.WebspaceLogs):
            return posixpath.join(webspace_system_path, 'logs')
        elif isinstance(path, web_paths.WebspaceProtectedDirs):
            return posixpath.join(webspace_system_path, 'pd')
        elif isinstance(path, web_paths.WebspaceAnonFTPPub):
            return posixpath.join(webspace_root_path, 'anon_ftp/pub')
        elif isinstance(path, web_paths.WebspaceAnonFTPIncoming):
            return posixpath.join(webspace_root_path, 'anon_ftp/incoming')
        elif isinstance(path, web_paths.WebspaceWebUser):
            return posixpath.join(webspace_root_path, 'web_users/%s' % path.webuser_name)
        elif isinstance(path, web_paths.WebspacePathTemplate):
            return self._expand_webspace_template(path, server)
        else:
            assert False, messages.UNSUPPORTED_TARGET_WEB_PATH_TYPE

    def _expand_site_path(self, path, server):
        """
        :type path: parallels.core.utils.web_paths.SitePath
        :type server: parallels.plesk.connections.target_server.PleskTargetServer
        :rtype: str | unicode
        """
        target_path = path.site.name.encode('idna')
        if server.get_plesk_version()[:2] >= (17, 9):
            target_path = target_path.lower()
        site_system_path = posixpath.join(
            server.vhosts_dir, 'system',
            convert_wildcard_to_path(target_path)
        )
        if isinstance(path, web_paths.SiteDocumentRoot):
            return self._get_site_wwwroot_path(path, server)
        elif isinstance(path, web_paths.SiteCGIBin):
            return posixpath.join(self._get_site_wwwroot_path(path, server), 'cgi-bin')
        elif isinstance(path, web_paths.SiteStatistics):
            return posixpath.join(site_system_path, 'statistics')
        elif isinstance(path, web_paths.SiteLogs):
            return posixpath.join(site_system_path, 'logs')
        elif isinstance(path, web_paths.SiteProtectedDirs):
            return posixpath.join(site_system_path, 'pd')
        elif isinstance(path, web_paths.SitePathTemplate):
            return self._expand_site_template(path, server)
        else:
            assert False, messages.UNSUPPORTED_TARGET_WEB_PATH_TYPE

    @staticmethod
    def _get_site_wwwroot_path(path, server):
        """
        :type path: parallels.core.utils.web_paths.SitePath
        :type server: parallels.plesk.connections.target_server.PleskTargetServer
        :rtype: str | unicode
        """
        return posixpath.join(
            server.vhosts_dir, path.webspace.name.encode('idna'), path.site.www_root
        )

    def _expand_webspace_template(self, path, server):
        """
        :type path: parallels.core.utils.web_paths.WebspacePathTemplate
        :type server: parallels.plesk.connections.target_server.PleskTargetServer
        :rtype: str | unicode
        """
        variable_paths = {
            'webspace_root': web_paths.WebspaceRoot,
            'document_root': web_paths.WebspaceDocumentRoot,
            'cgi_bin': web_paths.WebspaceCGIBin,
            'statistics': web_paths.WebspaceStatistics,
            'logs': web_paths.WebspaceLogs,
            'protected_dirs': web_paths.WebspaceProtectedDirs,
            'anon_ftp_pub': web_paths.WebspaceAnonFTPIncoming,
            'anon_ftp_incoming': web_paths.WebspaceAnonFTPIncoming,
        }
        variables = {}
        for var_name, path_class in variable_paths.items():
            variables[var_name] = self.expand(path_class(path.webspace), server)
        variables['webspace'] = path.webspace.name
        variables['webspace_idn'] = path.webspace.name.encode('idna')

        return path.template.format(**variables)

    def _expand_site_template(self, path, server):
        """
        :type path: parallels.core.utils.web_paths.SitePathTemplate
        :type server: parallels.plesk.connections.target_server.PleskTargetServer
        :rtype: str | unicode
        """
        webspace_variable_paths = {
            'webspace_root': web_paths.WebspaceRoot,
            'webspace_document_root': web_paths.WebspaceDocumentRoot,
            'webspace_cgi_bin': web_paths.WebspaceCGIBin,
            'webspace_statistics': web_paths.WebspaceStatistics,
            'webspace_logs': web_paths.WebspaceLogs,
            'webspace_protected_dirs': web_paths.WebspaceProtectedDirs,
            'webspace_anon_ftp_pub': web_paths.WebspaceAnonFTPIncoming,
            'webspace_anon_ftp_incoming': web_paths.WebspaceAnonFTPIncoming,
        }
        site_variable_paths = {
            'document_root': web_paths.SiteDocumentRoot,
            'cgi_bin': web_paths.SiteCGIBin,
            'statistics': web_paths.SiteStatistics,
            'logs': web_paths.SiteLogs,
            'protected_dirs': web_paths.SiteProtectedDirs,
        }
        variables = {}
        for var_name, path_class in webspace_variable_paths.items():
            variables[var_name] = self.expand(
                path_class(path.webspace), server
            )
        for var_name, path_class in site_variable_paths.items():
            variables[var_name] = self.expand(
                path_class(path.webspace, path.site), server
            )
        variables['webspace'] = path.webspace.name
        variables['webspace_idn'] = path.webspace.name.encode('idna')
        variables['site'] = path.site.name
        variables['site_idn'] = path.site.name.encode('idna')

        return path.template.format(**variables)
