###################################################################################
# LAVA QA tool
# Copyright (C) 2015  Luis Araujo <luis.araujo@collabora.co.uk>

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  US
###################################################################################

import os
import yaml
import logging
import os.path
from urlparse import urlsplit, urlunsplit
from lqa_api.exit_codes import APPLICATION_ERROR

CONFIG_PATH=os.getenv("HOME") + '/.config/'
LAVA_CONFIG='lqa.yaml'

lqa_logger = logging.getLogger('lqa')

class Settings(object):
    """Initialize settings for command objects.

    :param cmd: The command object to setup
    :param default_config_file: The default configuration file path"""

    def __init__(self):
        pass

    def load_config(self, config_file=None, log_file=None):
        # Set looger
        # Log to file using formatter if --log-file passed, otherwise to stderr
        if log_file:
            hdl = logging.FileHandler(filename=log_file)
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s '
                                          '- %(message)s')
            hdl.setFormatter(formatter)
        else:
            hdl = logging.StreamHandler()
        lqa_logger.addHandler(hdl)
        lqa_logger.setLevel(logging.DEBUG)

        # Check for the configuration file and retrieve values
        self.config_file = self.find_config_file(config_file)
        # Set yaml configuration
        try:
            with open(self.config_file) as conf_data:
                self.config = yaml.safe_load(conf_data)
        except EnvironmentError as e:
            lqa_logger.error(e)
            exit(APPLICATION_ERROR)
        except yaml.scanner.ScannerError as e:
            lqa_logger.error(e)
            exit(APPLICATION_ERROR)

        # After loading the configuration file, check the minimum required values
        # and set the rpc_url.
        self.check_config_fields(['user', 'auth-token', 'server'])
        self.rpc_url = self._build_rpc_api_url()

    def find_config_file(self, config_file = None):
        """Find the configuration file.

        It follows the priority:

         1) config file passed e.g. via -c/--config to the cli

         2) LQA_CONFIG_FILE environment variable value if it is set

         3) local 'CONF.yaml' file

         4) global CONF.yaml file from $HOME/.config/

        :param config: Optional override of the default

        :returns: The found and available configuration file in the system
        """
        default_config_path = os.path.join(CONFIG_PATH, LAVA_CONFIG)
        lqa_config_file = os.getenv("LQA_CONFIG_FILE")
        if config_file:
            if not os.path.isfile(config_file):
                lqa_logger.error("Configuration file '{}' not found"
                                 .format(config_file))
                exit(APPLICATION_ERROR)
        elif lqa_config_file:
            config_file = lqa_config_file
        elif os.path.isfile(os.path.join(os.getcwd(), LAVA_CONFIG)):
            config_file = os.path.join(os.getcwd(), LAVA_CONFIG)
        elif os.path.isfile(default_config_path):
            config_file = default_config_path
        else:
            # No config file?.. exit
            lqa_logger.error("Configuration file '{}' not found. Or use the "
                             "-c/--config flag to specify a different file"
                             .format(default_config_path))
            exit(APPLICATION_ERROR)
        return config_file

    def check_config_fields(self, config_fields):
        """Check that the configuration file has the required fields to proceed"""
        # Make sure config exists since it can be None if no yaml 
        # fields are defined.
        if self.config:
            for field in config_fields:
                if field not in self.config:
                    lqa_logger.error("Required field '{}' not found in "
                                     "configuration file {}"
                                     .format(field, self.config_file))
                    exit(APPLICATION_ERROR)
        else:
            lqa_logger.error("No configuration fields available in file {}"
                             .format(self.config_file))
            exit(APPLICATION_ERROR)

    def _build_rpc_api_url(self):
        (scheme, netloc, _, _, _) = urlsplit(self.config['server'])
        if not scheme or not netloc:
            lqa_logger.error("The syntax '{}' for server field is not valid at {}"
                             .format(self.config['server'],
                                     self.config_file))
            lqa_logger.error("Please use the form '[scheme]://[address]/' for the "
                             "server field")
            exit(APPLICATION_ERROR)

        return urlunsplit((scheme,
                           "{}:{}@{}".format(self.config['user'],
                                             self.config['auth-token'],
                                             netloc),
                           'RPC2', '', ''))

settings = Settings()
