import math
import pandas as pd
import numpy as np
import torch
from torch import nn, cuda
from torch.utils.data import Dataset

import utilities as util


class Setting:
    def __init__(self, simul_type):
        self.simul_type = simul_type
        
        if simul_type == "Single":
            self.dataset_settings   = [] 
            self.batch_size         = None
            self.epochs             = None 
            self.parameters_to_use  = None
            self.plants_to_use      = None
            self.start_date         = None
            self.end_date           = None
            self.learning_rate      = None
            self.samples_per_param  = None
            self.overlap_of_samples = None
            self.outputs            = None
            self.loss_fn            = None
            self.model              = None
            self.optimizer          = None

        if simul_type == 'FeaturesUsed':
            self.dataset_settings   = []
            self.batch_size         = None    
            self.epochs             = None
            self.parameters_to_use  = None
            self.plants_to_use      = None
            self.start_date         = None
            self.end_date           = None
            self.learning_rate      = None
            self.samples_per_param  = None
            self.overlap_of_samples = None
            self.outputs            = None
            self.output_neurons     = None
            self.loss_fn            = None
            self.optimizer          = None
            self.layers             = None              # List of neuron quantities in a layer, its length is the number of hidden layers
            self.activations        = None          # List of activation function that has to be used for each hidden layer, must be with the same length of self.layers    

    # Setters 

    def set_dataset_settings(self, settings):
        self.dataset_settings       = settings

    def set_batch_size(self, batch_size):
        self.batch_size             = batch_size        

    def set_epochs(self, epochs):
        self.epochs                 = epochs

    def set_learning_rate(self, learning_rate):
        self.learning_rate          = learning_rate

    def set_parameters_to_use(self, parameters_to_use):
        self.parameters_to_use      = parameters_to_use         

    def set_outputs(self, outputs):
        self.outputs                = outputs

    def set_output_neurons(self, output_neurons):
        self.output_neurons         = output_neurons    

    def set_plants_to_use(self, plants_to_use):
        self.plants_to_use          = plants_to_use

    def set_start_date(self, start_date):
        self.start_date             = start_date

    def set_end_date(self, end_date):
        self.end_date               = end_date            

    def set_samples_per_param(self, samples_per_param):
        self.samples_per_param      = samples_per_param    

    def set_overlap_of_samples(self, overlap_of_samples):
        self.overlap_of_samples     = overlap_of_samples

    def set_simul_type(self,simul_type):
        self.simul_type             = simul_type

    def set_loss_fn(self, loss_fn):
        self.loss_fn                = loss_fn

    def set_optimizer(self, optimizer):
        self.optimizer              = optimizer

    def set_model(self, model):
        self.model                  = model
    
    def set_layers(self,layers):
        self.layers                 = layers

    def set_activations(self, activations):
        self.activations            = activations    


    # Getters    
    def get_dataset_settings(self):
        return self.dataset_settings

    def get_batch_size(self):
        return self.batch_size

    def get_epochs(self):
        return self.epochs

    def get_learning_rate(self):
        return self.learning_rate

    def get_parameters_to_use(self):
        return self.parameters_to_use

    def get_plants_to_use(self):
        return self.plants_to_use

    def get_start_date(self):
        return self.start_date

    def get_end_date(self):
        return self.end_date

    def get_samples_per_param(self):
        return self.samples_per_param

    def get_overlap_of_samples(self):
        return self.overlap_of_samples

    def get_simul_type(self):
        return self.simul_type

    def get_outputs(self):
        return self.outputs    

    def get_output_neurons(self):
        return self.output_neurons

    def get_loss_fn(self):
        return self.loss_fn    

    def get_optimizer(self):
        return self.optimizer    

    def get_model(self):
        return self.model    
        
    def get_layers(self):
        return self.layers    

    def get_activations(self):
        return self.activations    