# TODO (dmt): Validate user input!
# TODO (dmt): Add doc!
# TODO (dmt): Provide default values and the correct data type!
PROTOCOL_LEVEL = 55


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

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

    def __set__(self, instance, value):
        if isinstance(value, list):
            try:
                self.set_features = [int(i) for i in value]
            except ValueError:
                # TODO (dmt): Provide proper exception handling
                raise Exception("Fehler")

        elif isinstance(value, str):
            # TODO (dmt): Try to parse the string and handle errors.
            if value == "":
                self.set_features = []
            else:
                self.set_features = [int(i) for i in value.split(",")]

        else:
            raise Exception("Fehler")


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):
        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):
        self.block_size = int(value)


class InputFile:
    def __init__(self):
        self.input_file = None

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

    def __set__(self, instance, value):
        self.input_file = value


class LearnDir:
    def __init__(self):
        self.learn_dir = None

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

    def __set__(self, instance, value):
        self.learn_dir = value


class MaxLearnDir:
    def __init__(self):
        self.max_learn_dir = None

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

    def __set__(self, instance, value):
        self.max_learn_dir = value


class UseExistingModels:
    def __init__(self):
        self.use_existing_models: bool = False

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

    def __set__(self, instance, value):
        self.use_existing_models = value


class KnowledgeDir:
    def __init__(self):
        self.knowledge_dir = None

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

    def __set__(self, instance, value):
        self.knowledge_dirk = value


class SetTargets:
    def __init__(self):
        self.set_targets = None

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

    def __set__(self, instance, value):
        self.set_targets = value


class SortTimeStamp:
    def __init__(self):
        self.sort_time_stamp = False

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

    def __set__(self, instance, value):
        self.sort_time_stamp = value


class MaxBlocks:
    def __init__(self):
        self.max_blocks = 20

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

    def __set__(self, instance, value):
        self.max_blocks = value


class StackIterations:
    def __init__(self):
        self.stack_iterations = 20

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

    def __set__(self, instance, value):
        self.stack_iterations = value


class LearnblockMinimum:
    def __init__(self):
        self.learnblock_minimum = 10

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

    def __set__(self, instance, value):
        if isinstance(value, int):
            self.learnblock_minimum = value

        elif isinstance(value, str):
            try:
                self.learnblock_minimu = int(value)
            except Exception as error:
                print(error)


class MaxCategories:
    def __init__(self):
        self.max_categories = 10

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

    def __set__(self, instance, value):
        if isinstance(value, int):
            self.max_categories = value

        elif isinstance(value, str):
            try:
                self.max_categories = int(value)
            except Exception as error:
                print(error)


class SigmaZetaCutoff:
    def __init__(self):
        self.sigma_zeta_cutoff = 10

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

    def __set__(self, instance, value):
        if isinstance(value, float):
            self.sigma_zeta_cutoff = value
        elif isinstance(value, str):
            try:
                self.sigma_zeta_cutoff = float(value)
            except Exception as error:
                print(error)


class MinCategorySize:
    def __init__(self):
        self.min_category_size = 10

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

    def __set__(self, instance, value):
        if isinstance(value, int):
            self.min_category_size = value

        elif isinstance(value, str):
            try:
                self.min_category_size = int(value)
            except Exception as error:
                print(error)


class MaxModelTargets:
    def __init__(self):
        self.max_model_targets = 10

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

    def __set__(self, instance, value):
        if isinstance(value, int):
            self.max_model_targets = value

        elif isinstance(value, str):
            try:
                self.max_model_targets = int(value)
            except Exception as error:
                print(error)


class MaxTargetError:
    def __init__(self):
        self.max_target_error = 0.8

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

    def __set__(self, instance, value):
        if isinstance(value, float):
            self.max_target_error = value

        elif isinstance(value, str):
            try:
                self.max_target_error = float(value)
            except TypeError as error:
                print(error)


class MaxFeatures:
    def __init__(self):
        self.max_features = 10

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

    def __set__(self, instance, value):
        if isinstance(value, int):
            self.max_features = value
        if isinstance(value, str):
            try:
                self.max_features = int(value)
            except TypeError as error:
                print(error)


class MaxFilterX:
    def __init__(self):
        self.max_filter_x = 10

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

    def __set__(self, instance, value):
        if isinstance(value, int):
            self.max_filter_x = value
        if isinstance(value, str):
            try:
                self.max_filter_x = int(value)
            except TypeError as error:
                print(error)


class MaxFilterY:
    def __init__(self):
        self.max_filter_y = 10

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

    def __set__(self, instance, value):
        if isinstance(value, int):
            self.max_filter_y = value
        if isinstance(value, str):
            try:
                self.max_filter_y = int(value)
            except TypeError as error:
                print(error)


class MaxModelsReduction:
    def __init__(self):
        self.max_models_reduction = 10

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

    def __set__(self, instance, value):
        if isinstance(value, bool):
            self.max_models_reduction = value
        if isinstance(value, str):
            if value in ("no", "false"):
                self.max_models_reduction = False
            else:
                print("error")


class MinTestAccuracy:
    def __init__(self):
        self.min_test_accuracy = 0.8

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

    def __set__(self, instance, value):
        if isinstance(value, float):
            self.min_test_accuracy = value
        elif isinstance(value, str):
            try:
                self.min_test_accuracy = float(value)
            except TypeError as error:
                print(error)


class MaxTestErrorAvg:
    def __init__(self):
        self.max_test_error_avg = 10

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

    def __set__(self, instance, value):
        if isinstance(value, float):
            self.max_test_error_avg = value
        elif isinstance(value, str):
            try:
                self.max_test_error_avg = float(value)
            except TypeError as error:
                print(error)


class MaxTestErrorMax:
    def __init__(self):
        self.max_test_error_max = 10

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

    def __set__(self, instance, value):
        if isinstance(value, float):
            self.max_test_error_max = value
        elif isinstance(value, str):
            try:
                self.max_test_error_max = float(value)
            except TypeError as error:
                print(error)


class ReliabilitySample:
    def __init__(self):
        self.reliability_sample = 10

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

    def __set__(self, instance, value):
        if isinstance(value, float):
            self.reliability_sample = value
        elif isinstance(value, str):
            try:
                self.reliability_sample = float(value)
            except TypeError as error:
                print(error)


class MinReliability:
    def __init__(self):
        self.min_reliability = 10

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

    def __set__(self, instance, value):
        if isinstance(value, float):
            self.min_reliability = value
        elif isinstance(value, str):
            try:
                self.min_reliability = float(value)
            except TypeError as error:
                print(error)


class ReduceModelRedundancy:
    def __init__(self):
        self.reduce_model_redundancy = False

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

    def __set__(self, instance, value):
        if isinstance(value, bool):
            self.reduce_model_redundancy = value
        elif isinstance(value, str):
            if value in ("False", "no", "false"):
                self.reduce_model_redundancy = False
            elif value in ("True", "yes", "true"):
                self.reduce_model_redundancy = True
            else:
                raise TypeError()


class DeconstStrategy:
    def __init__(self):
        self.deconst_strategy = ""

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

    def __set__(self, instance, value):
        self.deconst_strategy = value


class DeconstMode:
    def __init__(self):
        self.deconst_mode = ""

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

    def __set__(self, instance, value):
        self.deconst_mode = value


class DeconstMaxDistanceT:
    def __init__(self):
        self.deconst_max_distance_t = 10

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

    def __set__(self, instance, value):
        self.deconst_max_distance_t = value


class ForceTimeExpansion:
    def __init__(self):
        self.force_time_expansion = 10

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

    def __set__(self, instance, value):
        self.force_time_expansion = value