"""Entry point.

"""
from os.path import join, expanduser

from cml.usecases.query import (
    PreprocessUsecase,
    KnowledgeSearchUsecase,
    CreateConstructorUsecase,
    FeatureSelectionUsecase,
    ReconstructionUsecase
)
from cml.ports.source_adapters import PandasAdapter
from cml.ports.ml_adapter import (
    ConstructionClusteringMLModel,
    FilterMethod,
    EmbeddedMethod
)
from cml.shared.settings import Settings
from cml.shared.settings import specific_settings_factory, read_settings
from cml.shared.request import (
    PreprocessRequest,
    KnowledgeSearchRequest,
    CreateConstructorRequest,
    FeatureSelectionRequest,
    ReconstructionRequest
)
from cml.ports.ml_adapter import (
    KernelDensityEstimator,
    find_relative_extrema,
    Autoencoder
)


__all__ = (
    "load_settings",
    "get_settings",
    "get_data_source",
    "construction",
    "reconstruction",
    "reconstruction",
    "search_knowledge",
    "visualizer",
    "save_knowledge",
    "load_knowledge"
)


def default_path(func):
    def wrapper(path: str = None):
        if not path:
            path = join(expanduser("~"), ".cml", "settings.ini")

        try:
            func(path)
        except FileNotFoundError as e:
            # TODO (dmt):Provide proper exception handling!
            pass
    return wrapper


@default_path
def load_settings(path: str):
    read_settings(path)


def get_settings():
    return Settings


def get_data_source():
    general_settings = specific_settings_factory("general")
    preprocessing_settings = specific_settings_factory("preprocessing")
    block_processing_settings = specific_settings_factory("block_processing")
    source_adapter = PandasAdapter.read_csv_data(general_settings.input_file)
    density_estimator = KernelDensityEstimator()
    relative_extrema = find_relative_extrema

    preprocessing_req = PreprocessRequest(source_adapter,
                                          preprocessing_settings,
                                          block_processing_settings,
                                          density_estimator,
                                          relative_extrema)
    preprocessing_usecase = PreprocessUsecase()
    return preprocessing_usecase.execute(preprocessing_req)


def construction(*args):
    ml_models = [ConstructionClusteringMLModel(raw_model) for raw_model in args]
    construction_settings = specific_settings_factory("construction")
    create_constructor_req = CreateConstructorRequest(construction_settings,
                                                      ml_models)
    create_construction_usecase = CreateConstructorUsecase()
    return create_construction_usecase.execute(create_constructor_req)


def reconstruction():
    pass


def search_knowledge(constructor, reconstructor, data_source):
    deconstruction_settings = specific_settings_factory("deconstruction")
    knowledge_search_req = KnowledgeSearchRequest(constructor,
                                                  reconstructor,
                                                  data_source,
                                                  deconstruction_settings)
    knowledge_search_usecase = KnowledgeSearchUsecase()
    return knowledge_search_usecase.execute(knowledge_search_req)


def visualizer():
    pass


def save_knowledge():
    pass


def load_knowledge():
    pass