"""
Created on Thu Mar  5 17:55:58 2020.

@author: Engelpracht
"""

# %% Import relevant libraries.
#
from json import dumps
from os import listdir
from os.path import isfile, join
from typing import Union

from pandas import read_csv, DataFrame, Series

# %% Define global constants used to read *.csv-files and to create JSON-file.
#
# Definition of names of columns of data frames: Columns are different for refrigerants, adsorption
# or absorption isotherms; and for equations or experimental data
#
# a) Names that are required for several entries
#
COLUMNS_DF_WPAIR = ['sorbent', 'refrigerant', 'sorbent-subtype', 'type']
COLUMNS_DF_LITERATURE = ['comment', 'literature']

COLUMNS_DF_ADS_PROPERTIES = ['prop-diameter-crystal', 'prop-diameter-pore',
                             'prop-diameter-pellet', 'prop-diameter-extrudate',
                             'prop-length-extrudate', 'prop-area-surface',
                             'prop-volume-pore', 'props-porosity-pellet',
                             'props-density-bulk', 'props-density-pellet',
                             'props-density-solid']

# b) Names that are required for entries of equation coefficients
#
COLUMNS_DF_ERROR = ['error-are', 'error-rmse']

COLUMNS_DF_ABS_VALIDITY = ['validity-temperature-min', 'validity-temperature-max']
COLUMNS_DF_ADS_VALIDITY = ['validity-pressure-min', 'validity-pressure-max',
                           'validity-temperature-min', 'validity-temperature-max',
                           'validity-loading-min', 'validity-loading-max']
COLUMNS_DF_REF_VALIDITY = ['validity-temperature-min', 'validity-temperature-max']

# c) Names that are required for entries of experimental data
#
COLUMNS_DF_MEASUREMENT = ['measurements-procedure', 'measurements-type']

COLUMNS_DF_ADS_UNCERTAINITY = ['uncertainty-data-source',
                               'uncertainty-pressure-abs',
                               'uncertainty-pressure-rel',
                               'uncertainty-temperature-abs',
                               'uncertainty-temperature-rel',
                               'uncertainty-loading-abs',
                               'uncertainty-loading-rel',
                               'uncertainty-adsorptionPotential-abs',
                               'uncertainty-adsorptionPotential-rel',
                               'uncertainty-volumetricLoading-abs',
                               'uncertainty-volumetricLoading-rel']

COLUMNS_DF_ABS_UNCERTAINITY = ['uncertainty-data-source',
                               'uncertainty-pressure-abs',
                               'uncertainty-pressure-rel',
                               'uncertainty-temperature-abs',
                               'uncertainty-temperature-rel',
                               'uncertainty-loading-abs',
                               'uncertainty-loading-rel']

# Definition of names of keys of dicts
#
# a) Keys that are more general
#
KEYS_DICT_BASE = ['k', 'v']

KEYS_DICT_K = ['_as_', '_rf_', '_st_', '_tp_']
KEYS_DICT_V = ['_ep_', '_ed_', '_r_', '_s_', '_t_']

KEYS_DICT_ABS_EQUATIONS = ['_c_', '_n_', '_e_', '_va_', '_p_']
KEYS_DICT_ADS_EQUATIONS = ['_c_', '_n_', '_e_', '_pr_', '_va_', '_er_', '_p_']
KEYS_DICT_REF_EQUATIONS = ['_c_', '_n_', '_e_', '_va_', '_p_']

KEYS_DICT_ADS_EXPDATA = ['_c_', '_n_', '_pr_', '_m_', '_u_', '_d_']
KEYS_DICT_ABS_EXPDATA = ['_c_', '_n_', '_m_', '_u_', '_d_']

KEYS_DICT_ADS_PROPERTIES = ['diameter-crystal', 'diameter-pore', 'diameter-pellet',
                            'diameter-extrudate', 'length-extrudate', 'area-surface',
                            'volume-pore', 'porosity-pellet', 'density-bulk',
                            'density-pellet', 'density-solid']

# b) Keys that are required for entries of equation coefficients
#
KEYS_DICT_ERROR = ['are', 'rmse']

KEYS_DICT_ABS_VALIDITY = ['temperature-min', 'temperature-max']
KEYS_DICT_ADS_VALIDITY = ['pressure-min', 'pressure-max',
                          'temperature-min', 'temperature-max',
                          'loading-min', 'loading-max']
KEYS_DICT_REF_VALIDITY = ['temperature-min', 'temperature-max']

# c) Keys that are required for entries of experimental data
#
KEYS_DICT_MEASUREMENT = ['procedure', 'type']

KEYS_DICT_ADS_UNCERTAINITY = ['data-source',
                              'pressure-abs', 'pressure-rel', 'temperature-abs',
                              'temperature-rel', 'loading-abs', 'loading-rel',
                              'adsorptionPotential-abs', 'adsorptionPotential-rel',
                              'volumetricLoading-abs', 'volumetricLoading-rel']

KEYS_DICT_ABS_UNCERTAINITY = ['data-source',
                              'pressure-abs', 'pressure-rel', 'temperature-abs',
                              'temperature-rel', 'loading-abs', 'loading-rel',
                              'adsorptionPotential-abs', 'adsorptionPotential-rel',
                              'volumetricLoading-abs', 'volumetricLoading-rel']

# %% Definition of sub-functions.
#
def read_csv_to_list(path: str) -> Union[list, list]:
    r"""Input a path to folder with *.csv-files to read files into panda data frames.

    This function reads all *.csv-files that are located in the directory
    specified by the variable 'path'. This function returns a list containing
    all names of the *.csv-files and another list containing all *.csv-files
    saved as data frames.

    Parameters
    ----------
    path : str
        Path that specifies folder in which *.csv-files are located.

    Returns
    -------
    names : list
        Contains all names of files without their type extensions (i.e. *.csv).
    files : list
        Contains all files saved as type 'pandas.core.frame.DataFrame'.

    Notes
    -----
    This function does not check if files have typ .csv.

    Examples
    --------
    >>> names, files = read_csv_to_list('C:\\example\\')
    >>> print(names)
    ['dss', 'langmuir']
    >>> print(type(files[0]))
    <class 'pandas.core.frame.DataFrame'>

    History
    -------
    03/07/2020, by Mirko Engelpracht:
        First implementation.
    """
    # Read names of files
    #
    names = [file for file in listdir(path) if isfile(join(path, file))]

    # Import all files as 'pandas.core.frame.DataFrame'
    # Drop second line of all files since it only contains units of values
    #
    files = []
    for _, name_file in enumerate(names):
        tmp_df = read_csv(join(path, name_file),
                          sep=';',
                          encoding='utf_8',
                          keep_default_na=False)
        files.append(tmp_df.drop(0).reset_index(drop=True))

    # Cut file-extensions of file names and return lists
    #
    return [name_file.split('.')[0] for name_file in names], files

def search_df(df_search: DataFrame, columns: list, values: list) -> DataFrame:
    r"""Search data frame for values in some columns.

    This function searches the data frame 'df_search' for the specified 'values'
    in the specified 'columns' and returns the maching data frame.

    Parameters
    ----------
    df_search : pandas.core.frame.DataFrame
        Data frame that that is being searched for.
    columns : list
        List containing names of the columns to be searched.
    values : list
        List containing values to be searched for.

    Returns
    -------
    pandas.core.frame.DataFrame
        Data frame that only contains searched values.

    Notes
    -----
    Parameters 'columns' and 'values' need to have the same length.

    Examples
    --------
    >>> search_result = search_df(df, ['Column 1'], ['Random value'])
    >>> print(type(search_result))
    <class 'pandas.core.frame.DataFrame'>

    History
    -------
    03/07/2020, by Mirko Engelpracht:
        First implementation.
    """
    # Search for specified values by sequential application of the search
    # criteria
    #
    for no_criterion, value_criterion in enumerate(values):
        df_search = df_search.loc[df_search[columns[no_criterion]] == value_criterion]

    # Return search result
    #
    return df_search

def search_wpair(dfs: list, columns: list) -> DataFrame:
    r"""Search for all available working pais.

    This function counts the number of unique working pairs, which are
    specfied by the 'columns' of the data frame, and returns a data frame that
    only contains the unique working pairs.

    Parameters
    ----------
    dfs : list
        List containing data frames that are searched for.
    columns : list
        List containing names of the columns to be searched.

    Returns
    -------
    pandas.core.frame.DataFrame
        Data frame that only unique working pairs according to 'columns'.

    History
    -------
    03/07/2020, by Mirko Engelpracht:
        First implementation.
    """
    # Create empty data frame and add all working pairs to it
    #
    df_unique = DataFrame(columns=columns)
    for _, val in enumerate(dfs):
        df_unique = df_unique.append(val[columns], ignore_index=True)

    # Drop duplicates and return data frame cointaing all working pairs
    #
    return df_unique.drop_duplicates().reset_index(drop=True)

def create_dict(series: Series, keys: list, convert: bool = False) -> dict:
    r"""Create a dict for a JSON file.

    This function creates a dict. Therefore, it uses the given 'keys' and takes
    values from the given 'series'. If necessary, the funtion convert values to
    floats when a conversion is possible.

    Parameters
    ----------
    series : pandas.core.series.Series
        Series containing values for the dict.
    keys : list
        Lists containing names of the keys of the dict.
    convert : bool
        Boolean indicating if values shall be converted to type float.

    Returns
    -------
    dict
        Data containing values from series.

    History
    -------
    03/07/2020, by Mirko Engelpracht:
        First implementation.
    """
    # Get series, read values of indices, and convert values if necessary
    #
    names_series = series.index
    values_series = []
    for _, val in enumerate(names_series):
        if convert:
            # Convert values to type float
            #
            if series[val] == '':
                values_series.append(series[val])
            else:
                values_series.append(float(series[val]))

        else:
            # Do not convert values to type float
            #
            values_series.append(series[val])

    # Create dict and return it
    #
    return dict(zip(keys, values_series))

