from parallels.core import safe_utf8_encode
from parallels.core.application.base import ApplicationModel, SingleConfigApplicationInstance
from parallels.core.application.utils import replace_database_host_line, replace_line_bounds, get_database
from parallels.core.logging import get_logger
from parallels.core.utils.common import cached, safe_format
from parallels.core.utils.message_utils import multi_line_message
from parallels.plesk.source.web import messages

logger = get_logger(__name__)


class JoomlaModel(ApplicationModel):
    @property
    def id(self):
        return 'joomla'

    @property
    def name(self):
        return 'Joomla!'

    def get_instance(self, server, base_path):
        """Retrieve instance of Joomla!

        :type server: parallels.core.connections.server.Server
        :type base_path: str
        :rtype: parallels.core.application.joomla.JoomlaInstance
        """
        return JoomlaInstance(server,  safe_utf8_encode(base_path))

    def get_supported_database_types(self):
        return [self.DATABASE_TYPE_MYSQL]

    def _search_file(self, server, file_path, file_name):
        binary_file_path = safe_utf8_encode(file_path)
        if file_name != 'configuration.php':
            return None
        file_contents = self._safe_get_file_contents(server, binary_file_path)
        if file_contents is None:
            return
        if 'jconfig' not in file_contents.lower():
            return None

        return self.get_instance(server, server.get_base_path(binary_file_path))

    def _search_directory(self, server, directory_path, directory_name, directory_tree):
        return None


class JoomlaInstance(SingleConfigApplicationInstance):
    @property
    def description(self):
        return safe_format(messages.APPLICATION_DESCRIPTION_JOOMLA, base_path=self.base_path)

    @property
    @cached
    def config_file_path(self):
        config_path = self.server.join_file_path(self.base_path, 'configuration.php')
        with self.server.runner() as runner:
            if runner.file_exists(config_path):
                return config_path
        return None

    def get_databases(self):
        php_code = multi_line_message("""
        <?php
        include '{config_file_path}';
        $jconfig = new JConfig;
        echo json_encode(array(
            'host' => $jconfig->host,
            'username' => $jconfig->user,
            'password' => $jconfig->password,
            'name' => $jconfig->db,
        ));
        """).encode('ascii').format(config_file_path=self.config_file_path)
        return [get_database(php_code, self)]

    def _get_database_hostname_replace_result(self, config_file_contents, database_hostname_mapping):
        """Replace database hostnames in configuration file of application, provided by string

        :type config_file_contents: str | unicode
        :type database_hostname_mapping: dict[str | unicode, str | unicode]
        :rtype: parallels.core.utils.line_processor.ReplaceResults
        """
        # Default config has line like:
        # public $host = '192.168.1.2'
        return replace_database_host_line(
            config_file_contents,
            '$host', """public\s*\$host\s*=\s*['"]""", """(:|['"];)""",
            database_hostname_mapping,
            regex=True
        )

    def _get_database_name_replace_result(self, config_file_contents, database_name_mapping):
        """Replace database names in configuration file of application, provided by string

        :type config_file_contents: str | unicode
        :type database_name_mapping: dict[str | unicode, str | unicode]
        :rtype: parallels.core.utils.line_processor.ReplaceResults
        """
        # Default config has line like:
        # public $db = 'myjoomla1';
        return replace_line_bounds(
            config_file_contents,
            ['$db'], ["""public\s*\$db\s*=\s*['"]"""], """['"];""",
            database_name_mapping,
            regex=True
        )

    def _get_database_user_name_replace_result(self, config_file_contents, database_user_name_mapping):
        """Replace database user names in configuration file of application, provided by string

        :type config_file_contents: str | unicode
        :type database_user_name_mapping: dict[str | unicode, str | unicode]
        :rtype: parallels.core.utils.line_processor.ReplaceResults
        """
        # Default config has line like:
        # public $user = 'myjoomla1';
        return replace_line_bounds(
            config_file_contents,
            ['$user'], ["""public\s*\$user\s*=\s*['"]"""], """['"];""",
            database_user_name_mapping,
            regex=True
        )
