# -*- coding: utf-8 -*-
# @Time    : 18/08/2022
# @Author  : Ing. Jorge Lara
# @Email   : jlara@iee.unsj.edu.ar
# @File    : ------------
# @Software: PyCharm

from .base_DSSE import BaseAlgorithm
from .Algorithm_classification import DSSE_algorithms
from .Sample_test_systems_DSS import Sample_tests
from .MEAS_from_OpenDSS import MEAS_files
from .error_handling_logging import *
import pandas as pd
import logging

log_py = logging.getLogger(__name__)

class init_DSSE(BaseAlgorithm):

    def __init__(self, Sbas3ph_MVA: float = 30, tolerance: float = 1e-3, max_iter: int = 30, init_values: str = 'flat'):
        """
        Base parameters for the whole program, if you want to make changes or other scenarios you must initialize a new class.

        :param Sbas3ph_MVA: Three-phase system base power. Default is 30
        :param tolerance: Convergence tolerance of selected algorithm. Default is 1e-3
        :param max_iter: Maximum number of iterations of the selected algorithm. Default is 30
        :param init_values: Initial values for state estimation. With 'flat' start with 1.0 p.u. / 0° on all buses and
                            with 'dss' start with OpenDSS voltage and angle results. Default is 'flat'
        """
        BaseAlgorithm.__init__(self, Sbas3ph_MVA, tolerance, max_iter, init_values)

    def test_circuit(self, Typ_cir: str = None, case: int = None):
        """
        Function that returns in a dictionary the path to the test circuit files.

        :param Typ_cir: Can be: '1ph' or 'Pos'.
        :param case: the uploaded charge, see documentation
        :return: dictionary with the keys: 'DSS_file', 'MEAS_path', 'save_path', 'name_project', and 'Typ_cir'.
        """
        ex = Sample_tests()
        dict_sample_test = ex.examples(Typ_cir, case)
        return dict_sample_test

    def empty_init_files_MEAS_Unc(self, DSS_path: str = None, MEAS_path_save: str = None):
        """
        Generates .json extension files, where the names of nodes and elements that can participate as measurements in
        the state estimation algorithm are placed.

        :param DSS_path: A path of the .DSS files of the circuit modeled in OpenDSS. Default is None
        :param MEAS_path_save: Path where the .json files will be saved
        :return: Init_Bus_i.json, Init_Elem_ft.json, Init_Bus_i_PMU.json, and Init_Elem_ft_PMU.json
        """
        empty_init_files_MEAS_SD_EH(DSS_path, MEAS_path_save, log_py)
        meas_file = MEAS_files(self.Sbas3ph_MVA)
        meas_file.generate_init_MEAS_files(DSS_path, MEAS_path_save)

    def add_error_files_MEAS(self, DSS_path: str = None, MEAS_path: str = None, seed_DS: int = 1):
        """
        With the initial files (.json) and according to the state and standard deviation entered, add a random error of
        normal distribution to the OpenDSS power flow results. This will serve as the type and location of measurements
        in the state estimation algorithm.
        If you know the type and location of measurements, it should be entered in the .json files generated by this
        function.

        :param DSS_path: A path of the .DSS files of the circuit modeled in OpenDSS . Default = None
        :param MEAS_path: Path where the initial .json files are located. In this same path will be saved the new
        measurement .json files with the added error. Default = None
        :param seed_DS: seed of the random function. Default=1
        :return: MEAS_Bus_i.json, MEAS_Elem_ft.json, MEAS_Bus_i_PMU.json, and MEAS_Elem_ft_PMU.json
        """
        add_error_file_MEAS_EH(DSS_path, MEAS_path, log_py)
        error_MEAS = MEAS_files(self.Sbas3ph_MVA)
        error_MEAS.add_errors_MEAS_accord_PF_DSS(DSS_path, MEAS_path, seed_DS)

    def empty_MEAS_files(self, DSS_path: str = None, MEAS_path_save: str = None):
        """

        :param DSS_path:
        :param MEAS_path_save:
        :return:
        """

        empty_MEAS_files_EH(DSS_path, MEAS_path_save, log_py)
        meas_files = MEAS_files(self.Sbas3ph_MVA)
        meas_files.generate_empty_MEAS_files(DSS_path, MEAS_path_save)

    def estimate(self, DSS_path: str = None, MEAS_path: str = None, path_save: str = None, Typ_cir: str = None,
                 ALG: str = 'NV', coord: str = 'polar', method: str = 'nonlinear_PMU',
                 name_project: str = 'Default', View_res: bool = False, DSS_coll: bool = False, summary: bool = False,
                 MEAS_Pos: bool = False):
        """
        Function to perform circuit state estimation and obtain the estimated values of angle and voltage.

        :param summary:
        :param DSS_path: OpenDSS circuit file path. Default is None
        :param MEAS_path: Measurement file path. Default is None
        :param path_save: File path where the results will be saved. Default is None
        :param Typ_cir:  Can be: '1ph' or 'Pos'. Default is None
        :param ALG: For the moment it is node voltage. Default is 'NV'
        :param coord: For the moment are polar coordinates. Default is 'polar'
        :param method: can be: 'nonlinear', 'linear_PMU' and 'nonlinear_PMU'. Default is 'nonlinear_PMU'
        :param name_project: Name of the project to identify it in the files with results. Default is 'default'
        :param View_res: console display of the state estimator output
        :param summary: Prints by console the summary of the selected algorithm.
        :param DSS_coll: Save or print to console the power flow results along with the estimated status. Default is True
        :param MEAS_Pos: Positive sequence measurement file path. Default is None

        :return: Dictionary with the keys: 'arr_V_ang', 'df_V_ang', 'n_Iter', 'tol', 'time' and corresponds to the
                results in an array, DataFrame, iteration number, error and execution time respectively.
        """
        estimate_EH(DSS_path, MEAS_path, path_save, Typ_cir, MEAS_Pos, log_py)
        Sel_Alg = DSSE_algorithms(
            self.Sbas3ph_MVA, self.tolerance, self.max_iter, self.init_values, DSS_path, MEAS_path, path_save, Typ_cir,
            ALG, coord, method, name_project, MEAS_Pos, DSS_coll, View_res, summary)

        V_Ang_EST = Sel_Alg.addresses_algorithm()

        return V_Ang_EST

    def calc_from_est(self, DSS_path: str = None, EST_pd: pd.DataFrame = None, EST_path: str = None,
                      I_Ang_EST: bool = False, PQi_EST: bool = False, PQf_EST: bool = False, no_PU: bool = False):
        """
        From the estimated status result, other electrical parameters are calculated and can be compared with the OpenDSS results.

        :param EST_path:
        :param EST_pd:
        :param I_Ang_EST: With estimated voltage and angle, calculate the current between two nodes. Default is 'False'
        :param PQi_EST: With estimated voltage and angle, calculate the node injection power. Default is 'False'
        :param PQf_EST: With estimated voltage and angle, calculate the power flow between two nodes. Default is 'False'
        :param no_PU: Displays results in real values (not per Unit). Default is 'False'
        :param DSS_path:
        :return:
        """
        print('In development')


    def calc_performance(self, DSS_path: str = None, EST_pd: pd.DataFrame = None, EST_path: str = None,
                         MAPE: bool = False, MAE: bool = False, RMSE: bool = False):
        """
        Function to calculate the performance metrics as Mean Absolute Percentage Error (MAPE), Mean Absolute Error
         (MAE), and Root Mean Square Error (RMSE).

        :param MAPE: Calculate the Mean Absolute Percentage Error (MAPE). Default is 'False'
        :param MAE: Calculate the Mean Absolute Error (MAE). Default is 'False'
        :param RMSE: Calculate the Root Mean Square Error (RMSE). Default is 'False'
        :param DSS_path: OpenDSS circuit file path
        :return:
        """
        print('In development')


    def plot_results(self, I_Ang_EST: bool = False, PQi_EST: bool = False, PQf_EST: bool = False, no_PU: bool = False,
                     MAPE: bool = False, MAE: bool = False, RMSE: bool = False):
        """

        :param I_Ang_EST: With estimated voltage and angle, calculate the current between two nodes. Default is 'False'
        :param PQi_EST:
        :param PQf_EST:
        :param no_PU: Displays results in real values (not per Unit). Default is 'False'
        :param MAPE:
        :param MAE:
        :param RMSE:
        :return:
        """
        print('In development')