# %% Definition of main-function.
#
def create_json_file(path_coef: str, path_exp: list, path_json: str) -> Union[list, str, str]:
    r"""Create JSON file.

    This function creates the JSON file. Therefore, it needs the path to the
    coefficients of the equations (i.e., 'path_coef'), the paths to the
    experimental data (i.e., 'path_exp'), and the path to the location where
    the JSON files shall be saved (i.e., 'path_json').

    Parameters
    ----------
    path_coef : str
        Path to *.csv-files that contain coefficients of equations.
    path_exp : list
        List containing paths to *.csv-files that contain experimental data points.
    path_exp : str
        Path to to folder where json-files shall be safed.

    Returns
    -------
    list_json : list
        List with content of JSON file.
    json_compact : str
        String of JSON file as one line.
    json_formatted : str
        String of JSON file formatted in multiple lines.

    History
    -------
    03/07/2020, by Mirko Engelpracht:
        First implementation.
    """
    # 0) Load all *.csv-files that contain equation coefficients or experimental
    #    data of refrigerants, adsorption isotherms, and absorption isotherms
    #
    names_equations, list_df_equations = read_csv_to_list(path_coef)

    tmp_list_df_experimental_data = []
    list_df_experimental_data = [None] * len(path_exp)

    for ind_exp, path_exp_i in enumerate(path_exp):
        _, list_df_experimental_data[ind_exp] = read_csv_to_list(path_exp_i)
        tmp_list_df_experimental_data = list_df_experimental_data[ind_exp] if ind_exp == 0 else \
            tmp_list_df_experimental_data + list_df_experimental_data[ind_exp]

    # 1) Get names of all unique refrigerants and working pairs:
    #
    df_wpair_unique = search_wpair(list_df_equations + tmp_list_df_experimental_data,
                                   COLUMNS_DF_WPAIR)

    # 2) Create dict 'k' that is used to save general information of all
    #    refrigerants and working pairs:
    #
    #       - Iterate over all unique refrigerants and working pairs
    #       - Save general information as dict
    #
    dict_k = [dict(zip(KEYS_DICT_K, row)) for _, row in df_wpair_unique.iterrows()]

    # 3) Create dict 'v' to save coefficients of equations and experimental
    #    data:
    #
    #       - Iterate over all unique refrigerants and working pairs
    #       - Create dicts and save dummy values for keys that will be later
    #         used for coefficients of equations and for experimental data
    #
    dict_v = [dict(zip(KEYS_DICT_V, [[], [],
                                     row[COLUMNS_DF_WPAIR[1]],
                                     row[COLUMNS_DF_WPAIR[0]],
                                     row[COLUMNS_DF_WPAIR[2]]]))
              for _, row in df_wpair_unique.iterrows()]

    # 4) Create dict '_ep_' to save coefficients of equations:
    #
    #       - Create dict that contains names of all equations as keys and empty
    #         lists as valeus
    #       - Create list for all unique refrigerants and working pairs with former
    #         created dict as attribute
    #       - For each refrigerant and working pair, count how often an equation
    #         occurs by iterating over refrigerants and working pairs first and
    #         iterating over equations second
    #       - For each equation, iterate over available sets of coefficients and
    #         save coresponding coefficients as dict
    #
    list_equations = []
    for _ in range(len(df_wpair_unique)):
        # Create empty dicts for each unique refrigerant and working pair, in which
        # the keys corespond the names of all existing equations
        #
        dict_equations = dict()
        for _, val in enumerate(names_equations):
            dict_equations.update(zip([val], [[]]))
        list_equations.append(dict_equations)

    for ind_ref_wpair, ref_wpair in df_wpair_unique.iterrows():
        for ind_equ, name_equ in enumerate(dict_equations):
            # Search current working pair within current equation data frame
            #
            df_equ = list_df_equations[ind_equ]
            cur_ref_wpair = ref_wpair.tolist()
            df_result = search_df(df_equ, COLUMNS_DF_WPAIR, cur_ref_wpair)

            # Save current equation data frame into coresponding position of
            # 'list_equations' when working pair exists
            #
            df_result = df_result.reset_index(drop=True)
            df_result = [] if df_result.empty else df_result
            list_equations[ind_ref_wpair].update(dict(zip([name_equ],
                                                          [df_result])))

    for ind_ref_wpair, _ in enumerate(dict_v):
        # Count and save names of different equation approaches for
        # current working pair
        #
        list_name_equ = []
        for _, name_equ in enumerate(list_equations[ind_ref_wpair]):
            if not isinstance(list_equations[ind_ref_wpair][name_equ], list):
                list_name_equ.append(name_equ)

        # Create dummy dict to save coefficient sets for each identified
        # equations of current working pair
        #
        list_equ = [[] for i in range(len(list_name_equ))]
        dict_equ = dict(zip(list_name_equ, list_equ))

        # For each equation, iterate over available sets of coefficients
        # For each set of coefficient, save coefficients as dict
        #
        for _, name_equ in enumerate(dict_equ):
            list_equ = []
            for _, equ_set in list_equations[ind_ref_wpair][name_equ].iterrows():
                # Create dummy dict for each set of coefficients depending on
                # kind of data (e.g., refrigerant or adsorption isotherm)
                #
                if dict_k[ind_ref_wpair]['_tp_']=='refrig':
                    list_equ_set = [[] for i in range(len(KEYS_DICT_REF_EQUATIONS))]
                    dict_equ_set = dict(zip(KEYS_DICT_REF_EQUATIONS, list_equ_set))

                elif dict_k[ind_ref_wpair]['_tp_']=='ads':
                    list_equ_set = [[] for i in range(len(KEYS_DICT_ADS_EQUATIONS))]
                    dict_equ_set = dict(zip(KEYS_DICT_ADS_EQUATIONS, list_equ_set))

                else:
                    list_equ_set = [[] for i in range(len(KEYS_DICT_ABS_EQUATIONS))]
                    dict_equ_set = dict(zip(KEYS_DICT_ABS_EQUATIONS, list_equ_set))

                # Update dummy dict depending on kind of data (e.g., refrigerant or
                # adsorption isotherm)
                #
                if dict_k[ind_ref_wpair]['_tp_']=='refrig':
                    # Update dummy dict: Literature
                    #
                    dict_equ_set[KEYS_DICT_REF_EQUATIONS[0]] = \
                        equ_set[COLUMNS_DF_LITERATURE[1]]

                    # Update dummy dict: Note
                    #
                    dict_equ_set[KEYS_DICT_REF_EQUATIONS[1]] = \
                        equ_set[COLUMNS_DF_LITERATURE[0]]

                    # Update dummy dict: Name of equation
                    #
                    dict_equ_set[KEYS_DICT_REF_EQUATIONS[2]] = \
                        name_equ.capitalize()

                    # Update dummy dict: Valid range
                    #
                    dict_equ_set[KEYS_DICT_REF_EQUATIONS[3]] = \
                        create_dict(equ_set[COLUMNS_DF_REF_VALIDITY],
                                    KEYS_DICT_REF_VALIDITY, True)

                    # Update dummy dict: Coefficients
                    #
                    equ_set = equ_set.drop(COLUMNS_DF_WPAIR +
                                           COLUMNS_DF_LITERATURE +
                                           COLUMNS_DF_REF_VALIDITY)

                    name_par = equ_set.index
                    list_par_name = []
                    list_par_value = []
                    for _, val in enumerate(name_par):
                        list_par_name.append(val)
                        list_par_value.append(float(equ_set[val]))

                    dict_equ_set[KEYS_DICT_REF_EQUATIONS[4]] = dict(zip(list_par_name,
                                                                    list_par_value))

                elif dict_k[ind_ref_wpair]['_tp_']=='ads':
                    # Update dummy dict: Literature
                    #
                    dict_equ_set[KEYS_DICT_ADS_EQUATIONS[0]] = \
                        equ_set[COLUMNS_DF_LITERATURE[1]]

                    # Update dummy dict: Note
                    #
                    dict_equ_set[KEYS_DICT_ADS_EQUATIONS[1]] = \
                        equ_set[COLUMNS_DF_LITERATURE[0]]

                    # Update dummy dict: Name of equation
                    #
                    dict_equ_set[KEYS_DICT_ADS_EQUATIONS[2]] = \
                        name_equ.capitalize()

                    # Update dummy dict: Further properties of sorbent
                    #
                    dict_equ_set[KEYS_DICT_ADS_EQUATIONS[3]] = \
                        create_dict(equ_set[COLUMNS_DF_ADS_PROPERTIES],
                                    KEYS_DICT_ADS_PROPERTIES)

                    # Update dummy dict: Valid range
                    #
                    dict_equ_set[KEYS_DICT_ADS_EQUATIONS[4]] = \
                        create_dict(equ_set[COLUMNS_DF_ADS_VALIDITY],
                                    KEYS_DICT_ADS_VALIDITY, True)

                    # Update dummy dict: Error
                    #
                    dict_equ_set[KEYS_DICT_ADS_EQUATIONS[5]] = \
                        create_dict(equ_set[COLUMNS_DF_ERROR],
                                    KEYS_DICT_ERROR, True)

                    # Update dummy dict: Coefficients
                    #
                    equ_set = equ_set.drop(COLUMNS_DF_WPAIR +
                                           COLUMNS_DF_LITERATURE +
                                           COLUMNS_DF_ADS_PROPERTIES +
                                           COLUMNS_DF_ADS_VALIDITY +
                                           COLUMNS_DF_ERROR)

                    name_par = equ_set.index
                    list_par_name = []
                    list_par_value = []
                    for _, val in enumerate(name_par):
                        list_par_name.append(val)
                        list_par_value.append(float(equ_set[val]))

                    dict_equ_set[KEYS_DICT_ADS_EQUATIONS[6]] = dict(zip(list_par_name,
                                                                    list_par_value))

                else:
                    # Update dummy dict: Literature
                    #
                    dict_equ_set[KEYS_DICT_ABS_EQUATIONS[0]] = \
                        equ_set[COLUMNS_DF_LITERATURE[1]]

                    # Update dummy dict: Note
                    #
                    dict_equ_set[KEYS_DICT_ABS_EQUATIONS[1]] = \
                        equ_set[COLUMNS_DF_LITERATURE[0]]

                    # Update dummy dict: Name of equation
                    #
                    dict_equ_set[KEYS_DICT_ABS_EQUATIONS[2]] = name_equ.capitalize()

                    # Update dummy dict: Valid range
                    #
                    dict_equ_set[KEYS_DICT_ABS_EQUATIONS[3]] = \
                        create_dict(equ_set[COLUMNS_DF_ABS_VALIDITY],
                                    KEYS_DICT_ABS_VALIDITY, True)

                    # Update dummy dict: Coefficients
                    #
                    equ_set = equ_set.drop(COLUMNS_DF_WPAIR +
                                           COLUMNS_DF_LITERATURE +
                                           COLUMNS_DF_ABS_VALIDITY)

                    name_par = equ_set.index
                    list_par_name = []
                    list_par_value = []
                    for _, val in enumerate(name_par):
                        list_par_name.append(val)
                        list_par_value.append(float(equ_set[val]))

                    dict_equ_set[KEYS_DICT_ABS_EQUATIONS[4]] = dict(zip(list_par_name,
                                                                    list_par_value))

                # Update list that contains all sets of coefficients
                #
                list_equ.append(dict_equ_set)

            # Update dict that contains different equations
            #
            dict_equ[name_equ] = list_equ

        # Update dict 'v' by adding coefficients of equations
        #
        dict_v[ind_ref_wpair][KEYS_DICT_V[0]] = dict_equ

    # 5) Create dict '_ed_' to save experimental data. Thereby, check type of data:
    #
    #       - Iterate over all refrigerants and working pairs
    #       - Check if experimental data exist
    #       - Iterate over all refrigerants and working pairs and save
    #         experimental data as dict
    #
    # Iterate over all experimental data specified by list of paths
    #
    for ind_type_exp, list_df_experimental_data_i in enumerate(list_df_experimental_data):
        df_exp_data = search_wpair(list_df_experimental_data_i, COLUMNS_DF_WPAIR)

        # Iterate over all refrigerants and working pairs
        #
        for ind_ref_wpair, _ in enumerate(dict_v):
            list_exp_data = []

            # Check if experimental data exists for current working pair
            # Thus, save time and skip iterations that are not necessary
            #
            df_cur_ref_wpair = df_wpair_unique.loc[ind_ref_wpair, :]
            name_cur_ref_wpair = df_cur_ref_wpair.tolist()
            df_result = search_df(df_exp_data, COLUMNS_DF_WPAIR,
                                  name_cur_ref_wpair)

            # If experimental data exist, save it into dict '_ed_'
            #
            if not df_result.empty:
                # Iterate over all data frames that contain experimental data
                #
                for _, df_exp in enumerate(list_df_experimental_data_i):
                    # Search experimental data within data frame for current working
                    # pair
                    # Note that experimental data only exists within one data frame!
                    #
                    df_exp = search_df(df_exp, COLUMNS_DF_WPAIR,
                                        name_cur_ref_wpair)

                    if not df_exp.empty:
                        # Check type of experimental data
                        #
                        if df_result['type'].all() == 'ads':
                            # Iterate over all available experimental data for the
                            # current working pair
                            #
                            for _, exp_set in df_exp.iterrows():
                                # Create dummy dict to save current experimental data
                                #
                                list_cur_exp_data = [[] for i in range(len(KEYS_DICT_ADS_EXPDATA))]
                                dict_exp_data = dict(zip(KEYS_DICT_ADS_EXPDATA,
                                                          list_cur_exp_data))

                                # Update dummy dict: Literature
                                #
                                dict_exp_data[KEYS_DICT_ADS_EXPDATA[0]] = \
                                    exp_set[COLUMNS_DF_LITERATURE[1]]

                                # Update dummy dict: Note
                                #
                                dict_exp_data[KEYS_DICT_ADS_EXPDATA[1]] = \
                                    exp_set[COLUMNS_DF_LITERATURE[0]]

                                # Update dummy dict: Sorbent properties
                                #
                                dict_exp_data[KEYS_DICT_ADS_EXPDATA[2]] = \
                                    create_dict(exp_set[COLUMNS_DF_ADS_PROPERTIES],
                                                KEYS_DICT_ADS_PROPERTIES)

                                # Update dummy dict: Measurement information
                                #
                                dict_exp_data[KEYS_DICT_ADS_EXPDATA[3]] = \
                                    create_dict(exp_set[COLUMNS_DF_MEASUREMENT],
                                                KEYS_DICT_MEASUREMENT)

                                # Update dummy dict: Uncertainty information
                                #
                                dict_exp_data[KEYS_DICT_ADS_EXPDATA[4]] = \
                                    create_dict(exp_set[COLUMNS_DF_ADS_UNCERTAINITY],
                                                KEYS_DICT_ADS_UNCERTAINITY)

                                # Update dummy dict: Measurements
                                #
                                mea_set = exp_set.drop(COLUMNS_DF_WPAIR +
                                                        COLUMNS_DF_LITERATURE +
                                                        COLUMNS_DF_ADS_PROPERTIES +
                                                        COLUMNS_DF_MEASUREMENT +
                                                        COLUMNS_DF_ADS_UNCERTAINITY)

                                name_par = mea_set.index
                                list_par_value = []
                                for _, val in enumerate(name_par):
                                    # Split string and ensure empty lists
                                    #
                                    measurments = mea_set[val].split(',')
                                    measurments = [] if (measurments[0] == '') else \
                                        [float(item) for item in measurments]

                                    list_par_value.append(measurments)

                                dict_exp_data[KEYS_DICT_ADS_EXPDATA[5]] = \
                                    dict(zip(name_par.to_list(), list_par_value))

                                # Update list containing all experiment data of current
                                # working pair
                                #
                                list_exp_data.append(dict_exp_data)

                        elif df_result['type'].all() == 'abs':
                            # Iterate over all available experimental data for the
                            # current working pair
                            #
                            for _, exp_set in df_exp.iterrows():
                                # Create dummy dict to save current experimental data
                                #
                                list_cur_exp_data = [[] for i in range(len(KEYS_DICT_ABS_EXPDATA))]
                                dict_exp_data = dict(zip(KEYS_DICT_ABS_EXPDATA,
                                                          list_cur_exp_data))

                                # Update dummy dict: Literature
                                #
                                dict_exp_data[KEYS_DICT_ABS_EXPDATA[0]] = \
                                    exp_set[COLUMNS_DF_LITERATURE[1]]

                                # Update dummy dict: Note
                                #
                                dict_exp_data[KEYS_DICT_ABS_EXPDATA[1]] = \
                                    exp_set[COLUMNS_DF_LITERATURE[0]]

                                # Update dummy dict: Measurement information
                                #
                                dict_exp_data[KEYS_DICT_ABS_EXPDATA[2]] = \
                                    create_dict(exp_set[COLUMNS_DF_MEASUREMENT],
                                                KEYS_DICT_MEASUREMENT)

                                # Update dummy dict: Uncertainty information
                                #
                                dict_exp_data[KEYS_DICT_ABS_EXPDATA[3]] = \
                                    create_dict(exp_set[COLUMNS_DF_ABS_UNCERTAINITY],
                                                KEYS_DICT_ABS_UNCERTAINITY)

                                # Update dummy dict: Measurements
                                #
                                mea_set = exp_set.drop(COLUMNS_DF_WPAIR +
                                                        COLUMNS_DF_LITERATURE +
                                                        COLUMNS_DF_MEASUREMENT +
                                                        COLUMNS_DF_ABS_UNCERTAINITY)

                                name_par = mea_set.index
                                list_par_value = []
                                for _, val in enumerate(name_par):
                                    # Split string and ensure empty lists
                                    #
                                    measurments = mea_set[val].split(',')
                                    measurments = [] if (measurments[0] == '') else \
                                        [float(item) for item in measurments]

                                    list_par_value.append(measurments)

                                dict_exp_data[KEYS_DICT_ABS_EXPDATA[4]] = \
                                    dict(zip(name_par.to_list(), list_par_value))

                                # Update list containing all experiment data of current
                                # working pair
                                #
                                list_exp_data.append(dict_exp_data)

                        # Update dict 'v' by adding experimental data
                        #
                        dict_v[ind_ref_wpair][KEYS_DICT_V[1]] = list_exp_data

    # 6) Create base dict that containts dicts 'k' and 'v':
    #
    #       - Iterate over all unique refrigerants and working pairs
    #       - Create dicts by zip-function
    #
    list_json = [dict(zip(KEYS_DICT_BASE, [val, dict_v[ind]])) for ind, val in
                 enumerate(dict_k)]

    # 7) Save JSON-files
    #
    with open(join(path_json, "sorpproplib.json"), "w") as text_file:
        json_compact = dumps(list_json)
        text_file.write(json_compact)

    with open(join(path_json, "sorpproplib_formatted.json"), "w") as text_file:
        json_formatted = dumps(list_json, indent=4)
        text_file.write(json_formatted)

    # Return data
    #
    return list_json, json_compact, json_formatted

