from typing import Union, Tuple, List, Dict, Any
import warnings
from ..base_loader import DatasetLoader

import os
import pandas as pd
import numpy as np


class FfE_DataLoader(DatasetLoader):
    """Loader for the data from FfE Open Data.
    http://opendata.ffe.de

    Currently implemented:
        - Electric profiles: get_electric_load_profiles()
        - Thermal profiles: get_thermal_load_profiles()
    """
    DATASET_NAME:str = 'FfE_Open_Data'
    electric_profiles_filename:str = 'electric_loads'
    thermal_profiles_filename:str = 'heat_loads'

    def load_electric_load_profiles(
            self, return_labels=False, convert_to_watts=True,
            ) -> Union[np.ndarray, Tuple[np.ndarray, List[Dict[Any, Any]]]]:
        """Electric thermal load profiles from
        http://opendata.ffe.de/dataset/synthetic-sample-electric-load-profile-three-phase-by-household-types-germany/
        ! ONLY THE TOTAL LOAD IS AVAILABLE HERE !
        These synthetic electric load profiles (3 phase) were generated
        by an integrated simulation model for load and mobility profiles
        of private households developed at FfE. Households with an
        average electric consumption were selected as examples for
        major household types from a simulated settlement of 940
        households representative for Germany. Care was also taken to
        ensure that thermal consumption and annual kilometrage were as
        average as possible. The period is one year and the temporal
        resolution is one minute. Corresponding datasets for thermal
        load profiles and mobility profiles are available.

        Args:
            return_labels: wheter the labels of the profiles should be
                returned. Defaults to False.

        Returns:
            [type]: [description]
        """
        try:
            # states loaded from npz file
            states = self._load_parsed_data(self.electric_profiles_filename)[0]
            if return_labels:
                labels = self._load_parsed_data(
                    self.electric_profiles_filename + '_labels',
                )
        except Exception as e:
            self._warn_could_not_load_parsed(e, self.electric_profiles_filename)
            states, labels = self._parse_elec_load()

        if convert_to_watts:
            states *= 1000.

        if return_labels:
            return states, labels
        else:
            return states


    def load_thermal_load_profiles(self, return_labels=False):
        """Load thermal load profiles from
        http://opendata.ffe.de/dataset/synthetic-sample-thermal-load-profile-by-household-types-germany/

        These synthetic thermal load profiles were generated by an
        integrated simulation model for load and mobility profiles of
        private households developed at FfE. Households with an average
        electric consumption were selected as examples for major household
        types from a simulated settlement of 940 households representative
        for Germany. Care was also taken to ensure that thermal consumption
        and annual kilometrage were as average as possible. The period is
        one year and the temporal resolution is one minute. Corresponding
        datasets for electric load profiles and mobility profiles are
        available.

        Args:
            return_labels: wheter the labels of the profiles should be
                returned. Defaults to False.

        Returns:
            [type]: [description]
        """
        try:
            # states loaded from npz file
            states = self._load_parsed_data(self.thermal_profiles_filename)[0]
            if return_labels:
                labels = self._load_parsed_data(
                    self.thermal_profiles_filename + '_labels',
                )
        except Exception as e:
            self._warn_could_not_load_parsed(e, self.thermal_profiles_filename)
            states, labels = self._parse_heat_load()

        if return_labels:
            return states, labels
        else:
            return states


    def load_labels_name(self, labels):
        """Load the german name corresponding to the houshold labels.
        """

        if isinstance(labels, int):
            if labels == 1:
                return 'One full-time working person'
            if labels == 2:
                return 'One pensioneer'
            if labels == 3:
                return 'Two full-time working persons'
            if labels == 4:
                return 'Two pensioneers'
            if labels == 5:
                return 'One full-time and one part-time working person'
            if labels == 6:
                return 'Two full-time working persons, one child'
            if labels == 7:
                return 'One full-time and one part-time working person, one child'
            if labels == 8:
                return 'Two full-time working persons, two children'
            if labels == 9:
                return 'One full-time and one part-time working person, two children'
            if labels == 10:
                return ' Two full-time working persons, three children'
            if labels == 11:
                return ' One full-time and one part-time working person, three children'
        elif hasattr(labels, '__iter__'):
            return [self.load_labels_name(lab) for lab in labels]


    def _parse_heat_load(self):

        file_name = 'v_opendata_thermal_load.htm'
        try:
            data = pd.read_json(os.path.join(self.raw_path, file_name))
        except FileNotFoundError:
            self._raise_missing_raw(file_name)

        states = []
        labels = []
        for d in data['data'][0]:
            states.append(d['values'])
            labels.append({
                #internal_id_type[1] = 54: Type of Household (clustered)
                #internal_id[1] = 1: One full-time working person
                #internal_id[1] = 2: One pensioneer
                #internal_id[1] = 3: Two full-time working persons
                #internal_id[1] = 4: Two pensioneers
                #internal_id[1] = 5: One full-time and one part-time working person
                #internal_id[1] = 6: Two full-time working persons, one child
                #internal_id[1] = 7: One full-time and one part-time working person, one child
                #internal_id[1] = 8: Two full-time working persons, two children
                #internal_id[1] = 9: One full-time and one part-time working person, two children
                #internal_id[1] = 10: Two full-time working persons, three children
                #internal_id[1] = 11: One full-time and one part-time working person, three children
                'hh_type': d['internal_id_1'],
            })
        states = np.asarray(states)

        self._save_parsed_data(
            self.thermal_profiles_filename,
            states,
            compress=True)
        self._save_parsed_data(
            self.thermal_profiles_filename + '_labels',
            labels)

        return states, labels


    def _parse_elec_load(self):

        file_name = 'v_opendata_electric_load.htm'
        try:
            data = pd.read_json(os.path.join(self.raw_path, file_name))
        except FileNotFoundError:
            self._raise_missing_raw(file_name)

        states = []
        labels = []
        for d in data['data'][0]:
            # internal_id_type[2] = 55: Electrical Load ,
            # internal_id[2] = 1: Phase 1
            # internal_id[2] = 2: Phase 2
            # internal_id[2] = 3: Phase 3
            # internal_id[2] = 0: Sum
            if d['internal_id_2'] == 0:
                states.append(d['values'])
                labels.append({
                    #internal_id_type[1] = 54: Type of Household (clustered)
                    #internal_id[1] = 1: One full-time working person
                    #internal_id[1] = 2: One pensioneer
                    #internal_id[1] = 3: Two full-time working persons
                    #internal_id[1] = 4: Two pensioneers
                    #internal_id[1] = 5: One full-time and one part-time working person
                    #internal_id[1] = 6: Two full-time working persons, one child
                    #internal_id[1] = 7: One full-time and one part-time working person, one child
                    #internal_id[1] = 8: Two full-time working persons, two children
                    #internal_id[1] = 9: One full-time and one part-time working person, two children
                    #internal_id[1] = 10: Two full-time working persons, three children
                    #internal_id[1] = 11: One full-time and one part-time working person, three children
                    'hh_type': d['internal_id_1'],
                })
        states = np.asarray(states)

        self._save_parsed_data(
            self.electric_profiles_filename,
            states,
            compress=True)
        self._save_parsed_data(
            self.electric_profiles_filename + '_labels',
            labels)
        return states, labels
