# AUTOGENERATED! DO NOT EDIT! File to edit: 01_preprocessor.ipynb (unless otherwise specified).

__all__ = ['PreProcessor']

# Cell
from .dataframeloader import *
from .logger import *

# Cell
# hide
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder, StandardScaler, MinMaxScaler, LabelEncoder
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
import numpy as np

# Cell

class PreProcessor:
    """
    Represent PreProcessor class

    Attributes:
    numerical_transformer: Numerical Columns Tranformer
    categorical_transformer: Categorical Columns Transformer
    preprocessor: Preprocessor for Columns Tranformer
    """

    def __init__(self):
        self.columns_transfomer = None
        self.transformer_type = None
        self.target_cols_transformer = None
        self.target_cols_pl = None
        self.cat_cols_pl = None
        self.num_cols_pl = None


    def __str__(self):
        """Returns human readable string reprsentation"""
        attr_str = "numerical_transformer, categorical_transformer,columns_transfomer"
        return "PreProcessor object with attributes:" + attr_str

    def __repr__(self):
        return self.__str__()

    # PreProcessor Pipeline core methods

    # Create preprocessing pipeline for numerical data
    def create_num_cols_pp_pl(self, num_cols__imputer, num_cols__scaler):
        self.num_cols_pl = Pipeline(steps=[
            ('imputer', num_cols__imputer),
            ('scaler',  num_cols__scaler)
        ])

    # Create Preprocessing pipeline for categorical data
    def create_cat_cols_pp_pl(self, cat_cols__imputer, cat_cols__encoder):
        self.cat_cols_pl = Pipeline(steps=[
        ('imputer', cat_cols__imputer),
        ('encoder', cat_cols__encoder)
        ])

    # Create Preprocessing pipeline for target cols
    def create_target_cols_pp_pl(self, target_cols__encoder):
        self.target_cols_pl = Pipeline(steps=[
        ('encoder', target_cols__encoder)
        ])

    # Bundle preprocessing pipelines based upon types of columns
    def preprocess_all_cols(self, dataframeloader, problem_type="regression",
                            num_cols__imputer=SimpleImputer(strategy='constant'),
                            num_cols__scaler=StandardScaler(),
                            cat_cols__imputer=SimpleImputer(strategy='constant'),
                            cat_cols__encoder=OneHotEncoder(handle_unknown='ignore'),
                            target_cols__encoder=LabelEncoder()):
                            #cat_cols__encoder=OrdinalEncoder(handle_unknown='use_encoded_value',
                                                             #unknown_value=np.nan)):

        #if problem type classification encode target
        # encode target based upon problem type
        if problem_type == "classification":
            logger.info("PreProcessing will include target(s) encoding!")
            #now just call fit tranform on y
            dataframeloader.y = target_cols__encoder.fit_transform(dataframeloader.y)
            #logger.info("Encoded dataframeloader.y:", dataframeloader.y)

        #TODO: REALLY NOT HAPPY WITH THIS DETERMINISTIC REPEATED FLOW
        # change preprocessor according to type of column found
        if len(dataframeloader.categorical_cols) < 1:
            logger.info("categorical columns are None, Preprocessing will done accordingly!")
            # create scikit-learn pipelines instance
            self.create_num_cols_pp_pl(num_cols__imputer, num_cols__scaler)
            #now setup columns tranformer
            self.columns_transfomer = ColumnTransformer(
                transformers=[
                    ('num_cols', self.num_cols_pl,
                     dataframeloader.numerical_cols)
                ])


        elif len(dataframeloader.numerical_cols) < 1:
            logger.info("numerical columns are None, Preprocessing will done accordingly!")
            # create sklearn pipelines instance
            self.create_cat_cols_pp_pl(cat_cols__imputer, cat_cols__encoder)
            #now setup columns tranformer
            self.columns_transfomer = ColumnTransformer(
                transformers=[
                    ('cat_cols', self.cat_cols_pl,
                     dataframeloader.categorical_cols)
                ])


        else:
            # create scikit-learn pipelines instance
            logger.info("Both Numerical & Categorical columns found, Preprocessing will done accordingly!")
            self.create_num_cols_pp_pl(num_cols__imputer, num_cols__scaler)
            self.create_cat_cols_pp_pl(cat_cols__imputer, cat_cols__encoder)
            #now setup columns tranformer
            self.columns_transfomer = ColumnTransformer(
                transformers=[
                    ('num_cols', self.num_cols_pl,
                     dataframeloader.numerical_cols),
                    ('cat_cols', self.cat_cols_pl,
                     dataframeloader.categorical_cols)
                ])


        # now setup final tranfomer type
        self.transformer_type = self.columns_transfomer
        #logger.info(f"self.transformer_type: {self.transformer_type}")

        return self