# %% Execute main-function.
#
if __name__ == "__main__":
    # Defines paths
    #
    PATH_COEFFICIENTS = 'JSON\\equation_coefficients\\'
    PATH_EXPERIMENTS = ['JSON\\experimental_data\\ads\\']
    PATH_JSON = 'JSON\\'

    # Create JSON files
    #
    JSON_FILE, JSON_STR_COMPLETE, JSON_STR_FORMATTED = \
        create_json_file(PATH_COEFFICIENTS, PATH_EXPERIMENTS, PATH_JSON)


from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from datetime import datetime
from .models import BlogPost
from .forms import BlogPostForm

# Create your views here.

@login_required(login_url="/account/login/")
def create_blog(request):
    user = request.user
    if request.method == 'POST':
        form = BlogPostForm(request.POST)
        if form.is_valid():
            blog_post = BlogPost.objects.create(
                author = user,
                judul_blog = form.cleaned_data.get('judul_blog'),
                blog_text = form.cleaned_data.get('blog_text'),
                post_time = datetime.now()
            )
            blog_post.save()
            return redirect("/")
    context = {'form': BlogPostForm()}
    return render(request, 'create_post.html', context)

@login_required(login_url="/account/login/")
def delete_blog(request, id_blog):
    blog_post = BlogPost.objects.filter(pk = id_blog)
    blog_post.delete()
    return redirect("/")

