"""Settings module.

"""


from itertools import starmap
from dataclasses import dataclass
from configparser import ConfigParser


class SetFeatures:
    def __init__(self):
        self.set_features = None

    def __get__(self, instance, owner):
        return self.set_features

    def __set__(self, instance, value):
        # TODO (dmt): Validate user input!
        self.set_features = [int(i) for i in value.split(",")]


class CutTimeStamp:
    def __init__(self):
        self.cut_time_stamp = False

    def __get__(self, instance, owner):
        return self.cut_time_stamp

    def __set__(self, instance, value):
        # TODO (dmt): Validate user input!
        self.cut_time_stamp = bool(value)


class BlockSize:
    def __init__(self):
        self.block_size = None

    def __get__(self, instance, owner):
        return self.block_size

    def __set__(self, instance, value):
        # TODO (dmt): Validate user input!
        self.block_size = int(value)


class MetaSettings(type):
    SET_FEATURES: SetFeatures = SetFeatures()
    CUT_TIME_STAMP: CutTimeStamp = CutTimeStamp()
    BLOCK_SIZE: BlockSize = BlockSize()


# TODO (dmt): Set default values.
class Settings(metaclass=MetaSettings):
    INPUT_FILE: str = ""
    LEARN_DIR: str = ""
    MAX_LEARN_DIR: int = 0
    USE_EXISTING_MODELS: bool = False
    SET_FEATURES: str = ""
    SET_TARGETS: str = ""
    SORT_TIME_STAMP: bool = False
    CUT_TIME_STAMP: bool = False
    BLOCK_SIZE: int = 0
    MAX_BLOCKS: int = 0
    STACK_ITERATIONS: int = 0
    LEARN_BLOCK_MINIMUM: int = 0
    SIGMA_ZETA_CUTOFF: float = 0.0


@dataclass
class GeneralSettings:
    input_file: str
    learn_dir: str
    max_learn_dir: int
    use_existing_models: bool


@dataclass
class PreprocessingSettings:
    set_features: str
    set_targets: str
    sort_time_stamp: bool
    cut_time_stamp: bool


@dataclass
class BlockProcessingSettings:
    block_size = int
    max_blocks = int
    stack_iterations = int
    learn_block_minimum = int
    sigma_zeta_cutoff = float


def specific_settings_factory(settings_type: str):
    types = {
        "general": starmap(
            GeneralSettings, [(Settings.INPUT_FILE,
                               Settings.LEARN_DIR,
                               Settings.MAX_LEARN_DIR,
                               Settings.USE_EXISTING_MODELS)]),
        "preprocessing": starmap(
            PreprocessingSettings, [(Settings.SET_FEATURES,
                                     Settings.SET_TARGETS,
                                     Settings.SORT_TIME_STAMP,
                                     Settings.CUT_TIME_STAMP)]),
        "block_processing": starmap(
            BlockProcessingSettings, [(Settings.BLOCK_SIZE,
                                       Settings.MAX_BLOCKS,
                                       Settings.STACK_ITERATIONS,
                                       Settings.LEARN_BLOCK_MINIMUM,
                                       Settings.SIGMA_ZETA_CUTOFF)])
    }

    return next(types[settings_type])


def read_settings(path: str):
    try:
        config = ConfigParser(path)
        configure_main_settings_class(config)
    except AttributeError as e:
        # TODO (dmt): Implement proper error handling.
        pass


def configure_main_settings_class(config):

    default = config["DEFAULT"]
    Settings.INPUT_FILE = default["input_file"]
    Settings.LEARN_DIR = default["learn_dir"]
    Settings.MAX_LEARN_DIR = default["max_learn_dir"]
    Settings.USE_EXISTING_MODELS = default["use_existing_models"]

    preprocessing = config["PREPROCESSING"]
    Settings.SET_FEATURES = preprocessing["set_features"]
    Settings.SET_TARGETS = preprocessing["set_targets"]
    Settings.SORT_TIME_STAMP = preprocessing["sort_time_stamp"]
    Settings.CUT_TIME_STAMP = preprocessing["cut_time_stamp"]

    block_processing = config["BLOCK_PROCESSING"]
    Settings.BLOCK_SIZE = block_processing["block_size"]
    Settings.MAX_BLOCKS = block_processing["max_blocks"]
    Settings.STACK_ITERATIONS = block_processing["stack_iterations"]
    Settings.LEARN_BLOCK_MINIMUM = block_processing["learn_block_minimum"]
    Settings.SIGMA_ZETA_CUTOFF = block_processing["sigma_zeta_cutoff"]