# Copyright 2019 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import json
import logging
import os

import common
from autotest_lib.client.common_lib import error


# Path to the local checkout of the fw-testing-configs repo
_CONFIG_DIR = os.path.abspath(os.path.join(
        os.path.dirname(os.path.realpath(__file__)), os.pardir,
        'fw-testing-configs'))
_CONSOLIDATED_JSON_BASENAME = 'CONSOLIDATED.json'


def _consolidated_json_fp():
    """Get the absolute path to CONSOLIDATED.json."""
    return os.path.join(_CONFIG_DIR, _CONSOLIDATED_JSON_BASENAME)


class Config(object):
    """Configuration for FAFT tests.

    This object is meant to be the interface to all configuration required
    by FAFT tests, including device specific overrides.

    It gets the values from the JSON files in _CONFIG_DIR.
    Default values are declared in the DEFAULTS.json.
    Platform-specific overrides come from <platform>.json.
    If the platform has model-specific overrides, then those take precedence
    over the platform's config.
    If the platform inherits overrides from a parent platform, then the child
    platform's overrides take precedence over the parent's.

    @ivar platform: string containing the board name being tested.
    @ivar model: string containing the model name being tested
    """

    def __init__(self, platform, model=None):
        """Initialize an object with FAFT settings.
        Load JSON in order of importance (model, platform, parent/s, DEFAULTS).

        @param platform: The name of the platform being tested.
        """
        self._precedence_list = []
        self._precedence_names = []
        with open(_consolidated_json_fp()) as f:
            consolidated_json = json.load(f)
        # Load the most specific JSON config possible by splitting `platform`
        # at '_'/'-' and reversing ([::-1]). For example, veyron_minnie should
        # load minnie.json. octopus_fleex should look for fleex.json. It
        # doesn't exist, so instead it loads octopus.json.
        platform = platform.lower().replace('-', '_')
        for p in platform.rsplit('_')[::-1]:
            logging.debug('Looking for %s config', p)
            if p in consolidated_json:
                logging.info('Found %s config', p)
                self.platform = p
                break
        else:
            self.platform = platform
        if self.platform in consolidated_json:
            platform_config = consolidated_json[self.platform]
            seen_platforms = [self.platform]
            self._add_cfg_to_precedence(self.platform, platform_config)
            model_configs = platform_config.get('models', {})
            model_config = model_configs.get(model, None)
            if model_config is not None:
                self._add_cfg_to_precedence(
                        'MODEL:%s' % model, model_config, prepend=True)
                logging.debug('Using model override for %s', model)
            parent_platform = self._precedence_list[-1].get('parent', None)
            while parent_platform is not None:
                if parent_platform in seen_platforms:
                    loop = ' -> '.join(seen_platforms + [parent_platform])
                    raise error.TestError('fw-testing-configs for platform %s '
                                          'contains an inheritance loop: %s' % (
                                          self.platform, loop))
                parent_config = consolidated_json[parent_platform]
                seen_platforms.append(parent_platform)
                self._add_cfg_to_precedence(parent_platform, parent_config)
                parent_platform = self._precedence_list[-1].get('parent', None)
        else:
            logging.debug('Platform %s not found in %s. Using DEFAULTS.',
                          self.platform, consolidated_json)
        default_config = consolidated_json['DEFAULTS']
        self._add_cfg_to_precedence('DEFAULTS', default_config)

        # Set attributes
        all_attributes = self._precedence_list[-1].keys()
        self.attributes = {}
        self.attributes['platform'] = self.platform
        for attribute in all_attributes:
            if attribute.endswith('.DOC') or attribute == 'models':
                continue
            for config_dict in self._precedence_list:
                if attribute in config_dict:
                    self.attributes[attribute] = config_dict[attribute]
                    break

    def _add_cfg_to_precedence(self, cfg_name, cfg, prepend=False):
        """Add a configuration to self._precedence_list.

        @ivar cfg_name: The name of the config.
        @ivar cfg: The config dict.
        @ivar prepend: If true, add to the beginning of self._precedence_list.
                       Otherwise, add it to the end.
        """
        position = 0 if prepend else len(self._precedence_list)
        self._precedence_list.insert(position, cfg)
        self._precedence_names.insert(position, cfg_name)

    def __getattr__(self, attr):
        if attr in self.attributes:
            return self.attributes[attr]
        raise AttributeError('FAFT config has no attribute named %s' % attr)

    def __str__(self):
        str_list = []
        str_list.append('----------[ FW Testing Config Variables ]----------')
        str_list.append('--- Precedence list: %s ---' % self._precedence_names)
        for attr in sorted(self.attributes):
            str_list.append('  %s: %s' % (attr, self.attributes[attr]))
        str_list.append('---------------------------------------------------')
        return '\n'.join(str_list)