def see_all_post(request):
    blog_post = BlogPost.objects.all()
    context = {
        'list_blog': blog_post
    }
    return render(request, 'index.html', context)

def see_detailed_post(request, id_blog):
    blog_post = BlogPost.objects.get(pk = id_blog)
    context = {
    'blog_author' : blog_post.author.username,
    'blog_post': blog_post.blog_text,
    'post_title': blog_post.judul_blog,
    'post_time': blog_post.post_time}
    return render(request, 'post.html', context)

def account_page(request):
    user = request.user
    blog_post = BlogPost.objects.filter(author = user)
    context = {
        'list_blog': blog_post
    }
    return render(request, 'profile_view.html', context)


from selenium import webdriver
from bs4 import BeautifulSoup
import requests
import time

def get_total(url):

    web_data = requests.get(url)
    time.sleep(2)
    soup = BeautifulSoup(web_data.text,'lxml')
    hrefs = soup.select('a.t')

    print(type(hrefs))
    href_list = []

    for href in hrefs:
        link = href.get('href')
        if 'pingbandiannao' in link:
           href_list.append(link)
    for href in href_list:
        spider(href)

def spider(href):
    driver = webdriver.Chrome()
    driver.get(href)
    driver.set_page_load_timeout(5)

    html = driver.page_source

    soup = BeautifulSoup(html, 'lxml')

    title_list = soup.select('h1.detail-title__name')
    title = title_list[0].text.strip()

    price_list = soup.select('span.infocard__container__item__main__text--price')
    price = price_list[0].text.strip()

    area_list = soup.select('div.infocard__container__item__main > a')
    area = area_list[0].text.strip()

    typename_list= soup.select('div.nav > a')
    typename= typename_list[-1].text

    view_list = soup.select('span.detail-title__info__totalcount')
    view = view_list[0].text.strip()
    data = {
        'title': title,
        'price': price,
        'area': area,
        'typename':typename,
        'view': view

    }
    print(data)

if __name__ == '__main__':
    urls = ['https://bj.58.com/pbdn/0/pn{}/'.format(str(i)) for i in range(1, 4, 1)]
    for url in urls:
        get_total(url)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @File  : test_task.py
# @Author: 蒋光谱
# @Date  : 2019/3/22
# @Desc  :
import asyncio
import threading
import time
import os
import sched
from concurrent.futures.thread import ThreadPoolExecutor
from datetime import datetime

import requests

schedule = sched.scheduler(time.time, time.sleep)

class ServiceRun():
    counter = 0

    @classmethod
    def perform_command(cls, inc):
        try:
            cls.counter += 1

            print('任务%s开始时间%s' % (cls.counter, datetime.now()))
            with ThreadPoolExecutor(100) as executor:
                for i in range(3):
                    executor.submit(cls.job1)
            print('任务%s结束时间%s' % (cls.counter, datetime.now()))

            schedule.enter(inc, 0, cls.perform_command, argument=(inc,))
        except Exception as e:
            print(e)

    @staticmethod
    def job1():
        print(threading.current_thread().getName())
        try:
            requests.get('http://www.google.com')
        except Exception as e:
            print(e)

if __name__ == '__main__':
    inc = 1
    # enter用来安排某事件的发生时间，从现在起第n秒开始启动
    schedule.enter(inc, 0, ServiceRun.perform_command, (inc,))
    # schedule.enter(inc, 0, ServiceRun.perform_command, (inc,))

    # 持续运行，直到计划时间队列变成空为止
    schedule.run()


from flask import Flask, render_template, request, redirect, url_for, send_from_directory
import ipaddress
import utilities.cloudUtility

app = Flask(__name__)

@app.route("/", methods=['GET'])
def route():
    return render_template('ccip.html', msg='', ipaddr='')

@app.route("/health", methods=['GET'])
def health():
    return render_template('health.html')

@app.route("/ccip", methods=['GET','POST'])
def ccip():
    if request.method == 'POST':
        if request.method == 'POST':
            if request.form['ipaddr'] is None :
                return render_template('ccip.html', msg='', ipaddr='')
            else:
                ipaddr = request.form['ipaddr']

                try:
                    ipaddress.ip_address(ipaddr)
                    print(ipaddr)
                    msg = utilities.cloudUtility.CheckIP(ipaddr)

                except Exception as e:
                    msg = str(ipaddr) + "\n"
                    msg += str(e)

                return render_template('ccip.html', msg=msg, ipaddr=ipaddr)

    else:
        return render_template('ccip.html', msg='', ipaddr='')

@app.route("/cyip", methods=['GET'])
def cyip():
    headers = request.headers
    environ = request.environ
    remoteAddr = request.remote_addr
    accessRoute = request.access_route
    environ_list = environ.items()

    return render_template('cyip.html', remoteAddr=remoteAddr, accessRoute=accessRoute, headers=headers,environ=environ_list)

@app.route("/.well-known/pki-validation/godaddy.html", methods=['GET'])
def validateCert():
    return render_template('godaddy.html')

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=80)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.contrib import admin
from app.models import Measurement,FabricCollection,Ratings,Designer,Styles,Country,Accessories,Fabrics,Profile,Category,Transactions,Order

class DesignerAdmin(admin.ModelAdmin):
    model = Designer
    list_display = ('name', 'user','average_rating','dp','cover_photo','city','country','address')

class RatingsAdmin(admin.ModelAdmin):
    model = Ratings
    list_display = ('comment', 'rating','designer','user')

class StylesAdmin(admin.ModelAdmin):
    model = Styles
    list_display = ('code','name','designer','custom_price','gender','pub_date')

class CountryAdmin(admin.ModelAdmin):
    model = Styles
    list_display = ('name',)

class CategoryAdmin(admin.ModelAdmin):
    model = Category
    list_display=('name',)

class AccessoriesAdmin(admin.ModelAdmin):
    model = Accessories
    list_display = ('name','price','designer','gender')

class FabricsAdmin(admin.ModelAdmin):
    model=Fabrics
    list_display = ('name','price','designer')

class ProfileAdmin(admin.ModelAdmin):
    model=Profile
    list_display = ('user','city','country','address')

class TransactionsAdmin(admin.ModelAdmin):
    model=Transactions
    list_display = ('user','reference','amount','status')

class FabricCollectionAdmin(admin.ModelAdmin):
    model=FabricCollection
    list_display = ('name','designer',)

class OrdersAdmin(admin.ModelAdmin):
    model=Transactions
    list_display = ('user','designer','style','fabric','transaction','reference')

class MeasurementAdmin(admin.ModelAdmin):
    model=Measurement

admin.site.register(Designer,DesignerAdmin)
admin.site.register(Ratings,RatingsAdmin)
admin.site.register(Styles,StylesAdmin)
admin.site.register(Country,CountryAdmin)
admin.site.register(Accessories,AccessoriesAdmin)
admin.site.register(Fabrics,FabricsAdmin)
admin.site.register(Profile,ProfileAdmin)
admin.site.register(Category,CategoryAdmin)
admin.site.register(Transactions,TransactionsAdmin)
admin.site.register(Order,OrdersAdmin)
admin.site.register(Measurement,MeasurementAdmin)
admin.site.register(FabricCollection,FabricCollectionAdmin)


import pytest

from src.data.test import Suite, Parameter, from_dict

@pytest.mark.unit
def test_deserialization():
    suite_dict = {
        'conditions': [{'id': 'c', 'variable': 'cause', 'condition': 'occurs'}],
        'expected': [{'id': 'e', 'variable': 'effect', 'condition': 'happens'}],
        'cases': [
            {'c': False, 'e': False},
            {'c': True, 'e': True}
        ]
    }
    deserialized = from_dict(suite_dict)

    cause = Parameter(id='c', variable='cause', condition='occurs')
    effect = Parameter(id='e', variable='effect', condition='happens')
    cases=[
        {'c': False, 'e': False},
        {'c': True, 'e': True}
    ]
    expected = Suite(conditions=[cause], expected=[effect], cases=cases)

    assert deserialized == expected


import numpy as np
import h5py
from skimage.transform import rotate
from skimage.draw import circle
from skimage.morphology import disk
from skimage.filters import rank
import os.path
from scipy.ndimage.filters import maximum_filter
from scipy.ndimage.filters import gaussian_laplace
from skimage.feature import peak_local_max

#for show_3D_surface
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt

