# vim: set expandtab sw=4 ts=4:
# pylint: disable=invalid-name,too-few-public-methods
'''
Manages settings of buildtime trend

Copyright (C) 2014 Dieter Adriaenssens <ruleant@users.sourceforge.net>

This file is part of buildtimetrend/python-lib
<https://github.com/buildtimetrend/python-lib/>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.

This program 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
'''

import sys
import os
import getopt
import yaml
import keen
import buildtimetrend
from buildtimetrend.collection import Collection
from buildtimetrend.tools import check_file
from buildtimetrend.tools import set_loglevel
from buildtimetrend.tools import get_logger


class Settings(object):
    '''
    Settings class is a singleton
    Inspired by
 http://python-3-patterns-idioms-test.readthedocs.org/en/latest/Singleton.html
    '''
    class __Settings(object):
        '''
        Settings class contains settings and config options
        '''
        def __init__(self):
            '''
            Initialise class
            '''
            self.settings = Collection()

            # set default project name
            self.set_project_name(buildtimetrend.NAME)

            # set modes
            self.add_setting("mode_native", False)
            self.add_setting("mode_keen", True)

        def set_project_name(self, name):
            '''
            Set project name
            Parameters :
            - name : project name
            '''
            self.add_setting("project_name", name)

        def get_project_name(self):
            '''
            Get project name
            '''
            return self.get_setting("project_name")

        def add_setting(self, name, value):
            '''
            Add a setting

            Parameters :
            - name : Setting name
            - value : Setting value
            '''
            self.settings.add_item(name, value)

        def get_setting(self, name):
            '''
            Get a setting value

            Parameters :
            - name : Setting name
            '''
            return self.settings.get_item(name)

        def load_config_file(self, config_file):
            '''
            Load settings from a config file

            Parameters :
            - config_file : name of the config file
            '''
            if not check_file(config_file):
                return False

            with open(config_file, 'rb') as file_stream:
                config = yaml.load(file_stream)
                self.settings.add_items(config["buildtimetrend"])

                # set Keen.io settings
                if "keen" in config:
                    if "project_id" in config["keen"]:
                        keen.project_id = config["keen"]["project_id"]
                    if "write_key" in config["keen"]:
                        keen.write_key = config["keen"]["write_key"]
                    if "read_key" in config["keen"]:
                        keen.read_key = config["keen"]["read_key"]
                return True

        def get_project_info(self):
            '''
            Get project info as a dictonary
            '''
            return {
                "version": buildtimetrend.VERSION,
                "schema_version": buildtimetrend.SCHEMA_VERSION,
                "project_name": str(self.get_project_name())
            }

        def process_argv(self, argv):
            '''
            Process command line arguments
            '''
            usage_string = '%s -h --log=<log_level> --build=<buildID>' \
                ' --job=<jobID> --branch=<branchname> --repo=<repo_slug>' \
                ' --ci=<ci_platform> --result=<build_result>' \
                ' --mode=<storage_mode>' % \
                argv[0]

            try:
                opts, args = getopt.getopt(
                    argv[1:], "h", [
                        "log=",
                        "build=", "job=", "branch=", "repo=",
                        "ci=", "result=", "mode=", "help"]
                )
            except getopt.GetoptError:
                print usage_string
                sys.exit(2)

            # check options
            for opt, arg in opts:
                if opt in ('-h', "--help"):
                    print usage_string
                    sys.exit()
                elif opt == "--log":
                    set_loglevel(arg)
                elif opt == "--build":
                    self.add_setting("build", arg)
                elif opt == "--job":
                    self.add_setting("job", arg)
                elif opt == "--branch":
                    self.add_setting("branch", arg)
                elif opt == "--repo":
                    self.set_project_name(arg)
                elif opt == "--ci":
                    self.add_setting("ci_platform", arg)
                elif opt == "--result":
                    self.add_setting("result", arg)
                elif opt == "--mode":
                    if arg == "native":
                        self.add_setting("mode_native", True)
                    elif arg == "keen":
                        self.add_setting("mode_keen", True)

            return args

        def load_env_vars(self):
            '''
            Load environment variables and assign their values to
            the corresponding setting value.
            '''
            # assign environment variable values to setting value
            self.env_var_to_settings("TRAVIS_ACCOUNT_TOKEN",
                                     "travis_account_token")

        def env_var_to_settings(self, env_var_name, settings_name):
            '''
            Store environment variable value as a setting
            Parameters:
            - env_var_name : Name of the environment variable
            - settings_name : Name of the corresponding settings value
            '''
            logger = get_logger()

            if env_var_name in os.environ:
                self.add_setting(settings_name, os.environ[env_var_name])
                logger.debug(
                    "Setting %s was set to %s",
                    settings_name, os.environ[env_var_name])
                return True
            else:
                logger.debug(
                    "Setting %s was not set,"
                    " environment variable %s doesn't exist",
                    settings_name, env_var_name)
                return False

    instance = None

    def __new__(cls):  # __new__ always a classmethod
        ''' Create a singleton '''
        if not Settings.instance:
            Settings.instance = Settings.__Settings()
        return Settings.instance

    def __getattr__(self, name):
        ''' Redirect access to get singleton properties '''
        return getattr(self.instance, name)

    def __setattr__(self, name):
        ''' Redirect access to set singleton properties '''
        return setattr(self.instance, name)

@@ -4272,16 +4272,237 @@
 rgv%5B0%5D%0A%0A
+            options = %7B%0A                %22--build%22: %22build%22,%0A                %22--job%22: %22job%22,%0A                %22--branch%22: %22branch%22,%0A                %22--ci%22: %22ci_platform%22,%0A                %22--result%22: %22result%22%0A            %7D%0A%0A
         
@@ -5145,516 +5145,156 @@
 opt 
-== %22--build%22:%0A                    self.add_setting(%22build%22, arg)%0A                elif opt == %22--job%22:%0A                    self.add_setting(%22job%22, arg)%0A                elif opt == %22--branch%22:%0A                    self.add_setting(%22branch%22, arg)%0A                elif opt == %22--repo%22:%0A                    self.set_project_name(arg)%0A                elif opt == %22--ci%22:%0A                    self.add_setting(%22ci_platform%22, arg)%0A                elif opt == %22--result%22:%0A                    self.add_setting(%22result%22, 
+in options:%0A                    self.add_setting(options%5Bopt%5D, arg)%0A                elif opt == %22--repo%22:%0A                    self.set_project_name(
 arg)

refactor process_argv : use list of options and corresponding settings