import os
import subprocess
import sys
from shutil import copyfile
from ..utils.utils import *

# Copyright (c) Efabless Corporation. All rights reserved.
# See LICENSE file in the project root for full license information.


class ConfigHandler():
#    def __init__(self, tag):
#        self.tag = tag
#        self.current_directory = os.path.dirname(__file__)
#        self.config_generator_script = os.path.join(self.current_directory, "gen_raw_config.sh")
#        self.config_generator_cmd = '{script} {tag}'.format(
#                script=self.config_generator_script,
#                tag=self.tag
#                )
#        self.config_dict = {}

    config_getter_script = os.path.join(os.path.dirname(__file__), "config_get.sh")
    configuration_values = ['PDK_VARIANT', 'CLOCK_PERIOD', 'GLB_RT_ADJUSTMENT', 'FP_CORE_UTIL', 'PL_TARGET_DENSITY',
                'SYNTH_STRATEGY', 'SYNTH_MAX_FANOUT', 'FP_PDN_VPITCH', 'FP_PDN_HPITCH', 'FP_ASPECT_RATIO']

    base_config_values = ['DESIGN_NAME', 'VERILOG_FILES', 'CLOCK_PERIOD', 'CLOCK_PORT']


    @classmethod
    def get_header(cls):
        return ",".join(cls.configuration_values)

#    def gen_possible_combos(self):
#        raw_configuration = subprocess.check_output(self.config_generator_cmd.split())
#        raw_configuration = raw_configuration.decode(sys.getfilesystemencoding())
#        for possible_vector in raw_configuration.splitlines():
#            parameters = possible_vector.split()
#            key = parameters[0]
#            self.config_dict[key] = parameters[1:]
    
    @classmethod
    def get_config(cls, design, tag):
        config_params = " ".join(cls.configuration_values)
        config_relative_path = "config.tcl"
        config_path = os.path.join(os.getcwd(), get_run_path(design=design, tag=tag), config_relative_path)
        cmd = "{script} {path} {params}".format(script=cls.config_getter_script, path=config_path, params=config_params)
        config_coded = subprocess.check_output(cmd.split())
        config = config_coded.decode(sys.getfilesystemencoding()).strip()
        config = config.split("##")
        config = list(filter(None, config))

        return config

    @classmethod
    def gen_base_config_legacy(cls, design, base_config_path):
        config_params = " ".join(cls.base_config_values)
        config_relative_path = "designs/{design}/config.tcl".format(design=design)
        config_path = os.path.join(os.getcwd(), config_relative_path)
        cmd = "{script} {path} {params}".format(script=cls.config_getter_script, path=config_path, params=config_params)
        config_coded = subprocess.check_output(cmd.split())
        config = config_coded.decode(sys.getfilesystemencoding()).strip()
        config = config.split("##")
        config = list(filter(None, config))

        f = open(base_config_path, 'w')
        for i in range(len(config)):
            f.write("set ::env({var}) {val}\n".format(var=cls.base_config_values[i], val=config[i]))

        f.close()

    @classmethod
    def gen_base_config(cls, design, base_config_file):
        config_file = os.path.join(get_design_path(design=design), 'config.tcl')
        copyfile(config_file, base_config_file)

        