class ScoreStack:
    #checks if data is available in correct format, initialize class attributes and create stack in correct shape, if readin is True stack is read in else empty
    #LoG: if Laplacian of Gaussian transformation should be performed for blob detection
    #sigma_LoG: sigma for LoG transform
    #substract_mean: if local maxima should be substracted by mean value within circle with radius radius_mean, does not work good
    def __init__(self, img, stack_height, x_center=0, y_center=0,  path_scoremaps='scoremaps/', dataset_name='data', readin=True, transform=True,LoG=False, sigma_LoG=3., substract_mean = False, radius_mean=3.):
        self.img = img #index of scoremap
        self.path_scoremaps = path_scoremaps
        self.dataset_name = dataset_name
        self.path_scoremaps = path_scoremaps
        self.stackname = 'stack_' + str(img) #stack format: stack_1200
        self.stack_height = stack_height
        self.x_center = x_center
        self.y_center = y_center
        self.have_data = False
        #self.stack_shape = (0, 0, self.stack_height)
        self.score_stack = np.array((0, 0, stack_height), dtype=np.float32)
        if readin:
            self.read_in()
        if transform:
            assert(self.have_data)
            self.transform()
        if LoG:
            self.transform_LoG(sigma_LoG)
        if substract_mean:
            self.substract_mean(radius_mean)

    #helper fct for read_in
    def exist_files(self):
        file_exist = True
        for i_rot in np.arange(self.stack_height):
            filepath = self.path_scoremaps+self.create_score_filename(i_rot)
            if os.path.isfile(filepath)==False:
                file_exist = False
                break
        return file_exist

    #helper fct for read_in
    #set stack_shape according to first scoremap shape and checks if shape of all scoremaps belonging to one img have same shape
    def set_check_shape(self):
        for i_rot in np.arange(self.stack_height):
            filepath = self.path_scoremaps + self.create_score_filename(i_rot)
            score_file = h5py.File(filepath, 'r')
            score_shape = score_file[self.dataset_name].shape
            score_file.close()
            if i_rot==0:
                self.score_stack.resize(score_shape[0], score_shape[1], self.stack_height)
            else:
                if not(self.score_stack.shape[0] == score_shape[0] and self.score_stack.shape[1] == score_shape[1]):
                    print('wrong shape: expexted {}, got: {}'.format(self.score_stack.shape[0], score_shape[0]))
                    return False
        return True

    def read_in(self):
        assert self.exist_files()
        shape_consistent = self.set_check_shape()
        assert shape_consistent
        for i_rot in np.arange(self.stack_height):
            filepath = self.path_scoremaps + self.create_score_filename(i_rot)
            score_file = h5py.File(filepath, 'r')
            self.score_stack[:,:,i_rot] = score_file[self.dataset_name][:,:,0]
            score_file.close()
        self.have_data = True

    def write_hdf5(self, data, filepath='', filename='default', dataset_name='data'):
        filepath_name = filepath + filename + '.h5'
        stack_file = h5py.File(filepath_name, 'w')
        stack_file.create_dataset(dataset_name, data=data)
        stack_file.close()

    def write_stack(self):
        assert(self.have_data)
        self.write_hdf5(data=self.score_stack, filename=self.stackname)

    #show surface plot of probmap in selected region and for selected angle/stacknumber i_rot
    def show(self, x_start, y_start, x_end, y_end , i_rot, zlim=(-1,1)):
        assert(self.have_data)
        assert(x_start < x_end)
        assert(y_start < y_end)
        assert(i_rot < self.stack_height)
        region = self.score_stack[y_start:y_end, x_start:x_end , i_rot]
        fig = plt.figure()
        ax = fig.gca(projection='3d')
        X = np.arange(x_end-x_start)
        Y = np.arange(y_end-y_start)
        X, Y = np.meshgrid(X, Y)
        Z = region[Y, X]
        #R = np.sqrt(X**2 + Y**2)
        #Z = np.sin(R)
        surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)
        ax.set_zlim(zlim[0], zlim[1])
        ax.zaxis.set_major_locator(LinearLocator(10))
        ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
        fig.colorbar(surf, shrink=0.5, aspect=5)
        plt.show()

    def create_score_filename(self, i_rot): #scoremap filename format: scoremap_1234_4.h5
        return 'scoremap_' + str(self.img) + '_' + str(i_rot) + '.h5'

    #rotate images in correct order
    def transform(self):
        angles = np.linspace(0, 360, self.stack_height, endpoint=False)
        for i_rot, angle in enumerate(angles):
            if i_rot==0:
                pass
            else:
                norm_factor = max(self.score_stack[:,:,i_rot].min(), self.score_stack[:,:,i_rot].max(), key=abs)
                self.score_stack[:,:,i_rot] *= 1/norm_factor
                self.score_stack[:,:,i_rot] = rotate(self.score_stack[:,:,i_rot], 360.-angle, resize = False, center = (self.y_center, self.x_center))
                self.score_stack[:,:,i_rot] *= norm_factor

    #LoG as blob detector
    def transform_LoG(self, sigma):
        for i_rot in np.arange(self.stack_height):
            self.score_stack[:,:,i_rot] = -gaussian_laplace(self.score_stack[:,:,i_rot], sigma)

    #transform score stack by substracting meanvalue within area of a disk
    #does not work properly
    def substract_mean(self, radius_disk):
        circle = disk(radius_disk)
        for i_rot in np.arange(self.stack_height):
            stack_slice = self.score_stack[:,:,i_rot]
            norm_factor = max(stack_slice.min(), stack_slice.max(), key=abs)
            stack_slice *= 1./norm_factor
            stack_slice = np.array(rank.mean(stack_slice, selem=circle), dtype=np.float32)
            stack_slice *= norm_factor
            self.score_stack[:,:,i_rot] = self.score_stack[:,:,i_rot]-stack_slice

    #computes the maxima in all scoremaps
    #radius: radius in px for circle around current px for looking for maxima, for footprint
    #return maxima: list of arrays, for each i_rot one array
    def extract_maxima(self, radius=3, threshold_abs=0.):
        maxima = []

        #xx, yy = circle(radius, radius, radius)
        #footprint = np.zeros((radius*2+1, radius*2+1), dtype=np.bool_)
        #footprint[xx, yy] = 1
        for i_rot in np.arange(self.stack_height):
            #mode='wrap' means periodic boundary conditions
            coord = peak_local_max(self.score_stack[:,:,i_rot], min_distance=radius, threshold_abs=threshold_abs)
            maxima.append(coord)
        return maxima

    #generate hypotheses and represent them as an an array [samples, attributes] x, y, alpha, score
    def extract_hypotheses(self, radius=3, threshold_abs=0):
        maxima = self.extract_maxima(radius=radius, threshold_abs=threshold_abs)
        n_hypotheses = 0
        for i_rot in np.arange(self.stack_height):
            n_hypotheses += len(maxima[i_rot])
        hypos = np.zeros((n_hypotheses, 4), dtype=np.float32)
        i_sample = 0
        #iterate over samples
        for i_rot in np.arange(self.stack_height):
            for i in np.arange(maxima[i_rot].shape[0]):
                coord = maxima[i_rot][i,:]      #coord [x,y]
                maximum_value = self.score_stack[coord[0], coord[1], i_rot]
                hypos[i_sample,0] = coord[0]
                hypos[i_sample,1] = coord[1]
                hypos[i_sample,2] = np.float32(i_rot)*360./np.float32(self.stack_height)
                hypos[i_sample,3] = maximum_value
                i_sample += 1
        return hypos

if __name__ == '__main__':
    #rotational paramater
    x_center = 510/2
    y_center = 514/2
    n_rot = 8

    #read in parameter
    path_scoremaps = '../../Deformabel-Part-Model/ccv/samples/fly/pred/scoremap/'
    start_idx = 2900
    n_scoremaps = 200

    stack_2934 = ScoreStack(2934, n_rot, x_center=x_center, y_center=y_center, path_scoremaps=path_scoremaps, LoG=True, sigma_LoG=1.)
    stack_2934.write_stack()
    x_start = 247
    y_start = 439
    x_end = 276
    y_end = 453
    i_rot = 6
    #hypos = stack_2989.extract_hypotheses(threshold_abs=0.35)
    #print hypos[10,:]
    #for i in np.arange(stack_2942.stack_height)
    #    print len(maxima[i])
    stack_2934.show(x_start, y_start, x_end, y_end , i_rot, zlim=(-1.,1.1))
    #stack_2942.write_stack()


from flask import Flask
from flask import request
import os
import applescript
import json

app = Flask(__name__)

#Define a song to play for each team member, this could be improved.

teammember_script = """tell application "iTunes"
	play track "Dont Stop Believing" of playlist "Done"
end tell
"""

teammember2_script = """tell application "iTunes"
	play track "Yelling Into The Wind" of playlist "Done"
end tell
"""

teammember3_script = """tell application "iTunes"
	play track "Good Times" of playlist "Done"
end tell
"""

# All script is to handle any team members who don't have an individual song defined
all_script = """tell application "iTunes"
	play track "NewTown" of playlist "Done"
end tell
"""

# All script is to handle any team members who don't have an individual song defined
bug_script = """tell application "iTunes"
	play track "NewTown" of playlist "Done"
end tell
"""

@app.route('/play/', methods = ['GET', 'POST', 'PATCH'])
@app.route('/play', methods = ['GET', 'POST', 'PATCH'])
def play():
	if request.method == 'POST':

		jsondata = request.data

		data = json.loads(jsondata)

		#Load the new status of the ticket from the JSON payload
		new_status = data['changelog']['items'][0]['toString']

		if (new_status == 'Done'):

				# if user_id is passed in as URL param
				if (request.values.get('user_id', None)):
					u = request.values.get('user_id', None)
				#checks to see which team member it is. This could be improved.
				if (u == 'user.name'):
					try:
						applescript.launch_script(teammember_script)
						return "playing first teammember's song"
					except applescript.AppleScriptError:
						return "Something has gone wrong with Applescript"

				elif (u == 'user.name'):
					try:
						applescript.launch_script(teammember2_script)
						return "playing teammember2's song"
					except applescript.AppleScriptError:
						return "Something has gone wrong with Applescript"

				elif (u == 'user.name'):
					try:
						applescript.launch_script(teammember3_script)
						return "playing teammember3's song"
					except applescript.AppleScriptError:
						return "Something has gone wrong with Applescript"

				elif u in other_team_members:
					try:
						applescript.launch_script(all_script)
						return "playing the default song"
					except applescript.AppleScriptError:
						return "Something has gone wrong with Applescript"

				#check to see if user_id is empty
				elif u is None:
					return "there was no user specified when this ticket was updated"
		else:
			return "Status not Done, do nothing"

#Create a webhook that only looks at bug type tickets in your project. Then point the webhook to this route.
@app.route('/bug/', methods = ['GET', 'POST', 'PATCH'])
@app.route('/bug', methods = ['GET', 'POST', 'PATCH'])
def bug():
	try:
		applescript.launch_script(bug_script)
		return "playing the bug creation song"
	except applescript.AppleScriptError:
		return "Something has gone wrong with Applescript"

if __name__ == '__main__':
	app.debug = True
	app.run()


'''utils.py - misc useful functions'''

import requests
import hashlib
import codecs
import csv
import ckanapi

from datetime import datetime
from airflow.models import Variable

def stream_download_to_md5(url):
    '''streams input url into returned md5 hash string'''
    r = requests.get(url, stream=True)

    sig = hashlib.md5()

    # loop over lines in url response
    for line in r.iter_content():
        sig.update(line)

    return sig.hexdigest()

def download_to_md5(url):
    '''downloads input url into returned md5 hash string'''
    r = requests.get(url)

    sig = hashlib.md5(r.text.encode())

    return sig.hexdigest()

