# coding: utf-8
# Copyright (c) Pymatgen Development Team.
# Distributed under the terms of the MIT License.

import json
from os import makedirs
from os.path import exists, expanduser

from pymatgen import SETTINGS
from pymatgen.analysis.chemenv.utils.scripts_utils import strategies_class_lookup

"""
This module contains the classes for configuration of the chemenv package.
"""

__author__ = "David Waroquiers"
__copyright__ = "Copyright 2012, The Materials Project"
__credits__ = "Geoffroy Hautier"
__version__ = "2.0"
__maintainer__ = "David Waroquiers"
__email__ = "david.waroquiers@gmail.com"
__date__ = "Feb 20, 2016"


class ChemEnvConfig:
    """
    Class used to store the configuration of the chemenv package :
     - Materials project access
     - ICSD database access
     - Default options (strategies, ...)
    """

    DEFAULT_PACKAGE_OPTIONS = {
        "default_strategy": {
            "strategy": "SimplestChemenvStrategy",
            "strategy_options": {
                "distance_cutoff": strategies_class_lookup[
                    "SimplestChemenvStrategy"
                ].DEFAULT_DISTANCE_CUTOFF,
                "angle_cutoff": strategies_class_lookup[
                    "SimplestChemenvStrategy"
                ].DEFAULT_ANGLE_CUTOFF,
                "additional_condition": strategies_class_lookup[
                    "SimplestChemenvStrategy"
                ].DEFAULT_ADDITIONAL_CONDITION,
                "continuous_symmetry_measure_cutoff": strategies_class_lookup[
                    "SimplestChemenvStrategy"
                ].DEFAULT_CONTINUOUS_SYMMETRY_MEASURE_CUTOFF,
            },
        },
        "default_max_distance_factor": 1.5,
    }

    def __init__(self, package_options=None):
        if SETTINGS.get("PMG_MAPI_KEY", "") != "":
            self.materials_project_configuration = SETTINGS.get("PMG_MAPI_KEY", "")
        else:
            self.materials_project_configuration = None

        if package_options is None:
            self.package_options = self.DEFAULT_PACKAGE_OPTIONS
        else:
            self.package_options = package_options

    def setup(self):
        while True:
            print("\n=> Configuration of the ChemEnv package <=")
            print("Current configuration :")
            if self.has_materials_project_access:
                print(" - Access to materials project is configured (add test ?)")
            else:
                print(" - No access to materials project")
            print(" - Package options :")
            for key, val in self.package_options.items():
                print("     {}   :   {}".format(str(key), str(val)))
            print("\nChoose in the following :")
            print(
                " <1> + <ENTER> : configuration of the package options (strategy, ...)"
            )
            print(" <q> + <ENTER> : quit without saving configuration")
            test = input(" <S> + <ENTER> : save configuration and quit\n ... ")
            if test == "1":
                self.setup_package_options()
            elif test == "q":
                break
            elif test == "S":
                config_file = self.save()
                break
            else:
                print(" ... wrong key, try again ...")
            print("")
        if test == "S":
            print('Configuration has been saved to file "{}"'.format(config_file))

    @property
    def has_materials_project_access(self):
        return self.materials_project_configuration is not None

    def setup_package_options(self):
        self.package_options = self.DEFAULT_PACKAGE_OPTIONS
        print("Choose between the following strategies : ")
        strategies = list(strategies_class_lookup.keys())
        for istrategy, strategy in enumerate(strategies):
            print(" <{}> : {}".format(str(istrategy + 1), strategy))
        test = input(" ... ")
        self.package_options["default_strategy"] = {
            "strategy": strategies[int(test) - 1],
            "strategy_options": {},
        }
        strategy_class = strategies_class_lookup[strategies[int(test) - 1]]
        if len(strategy_class.STRATEGY_OPTIONS) > 0:
            for option, option_dict in strategy_class.STRATEGY_OPTIONS.items():
                while True:
                    print(
                        '  => Enter value for option "{}" '
                        "(<ENTER> for default = {})\n".format(
                            option, str(option_dict["default"])
                        )
                    )
                    print("     Valid options are :\n")
                    print("       {}".format(option_dict["type"].allowed_values))
                    test = input("     Your choice : ")
                    if test == "":
                        self.package_options["default_strategy"]["strategy_options"][
                            option
                        ] = option_dict["type"](
                            strategy_class.STRATEGY_OPTIONS[option]["default"]
                        )
                        break
                    try:
                        self.package_options["default_strategy"]["strategy_options"][
                            option
                        ] = option_dict["type"](test)
                        break
                    except ValueError:
                        print("Wrong input for option {}".format(option))

    def package_options_description(self):
        out = "Package options :\n"
        out += " - Maximum distance factor : {:.4f}\n".format(
            self.package_options["default_max_distance_factor"]
        )
        out += ' - Default strategy is "{}" :\n'.format(
            self.package_options["default_strategy"]["strategy"]
        )
        strategy_class = strategies_class_lookup[
            self.package_options["default_strategy"]["strategy"]
        ]
        out += "{}\n".format(strategy_class.STRATEGY_DESCRIPTION)
        out += "   with options :\n"
        for option, option_dict in strategy_class.STRATEGY_OPTIONS.items():
            out += "     - {} : {}\n".format(
                option,
                self.package_options["default_strategy"]["strategy_options"][option],
            )
        return out

    def save(self, root_dir=None):
        if root_dir is None:
            home = expanduser("~")
            root_dir = "{}/.chemenv".format(home)
        if not exists(root_dir):
            makedirs(root_dir)
        config_dict = {"package_options": self.package_options}
        config_file = "{}/config.json".format(root_dir)
        if exists(config_file):
            test = input(
                "Overwrite existing configuration ? (<Y> + <ENTER> to confirm)"
            )
            if test != "Y":
                print("Configuration not saved")
                return config_file
        f = open(config_file, "w")
        json.dump(config_dict, f)
        f.close()
        print("Configuration saved")
        return config_file

    @classmethod
    def auto_load(cls, root_dir=None):
        if root_dir is None:
            home = expanduser("~")
            root_dir = "{}/.chemenv".format(home)
        config_file = "{}/config.json".format(root_dir)
        try:
            f = open(config_file, "r")
            config_dict = json.load(f)
            f.close()
            return ChemEnvConfig(package_options=config_dict["package_options"])

        except IOError:
            print('Unable to load configuration from file "{}" ...'.format(config_file))
            print(" ... loading default configuration")
            return ChemEnvConfig()