def file_to_md5(filepath):
    '''streams input string into returned md5 hash string'''
    sig = hashlib.md5()
    with open(filepath, "rb") as f:
        # loop over bytes of file until there are no bytes left
        # reads 8192 bytes at a time - md5 has 128-byte digest blocks
        # and 8192 is 128*64
        # stackoverflow.com/questions/1131220/get-the-md5-hash-of-big-files-in-python
        while True:
            buf = f.read(8192)
            if not buf:
                break
            sig.update(buf)

    return sig.hexdigest()

def csv_to_generator(filepath, fieldnames):
    '''input csv filepath and fieldnames, output stream of rows as json'''
    with codecs.open(filepath, "rbU", "latin1") as f:
        reader = csv.DictReader(f, fieldnames=fieldnames)
        next(reader)
        for row in reader:
            yield(row)

def clean_string(input):
    '''converts data to fit in CKAN datastore text column'''
    if input is None:
        return ""
    if not isinstance(input, str):
        return str(input)
    else:
        return str(input).strip()

def clean_int(input):
    '''converts data to fit in CKAN datastore int column'''
    if input:
        return int(input)
    else:
        return None

def clean_float(input):
    '''converts data to fit in CKAN datastore float column'''
    if input:
        return float(input)
    else:
        return None

def clean_date_format(input, input_format=None):
    '''converts data to fit in CKAN datastore date or timestamp column'''
    # loops through the list of formats and tries to return an input
    # string into a datetime of one of those formats

    if input is None:
        return

    if len(input) == 0:
        return

    assert isinstance(
        input, str
    ), "Utils.clean_date_format() accepts strings - it got {}".format(
        type(input)
    )

    format_dict = {
        "%Y-%m-%dT%H:%M:%S.%f": "%Y-%m-%dT%H:%M:%S",
        "%Y-%m-%d %H:%M:%S.%f": "%Y-%m-%dT%H:%M:%S",
        "%Y-%m-%dT%H:%M:%S": "%Y-%m-%dT%H:%M:%S",
        "%Y-%m-%d %H:%M:%S": "%Y-%m-%dT%H:%M:%S",
        "%Y-%m-%d": "%Y-%m-%d",
        "%d-%b-%Y": "%Y-%m-%d",
        "%d-%b-%y": "%Y-%m-%d",
        "%b-%d-%Y": "%Y-%m-%d",
        "%m-%d-%y": "%Y-%m-%d",
        "%m-%d-%Y": "%Y-%m-%d",
        "%d-%m-%y": "%Y-%m-%d",
        "%d-%m-%Y": "%Y-%m-%d",
        "%Y%m%d%H%M%S": "%Y-%m-%dT%H:%M:%S",
        "%d%m%Y": "%Y-%m-%d",
        "%d%b%Y": "%Y-%m-%d",
        "%Y-%b-%d": "%Y-%m-%d",
        "%b %d, %Y": "%Y-%m-%d",
    }

    if input_format:
        if input_format == "epoch":
            # assumes input is in milliseconds

            datetime_object = datetime.fromtimestamp(int(input)/1e3)
            try:
                return datetime_object.strftime("%Y-%m-%dT%H:%M:%S")
            except ValueError:
                return datetime_object.strftime("%Y-%m-%d")

        else:
            input = input.replace("/", "-")
            input_format = input_format.replace("/", "-")
            datetime_object = datetime.strptime(input, input_format)
            output = datetime_object.strftime(format_dict[input_format])

        return output

    else:
        for format in format_dict.keys():
            try:
                input = input.replace("/", "-")
                datetime_object = datetime.strptime(input, format)
                output = datetime_object.strftime(format_dict[format])
                return output
            except ValueError:
                pass

def connect_to_ckan():
    '''Returns RemoteCKAN object for appropriate CKAN instance'''

    # init hardcoded vars
    ACTIVE_ENV = Variable.get("active_env")
    CKAN_CREDS = Variable.get("ckan_credentials_secret", deserialize_json=True)
    CKAN = CKAN_CREDS[ACTIVE_ENV]["address"]#
    CKAN_APIKEY = CKAN_CREDS[ACTIVE_ENV]["apikey"]#

    return ckanapi.RemoteCKAN(apikey=CKAN_APIKEY, address=CKAN)


from datetime import timedelta
from http import HTTPStatus

from django.core import mail
from django.test import TestCase
from django.urls import reverse
from django.utils.timezone import now

from users.forms import EmailVerification
from users.models import User

if __name__ == '__main__':
    import unittest
    unittest.main()

class UserRegistrationViewTestCase(TestCase):

    def setUp(self):
        self.path = reverse('users:registration')
        self.data = {
            'first_name': 'Daniel',
            'last_name': 'Kotelnikov',
            'username': 'Daniel',
            'email': 'daniel@yandex.ru',
            'password1': '58523',
            'password2': '58523'
        }

    def test_user_registration_get(self):
        response = self.client.get(self.path)

        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertEqual(response.context_data['title'], 'Store - Регистрация')
        self.assertTemplateUsed(response, 'users/registration.html')

    def test_user_registration_post(self):
        first_name = self.data['first_name']
        self.assertFalse(User.objects.filter(first_name=first_name).exists())
        response = self.client.post(self.path, self.data)

        self.assertEqual(response.status_code, HTTPStatus.FOUND)
        self.assertRedirects(response, reverse('users:login'))
        self.assertTrue(User.objects.filter(first_name=first_name).exists())

        email_verification = EmailVerification.objects.filter(first_name=first_name)
        self.assertEqual(email_verification.exists())
        self.assertEqual(
            email_verification.first().expiration.date(),
            (now() + timedelta(hours=48)).date()
        )

    def test_user_registration_error(self):
        User.objects.create(first_name=self.data['first_name'])
        response = self.client.post(self.path, self.data)

        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertContains(response, 'User has been created', html=True)

class EmailTest(TestCase):
    def test_send_email(self):
        # Send message.
        mail.send_mail(
            'Subject here',
            'Here is the message.',
            'storeserverlogin@yandex.ru',
            ['daniel.kotelnickov@yandex.ru']
        )

        # Test that one message has been sent.
        self.assertEqual(len(mail.outbox), 1)

        # Verify that the subject of the first message is correct.
        self.assertEqual(mail.outbox[0].subject, 'Subject here')


from suds.client import Client

def userinfo(message):

    session_status = 'Нет активной сессии'

    login_id = message.text
    endpoint = "http://172.16.89.4:8088/billing/phpclient/admin/soap/api3.wsdl"
    service_url = 'http://172.16.89.4:34012'
    client = Client(endpoint, faults=False)
    client.set_options(location=service_url)
    manager = client.service.Login('userinfo', ')@6D2f78')

    users = client.service.getVgroups(flt={'login': login_id})
    user = users[1][0]
    account = client.service.getAccount(id=user['uid'])
    account = account[1][0]
    tarif_info = client.service.getTarif(id=user['tarid'])
    tarif_info = tarif_info[1][0]
    block_id = user['blocked']
    abonent_name = user['username']
    mobile = account['account']['mobile']
    balance = round(user['balance'], 2)
    tarif = tarif_info['tarif']['descr']
    shape = tarif_info['tarif']['shape']
    rent = tarif_info['tarif']['rent']

    sessions = client.service.getSessionsRadius(flt={'agentid': '1'}, )

    for session in sessions[1]:
        if session['vgid'] == user['vgid']:
            x = bin(session['assignedip'])[2:].zfill(32)
            x1 = int(x[0:8], base=2)
            x2 = int(x[8:16], base=2)
            x3 = int(x[16:24], base=2)
            x4 = int(x[24:], base=2)
            ip = f'{x1}.{x2}.{x3}.{x4}'
            ip_address = ip
            session_status = 'Сессия активна'
            mac = session['sessani']
            start_time = session['starttime']

    if 'address' in user:
        address_list = user['address'][0]['address'].split(',')
        address = address_list[3] + ' ' + address_list[5] + ' ' + address_list[6] + ' '
        city = address[3]
        street = address[5]
        house = address[6]
        if len(address_list[7]) > 0:
            address = address + address_list[7]
    else:
        address = "~"

    if block_id == 0:
        block = 'Активная'
    elif block_id == 4:
        block = 'Заблокирована по балансу'
    elif block_id == 10:
        block = 'Учетная запись отключена'
    else:
        block = 'Заблокирована, причина: ' + str(block_id)

    if session_status == 'Сессия активна':
        info_for_user = f'''
Абонент: {abonent_name};
Телефон: {mobile};
Адрес: {address};
Баланс: {balance} тг;
Статус у.з.: {block};
Сессия: {session_status};
Время начала: {start_time};
Ip: {ip_address}.
    '''
    else:
        info_for_user = f'''
Абонент: {abonent_name};
Телефон: {mobile};
Адрес: {address};
Баланс: {balance} тг;
Статус у.з.: {block};
Сессия: {session_status}.
            '''

    return info_for_user


import json
from pprint import pprint
import numpy as np
from src.environment import TennisEnvironment
from src.maddpg import MADDPG1
from src.models import SimpleMADDPGAgent1
import datetime
import matplotlib.pyplot as plt
import torch

def train(*args, **kwargs):
    print(kwargs)

    env = TennisEnvironment(**kwargs['env'])
    env.reset(train_mode=True)

    state_dim = env.get_state_dim()
    action_dim = env.get_action_dim()
    kwargs['agent']['state_dim'] = state_dim
    kwargs['agent']['action_dim'] = action_dim
    kwargs['agent']['num_agents'] = env.get_num_agents()

    kwargs['ddpg']['device'] = 'cpu'

    agent = SimpleMADDPGAgent1(**kwargs['agent'])
    target_agent = SimpleMADDPGAgent1(**kwargs['agent'])
    alg = MADDPG1(agent=agent, target_agent=target_agent, **kwargs['ddpg'])
    scores = alg.train(env, 4000)

    dt = str(datetime.datetime.now().strftime("%m_%d_%Y_%I_%M_%p"))
    model_fname = "../models/ddpg_reacher_{}.pt".format(dt)
    torch.save(agent, model_fname)

    plt.plot(np.max(scores,axis=-1))
    plt.plot(np.convolve(np.max(scores, axis=-1), np.ones(100) / 100))
    fig_name = "../reports/ddpg_reacher_{}.png".format(dt)
    plt.savefig(fig_name)
    scores_fname = "../reports/ddpg_reacher_{}".format(dt)
    np.save(scores_fname, np.asarray(scores))

if __name__ == '__main__':
    with open('../config.json') as data_file:
        data = json.load(data_file)

    pprint(data)
    kwargs = data

    train(**kwargs)


#!/usr/local/bin/python3.11

from tkinter import *
from datetime import datetime
import sqlite3
import datetime
from tkcalendar import Calendar, DateEntry
from tkinter import messagebox
from configparser import ConfigParser
from frame_functions import *
from pdf_report import *

# from tkinter import askopenfilename
database = "database files/kdm_stores.db"
lookup_record = "Returns"

def populate_returns_tree(tree, records):
    for record in tree.get_children():
        tree.delete(record)
    global count
    count = 0
    current_time = datetime.now()

    #	print(record)
    # sort the records
    # records = sorted(records, key=lambda x: datetime.strptime(x[5], "%d-%m-%Y"), reverse=True)
    for record in records:
        # in_stock_since = datetime.strptime(record[5], "%d-%m-%Y")  # Assuming the date is in the sixth column
        # elapsed_time = (current_time - in_stock_since).days
        if count % 2 == 0:
            tree.insert(parent='', index='end', iid=count, text='',
                        values=(record[0], record[3], record[2], record[3], record[4], record[6], record[7]),
                        # values=(record[0], record[3], record[4],record[5]),
                        tags=('evenrow',))
        else:
            tree.insert(parent='', index='end', iid=count, text='',
                        values=(record[0], record[2], record[0], record[4], record[5], record[6], record[7]),
                        # values=(record[0], record[3], record[4], record[5]),
                        tags=('oddrow',))
        # increment counter
        count += 1

# Call the function with your database path
def create_returns_table(database):
    # Create a database or connect to one that exists
    connection = sqlite3.connect(database)
    # Create a cursor instance

    cursor = connection.cursor()
    with connection:
        # Create Table
        cursor.execute("""CREATE TABLE if not exists returns (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
            	fleet_number text,
            	return_motive text,
            	cpr_number text,
            	date_created date,
            	date_returned date,
            	status text)
            	""")
        print("Table Created")

# create_returns_table(database)
# insert_dummy_data(database)
def query_returns_table(database):
    # Create a database or connect to one that exists
    connection = sqlite3.connect(database)
    # Create a cursor instance

    cursor = connection.cursor()
    with connection:
        # Create Table
        cursor.execute("""SELECT rowid,* FROM returns""")
        records = cursor.fetchall()
        for record in records:
            print(record)
        return records

query_returns_table(database)

class GoodsReturnClass:

    def __init__(self, master_root, kdm_division, division_image):
        """Init method for objects of class Small tools"""

        kdm_division = kdm_division
        self.report = None
        self.master_root = master_root
        self.window = Toplevel(master_root)
        self.window.title(kdm_division)

        self.kdm_division = kdm_division
        self.parser = ConfigParser()
        self.parser.read("treebase.ini")
        self.saved_primary_color = self.parser.get('colors', 'primary_color')
        self.saved_secondary_color = self.parser.get('colors', 'secondary_color')
        self.saved_highlight_color = self.parser.get('colors', 'highlight_color')

        # Designate Height and Width of our app
        app_width = 1400
        app_height = 850
        # get the current screen measures
        screen_width = master_root.winfo_screenwidth()
        screen_height = master_root.winfo_screenheight()
        # center the window on the current screen
        x = (screen_width / 2) - (app_width / 2)
        y = (screen_height / 2) - (app_height / 2)

        self.window.geometry(f'{app_width}x{app_height}+{int(x)}+{int(y)}')
        master_root.withdraw()
        self.frame()

        # use images like buttons
        self.button_image = PhotoImage(file=division_image)
        label_text = f"Close {kdm_division} window"
        self.label = Label(self.window, text=label_text)
        self.label.pack()
        self.button = Button(self.window, image=self.button_image, command=self.close)
        self.button.pack(pady=10)
        self.button.bind("<Return>", self.bind_close)

    def update(self):
        records = query_returns_table(database)
        populate_returns_tree(self.my_tree, records)

    def create_returns_report(self):
        lookup_record = self.kdm_division
        records, details = query_pdf_data(lookup_record)
        create_pdf(details, lookup_record)
        messagebox.showinfo("PDF Report Created", f"PDF file for {lookup_record} created.")

    def clear_entry_boxes(self):
        """Clear all entry boxes"""
        # Clear entry boxes
        try:
            database_id_entry.delete(0, END)
            # division_entry.delete(0, END)
            info_fleet_number_entry.delete(0, END)
            # info_job_number_entry.delete(0, END)
            info_description_entry.delete(0, END)
            # info_requested_by_entry.delete(0, END)
            info_date_added_entry.delete(0, END)
        except:
            pass

    def select_record(self, event):
        self.clear_entry_boxes()

        # Grab record Number
        selected = self.my_tree.focus()
        # Grab record values from the tree
        values = self.my_tree.item(selected, 'values')
        # output to entry boxes
        try:
            database_id_entry.insert(0, values[0])
            # print(f"ID = {values[0]}")

            info_fleet_number_entry.insert(0, values[1])
            # print(f"Fleet Number = {values[1]}")

            info_description_entry.insert(0, values[2])
            # print(f"Part description = {values[2]}")

            info_date_added_entry.insert(0, values[3])
            # print(f"Date added = {values[3]}")

        except:
            print("error")

    def close(self):
        """Close the current window and open the main window"""
        self.window.destroy()
        self.master_root.deiconify()

    def bind_close(self, event):
        self.close()

    def cancel_entry(self):
        """Close the window if canceled"""
        self.add_new_record_frame.destroy()

    def bind_cancel_entry(self, event):
        """Close the window if canceled"""
        self.cancel_entry()

    def bind_add_record_to_database(self, event):
        self.add_record_to_database()

    def reset(self):
        records = query_returns_table(database)
        populate_returns_tree(self.my_tree, records)

    def add_record_to_database(self):

        # Define the data to be inserted
        kdm_division = self.kdm_division
        fleet_number = new_fleet_number_entry.get().upper().strip()
        description = new_description_entry.get().title().strip()
        date = date_label.cget("text")

        status = 'current status'
        # division = self.kdm_division

        # Update the database
        # Create a database or connect to one that exists
        connection = sqlite3.connect(database)

        # Create a cursor instance
        cursor = connection.cursor()
        with connection:
            # Add New Record
            # Insert the data into the table
            cursor.execute("""
                INSERT INTO vor_shelves_data (kdm_division, fleet_number, parts_description, in_stock_since,status)
                VALUES (?, ?, ?, ?, ?)
            """, (kdm_division, fleet_number, description, date, status))

        self.add_new_record_frame.destroy()
        self.update()
        messagebox.showinfo("VOR Update", "Parts added.")

    def bind_query_kdm_division(self, event):
        self.update()

    def add_new_record_window(self):
        """Add new record to the database"""
        global add_new_record_frame
        app_width: int = 800
        app_height = 400
        self.add_new_record_frame = Toplevel(self.window)
        screen_width = self.add_new_record_frame.winfo_screenwidth()
        screen_height = self.add_new_record_frame.winfo_screenheight()
        # This will center the app on the screen
        x = (screen_width / 2) - (app_width / 2)
        y = (screen_height / 2) - (app_height / 2)

        self.add_new_record_frame.geometry(f'{app_width}x{app_height}+{int(x)}+{int(y)}')
        self.add_new_record_frame.title(f"Add new record to {self.kdm_division} Database")

        global new_fleet_number_entry
        fleet_number_label = Label(self.add_new_record_frame, text='Fleet Number', font=("Arial", 30))
        fleet_number_label.grid(row=2, column=0, padx=10, pady=10)
        new_fleet_number_entry = Entry(self.add_new_record_frame)
        new_fleet_number_entry.grid(row=2, column=1, padx=10, pady=10)

        global new_description_entry
        description_label = Label(self.add_new_record_frame, text="Parts Description", font=("Arial", 30))
        description_label.grid(row=4, column=0, padx=10, pady=10)
        new_description_entry = Entry(self.add_new_record_frame)
        new_description_entry.grid(row=4, column=1, padx=10, pady=10)

        global clicked
        clicked = StringVar()
        # clicked.set(name_options[0])
        global date_label

        global date_label

        def select_date():
            date_label.config(text=calendar.get_date())
            date_window.destroy()

        def pick_date():
            global calendar, date_window
            date_window = Toplevel()
            date_window.grab_set()
            date_window.title("Select Date")
            date_window.geometry("400x300")
            calendar = Calendar(date_window, selectmode='day', date_pattern="dd-mm-y", font=("Arial", 20),
                                borderwidth=2)
            calendar.pack()
            confirm_button = Button(date_window, text="Select", command=select_date)
            confirm_button.pack(pady=20)

        current_date = datetime.now().strftime("%d-%m-%Y")
        global new_date_entry
        new_date_label = Label(self.add_new_record_frame, text="Date Received", font=("Arial", 30))
        new_date_label.grid(row=5, column=0, padx=10, pady=10)

        date_label = Label(self.add_new_record_frame, text=current_date, font=("Arial", 30))
        # date_label = Label(root, text=current_date)
        date_label.grid(row=5, column=1, padx=10, pady=10)

        select_button = Button(self.add_new_record_frame, text="Select", command=pick_date, font=("Arial", 30))
        select_button.grid(row=5, column=2, padx=10, pady=10)

        worker_options = ["Worker 1", "Worker 2", "Worker 3", "Worker 4"]
        worker_label = Label(self.add_new_record_frame, text='Select Worker', font=("Arial", 30))
        worker_label.grid(row=7, column=0, padx=10, pady=10)

        self.worker_combobox = ttk.Combobox(self.add_new_record_frame, values=worker_options, font=("Arial", 30))
        self.worker_combobox.grid(row=7, column=1, padx=10, pady=10)
        self.worker_combobox.set(worker_options[0])  # Set the default selected worker

        add_button = Button(self.add_new_record_frame, text="Add Record", command=self.add_record_to_database,
                            font=("Arial", 30))
        add_button.bind("<Return>", self.bind_add_record_to_database)
        add_button.grid(row=8, column=1, padx=20, pady=10)
        # add_button.pack()

        cancel_button = Button(self.add_new_record_frame, text="Cancel", command=self.cancel_entry, font=("Arial", 30))
        cancel_button.bind("<Return>", self.bind_cancel_entry)
        cancel_button.grid(row=8, column=2, padx=10, pady=10)

    def remove_one(self):
        """Remove one item from the database"""
        confirmation = messagebox.askyesno("Delete Item", "Delete Item?")
        if confirmation == YES:
            selected_to_delete = self.my_tree.selection()[0]
            self.my_tree.delete(selected_to_delete)
            # Create a database or connect to one that exists
            connection = sqlite3.connect(database)
            # Create a cursor instance
            cursor = connection.cursor()
            # Delete From Database
            with connection:
                cursor.execute("DELETE from returns WHERE oid=" + database_id_entry.get())
            # Clear The Entry Boxes
            self.clear_entry_boxes()
            # Add a little message box for fun
            messagebox.showinfo("Deleted!", "Your Record Has Been Deleted!")
            self.update()

    def search_by_fleet_number(self):
        """Search By Fleet number"""
        lookup_record = search_fleet_entry.get().strip(' ')
        search_fleet_entry.delete(0, END)
        self.clear_entry_boxes()

        # Clear the Treeview
        for record in self.my_tree.get_children():
            self.my_tree.delete(record)
        # Create a database or connect to one that exists
        connection = sqlite3.connect(database)
        # Create a cursor instance
        cursor = connection.cursor()
        with connection:
            cursor.execute("SELECT rowid, * FROM returns WHERE fleet_number like ?", (lookup_record,))
            records = cursor.fetchall()
            # Add our data to the screen
        return records

    def bind_search_by_feet_number(self, event):

        self.update()

    def bind_query_kdm_division(self, event):
        """Bind function to query the database"""
        self.update()

    def update_details(self):
        selected_item = self.my_tree.focus()
        flee_number = info_fleet_number_entry.get().upper().strip()
        description = info_description_entry.get().title().strip()
        date = info_date_added_entry.get()
        oid = database_id_entry.get()

        self.my_tree.item(selected_item, values=(oid, flee_number, description))

        with sqlite3.connect(database) as connection:
            cursor = connection.cursor()
            cursor.execute("""UPDATE returns SET fleet_number = ?,parts_description = ?,in_stock_since = ?
                WHERE oid = ?
            """, (flee_number, description, date, oid))

        self.clear_entry_boxes()
        messagebox.showinfo("Vor Returns Update", "Record Updated.")
        records = query_kdm_division(self.my_tree, database, self.kdm_division)
        populate_division_tree(self.my_tree, records)

    def bind_update_details(self, event):
        self.update_details()

    def frame(self):

        main_frame = Frame(self.window, width=1200, height=700)
        main_frame.pack()
        global search_fleet_entry
        search_fleet_number_label = Label(main_frame, text="Search Fleet Number", font=("Arial", 30))
        search_fleet_number_label.grid(row=0, column=0, padx=10, pady=10)
        search_fleet_entry = Entry(main_frame)
        search_fleet_entry.bind("<Return>", self.bind_search_by_feet_number)
        search_fleet_entry.grid(row=0, column=1, padx=10, pady=10)

        reset_button = Button(main_frame, text="Reset", command=self.reset, font=("Arial", 20))
        reset_button.bind("<Return>", self.bind_query_kdm_division)
        reset_button.grid(row=0, column=4, padx=10, pady=10)

        tree_frame = Frame(self.window)
        tree_frame.pack(pady=5)

        # Create a Treeview Scrollbar
        tree_scroll = Scrollbar(tree_frame)
        tree_scroll.pack(side=RIGHT, fill=Y)
        # Create the treeview
        global my_tree
        self.my_tree = ttk.Treeview(tree_frame, yscrollcommand=tree_scroll.set, selectmode="extended")
        self.my_tree.pack()
        # Configure the Scrollbar
        tree_scroll.config(command=self.my_tree.yview)

        # Add Some Style
        self.style = ttk.Style()
        # Pick A Theme
        self.style.theme_use('default')
        # Configure the Treeview Colors
        self.style.configure("Treeview",
                             background="#D3D3D3",
                             foreground="black",
                             rowheight=30,
                             fieldbackground="#D3D3D3")

        self.style.configure("Treeview.Heading", font=("Arial", 25))  # Set the font size here for the column headings
        # configure the rows in the tree
        self.style.configure("Treeview", font=("Arial", 20))  # Set the font size here
        # Change Selected Color #347083
        self.style.map('Treeview',
                       background=[('selected', self.saved_highlight_color)])

        blue = "blue"
        gray = "lightgray"
        white = "white"

        self.my_tree.tag_configure('oddrow', background=gray)
        self.my_tree.tag_configure('evenrow', background=white)

        visible_items = 15  # Adjust the number of items visible in the treeview
        self.my_tree["height"] = visible_items

        self.my_tree['columns'] = (
            "id", "fleet_number", "parts_description", "in_stock_since", "status", "kdm_division")

        # Format Our Columns
        self.my_tree.column("#0", width=0, stretch=NO)
        self.my_tree.column("id", width=0, stretch=NO)
        self.my_tree.column("fleet_number", anchor=W, width=200)
        self.my_tree.column("parts_description", anchor=W, width=550)
        self.my_tree.column("in_stock_since", anchor=CENTER, width=300)
        self.my_tree.column("status", anchor=CENTER, width=200)
        self.my_tree.column("kdm_division", width=0, stretch=NO)

        # Create Headings
        self.my_tree.heading("#0", text="", anchor=W)
        self.my_tree.heading("id", text="ID", anchor=W)
        self.my_tree.heading("fleet_number", text="Fleet Number", anchor=W)
        self.my_tree.heading("parts_description", text="Parts Description", anchor=W)
        self.my_tree.heading("in_stock_since", text="In Stock Since", anchor=CENTER)
        self.my_tree.heading("status", text="Days In Stock", anchor=CENTER)
        self.my_tree.heading("kdm_division", text="KDM Division", anchor=CENTER)

        self.blue = "blue"
        self.gray = "lightgray"
        self.white = "white"

        # Create Striped Row Tags
        self.my_tree.tag_configure('oddrow', background=self.gray)
        self.my_tree.tag_configure('evenrow', background=self.white)

        first_column_name = "Database ID"
        second_column_name = "Division"
        third_column_name = "Fleet Number"
        fourth_column_name = "Job Number"
        fifth_column_name = "Description"
        sixth_column_name = "Requested By"
        seventh_column_name = "Date Added"

        # Item Info Frame
        information_frame = LabelFrame(self.window, text="Fleet Information", font=("Arial", 30))
        information_frame.pack(fill="x", expand="yes", padx=20)
        # information_frame.grid(row=3, column=0)

        global database_id_entry
        database_id_label = Label(information_frame, text=first_column_name)
        # database_id_label.grid(row=0, column=6, padx=10, pady=10)
        database_id_entry = Entry(information_frame)
        # database_id_entry.grid(row=0, column=7, padx=10, pady=10)

        global division_entry
        division_label = Label(information_frame, text=second_column_name)

        division_entry = Entry(information_frame)

        global info_fleet_number_entry
        fleet_number_label = Label(information_frame, text=third_column_name)
        fleet_number_label.grid(row=0, column=0, padx=10, pady=10)
        info_fleet_number_entry = Entry(information_frame)
        info_fleet_number_entry.grid(row=0, column=1, padx=10, pady=10)

        global info_description_entry
        description_label = Label(information_frame, text=fifth_column_name)
        description_label.grid(row=0, column=2, padx=10, pady=10)
        info_description_entry = Entry(information_frame)
        info_description_entry.grid(row=0, column=3, padx=10, pady=10)

        # clicked = StringVar()
        # clicked.set(options[0])

        global info_date_added_entry
        date_added_label = Label(information_frame, text=seventh_column_name)
        date_added_label.grid(row=0, column=4, padx=10, pady=10)
        info_date_added_entry = Entry(information_frame)
        info_date_added_entry.grid(row=0, column=5, padx=10, pady=10)

        # Item Info Frame
        update_button = Button(information_frame, text="Update Record", command=self.update_details)
        update_button.bind("<Return>", self.bind_update_details)
        update_button.grid(row=0, column=6, padx=10, pady=10)

        # Command Frame
        command_frame = LabelFrame(self.window, text="Commands", font=("Arial", 30))
        command_frame.pack(fill="x", expand="yes", padx=20)

        # Add Buttons
        add_new_button = Button(command_frame, text="Add New Goods Return",
                                command=self.add_new_record_window, font=("Arial", 30))
        add_new_button.bind()
        add_new_button.grid(row=0, column=0, padx=10, pady=10)

        remove_selected_button = Button(command_frame, text="Close Goods Return",
                                        command=self.remove_one, font=("Arial", 30))
        remove_selected_button.bind()
        remove_selected_button.grid(row=0, column=2, padx=10, pady=10)

        clear_entry_button = Button(command_frame, text="Clear Entry Boxes",
                                    command=self.clear_entry_boxes, font=("Arial", 30))
        clear_entry_button.grid(row=0, column=7, padx=10, pady=10)

        generate_report_button = Button(command_frame, text="Print Report",
                                        command=self.create_returns_report, font=("Arial", 30))
        generate_report_button.grid(row=0, column=8, padx=10, pady=10)
        # Bind the treeview
        self.my_tree.bind("<ButtonRelease-1>", self.select_record)
        self.my_tree.bind("<Return>", self.select_record)

        self.update()

if __name__ == "__main__":
    root = Tk()
    global kdm_division
    # kdm_division = "Goods Return"
    kdm_division = "Plant"
    division_image = "images/plant.png"
    # division_image = "images/small.png"
    GoodsReturnClass(root, kdm_division, division_image)
    root.mainloop()