# -*- coding: utf-8 -*-
"""
Created on Thu Dec 06 09:49:58 2018

@author: daniel
"""

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import math
import os
import csv
import os.path
import tarfile
import shutil
import collections

"""
Function that checks if there is no ocean/sea on the left side of the model domain, if there is it finds the highest positioned
point of the inland area and clips the model accordingly (keeping the domain to the right side of that point). This simulates the
position of the water divide.

top_lst = model.top_elev
ib_arr = model.ibound_arr
model_obj = model

"""
def trim_model_domain(model_obj, top_lst, ib_arr):

    #   first check if there really is a sea on the left side of the model domain, if there actually is one then find the index of the
    #   left coastline position. Trim the topo values in case there is also sea/ocean at the left side of the land (land looks like an island)

    left_side = top_lst[:25]
    neg_lst = [i for i in left_side if i < 0]
    if len(neg_lst) > 0:
        start = 0
        for f in range(100):
            cut_lst = top_lst[start : start + 10]
            if len([i for i in cut_lst if i < 0]) >= 5:
                start += 10
            else:
                break
        idx_neg = start#left_side.index([i for i in left_side if i < 0][-1])
        while top_lst[idx_neg] < -0.:
            idx_neg += 1
        new_st_idx = idx_neg

    else:
        idx_neg = 0
        while top_lst[idx_neg] < -0.:
            idx_neg += 1
        new_st_idx = 0

    left_cst_idx = idx_neg

    #   check that the landward boundary doesnt have any empty columns on the inland side of the model domain
    for z in range(ib_arr.shape[-1]):
        ibound_act_lay_idxs = [i for i, x in enumerate(model_obj.ibound_arr[:, 0, z].tolist()) if x == 1]
        if ibound_act_lay_idxs != []:
            break#pass
        else:
            new_st_idx += 1
            pass#break
    ib_arr = ib_arr[:, :, new_st_idx:]

    #   check if there is any column that contains only inactive cells - if so then cut the IBOUND array to end before that column
    new_end_idx = -1
    for a in range(new_st_idx, model_obj.ibound_arr.shape[-1]):
        ibound_act_lay_idxs = [i for i, x in enumerate(model_obj.ibound_arr[:, 0, a].tolist()) if x == 1]
        if ibound_act_lay_idxs != []:
            pass
        else:
            ib_arr = ib_arr[:, :, : a - new_st_idx]
            new_end_idx = a
            break

    #   second step also checks that the end of the model domain ends at the lowest point, start from the end of the model domain
    if new_end_idx != -1:
        offsh_indx = new_end_idx
    else:
        offsh_indx = len(top_lst)

    for b in range(offsh_indx - 11, 10, -10):

        top_right_lst = []
        for c in range(b, b + 10):
            top_right_lay = [j for j, x in enumerate(model_obj.ibound_arr[:, 0, c].tolist()) if x == 1][0]
            top_right_lst.append(top_right_lay)

        top_left_lst = []
        for d in range(b - 10, b):
            top_lay_left = [j for j, x in enumerate(model_obj.ibound_arr[:, 0, d].tolist()) if x == 1][0]
            top_left_lst.append(top_lay_left)

        print(np.mean(top_left_lst), np.mean(top_right_lst))

        #   if the elevation on the right is higher than on the left, continue
        if np.mean(top_left_lst) >= np.mean(top_right_lst) + 1.0:
            pass
        else:
            new_end_idx = b
            #new_end_lay = [j for j, x in enumerate(model_obj.ibound_arr[:, 0, b].tolist()) if x == 1][-1]
            #ib_arr = ib_arr[:new_end_lay, :, :b]
            break

    #   now check that the right side of the model domain is not actually even higher than the left side
    if top_lst[new_end_idx] > top_lst[0]:
        print(top_lst[new_end_idx], top_lst[0])
        new_end_idx = top_lst.index(min(top_lst))
        b = new_end_idx

    new_end_lay_1 = [j for j, x in enumerate(model_obj.ibound_arr[:, 0, new_end_idx].tolist()) if x == 1][-1]
    new_end_lay_2 = new_end_lay_1

    #for c in range(model_obj.cst_idx, new_end_idx):
    for c in range(int(model_obj.cst_idx / 2), new_end_idx):
        try:
            new_end_lay_3 = [j for j, x in enumerate(model_obj.ibound_arr[:, 0, c].tolist()) if x == 1][-1]
            if new_end_lay_3 > new_end_lay_2:
                new_end_lay_2 = new_end_lay_3
        except IndexError:
            pass

    new_end_lay = max(new_end_lay_1, new_end_lay_2)

    if b < new_end_idx:
        ib_arr = ib_arr[:new_end_lay, :, : b]
    else:
        ib_arr = ib_arr[:new_end_lay, :, :]
    """
    #   if the idx_neg is 0 then dont do anything otherwise adjust the model domain and
    if idx_neg == 0:

        #   check for multiple landmasses
        import itertools
        splitted = [list(g) for i, g in itertools.groupby(top_lst,lambda x: x<0)]

        #   sometimes there might be small chunks of below sea level areas, but those are not the real ocean yet
        #   check from the beginning of the splitted list and if there is a short (< 2km) below sea level area
        new_splitted = [x for x in splitted]

        g = 1
        while len(new_splitted[g]) <= 20 and new_splitted[g][0] < 0. or new_splitted[g][0] > 0.:
            new_splitted[0] = new_splitted[0] + splitted[g]
            del new_splitted[g]

        if len(new_splitted) > 2 and new_splitted[0][0] > 0. and new_splitted[1][0] < 0.:
            new_end_idx = top_lst.index(min(new_splitted[1]))
            max_elev = max(top_lst[:new_end_idx])
            if top_lst.index(max_elev) > 0:
                max_elev_idx = top_lst.index(max_elev) - 1
            else:
                max_elev_idx = top_lst.index(max_elev)

            new_x_start = model_obj.x_start
            new_ib_arr = ib_arr[:, :, :new_end_idx]
            new_ncol = new_ib_arr.shape[-1]

        else:
            new_x_start = model_obj.x_start
            new_ib_arr = ib_arr
            new_ncol = ib_arr.shape[-1]
            max_elev = max(top_lst[:])
            max_elev_idx = top_lst.index(max_elev) - 1
            idx_neg = 0

        return new_x_start, new_ib_arr, new_ncol, max_elev_idx, new_end_idx, idx_neg

    else:
    """
    #   find the position of the coastline on the right side of the model domain
    #cst_val  = next((x for x in top_lst[left_cst_idx:] if x < 0.0), None)
    #right_cst_idx = left_cst_idx + top_lst[left_cst_idx:].index(cst_val) - 1
    right_cst_idx = - 1
    #   now find the maximum elevation between these two points
    try:
        max_elev = max(top_lst[left_cst_idx:right_cst_idx])
        max_elev_idx = top_lst.index(max_elev) #- 1 - left_cst_idx
    except ValueError:
        max_elev = max(top_lst[left_cst_idx:])
        max_elev_idx = top_lst.index(max_elev) #- 1 - left_cst_idx

    #   change the
    new_x_start = -(max_elev_idx / 10.) #model_obj.x_start + (max_elev_idx / 10.)
    new_ib_arr = ib_arr[:, :, max_elev_idx : new_end_idx]
    new_end_idx = max_elev_idx + new_ib_arr.shape[-1]
    new_ncol = new_ib_arr.shape[-1]

    return new_x_start, new_ib_arr, new_ncol, max_elev_idx, new_end_idx, idx_neg

def find_lonely_cells(ibound_array):

    col_n = ibound_array.shape[-1]
    row_n = ibound_array.shape[0]

    #   go through the ibound_arr cell by cell
    for j in range(1, col_n - 1):
        for i in range(1, row_n - 1):
            if j == 0:
                left = 0
            else:
                left = ibound_array[i-1,0,j]

            if j == (col_n - 1):
                right = 0
            else:
                right = ibound_array[i+1,0,j]

            if i == 0:
                up = 0
            else:
                up = ibound_array[i,0,j-1]

            if i == (row_n -1):
                down = 0
            else:
                down = ibound_array[i,0,j+1]

            if (left == 0 and right == 0 and up == 0 and down == 0):
                ibound_array[i,0,j] = 0

    return ibound_array

"""
Function that reads a CSV file and returns the lognormal values of MU and STDEV depending
on what COSCAT region and which parameter we are looking for.

coscat_id = 16
subreg_id = 1
csv_dir = r'g:\Water_Nexus\_A4_GUM\_MODEL_input_files\_SUBREG_representative_models_GEOLOGY_stats.csv'
cst_type = 'henry_other'
param_type = 'glhymps_bot'
"""

def read_param_from_csv_subreg(coscat_id, subreg_id, csv_dir, param_type):
    #   read in the csv file with pandas and get the list of column names
    df = pd.read_csv(csv_dir, index_col = False, header = 0)
    col_names = list(df.columns.values)
    #   define the name of the column we are looking for based on the function parameters
    col_param_name = param_type
    match_str = [s for s in col_names if col_param_name in s]
    #   find which string is the mu and which is the stdv
    mu_col = [r for r in match_str if 'mu' in r]
    std_col = [r for r in match_str if 'std' in r]
    #   find the values in the table
    mu_val = df.loc[(df[col_names[0]] == coscat_id) & (df[col_names[1]] == subreg_id), mu_col].values[0]
    std_val = df.loc[(df[col_names[0]] == coscat_id) & (df[col_names[1]] == subreg_id), std_col].values[0]
    #   return the final values
    return mu_val, std_val

def read_param_from_csv(coscat_id, csv_dir, param_type):
    #   read in the csv file with pandas and get the list of column names
    df = pd.read_csv(csv_dir, index_col = False, header = 0)
    col_names = list(df.columns.values)
    #   define the name of the column we are looking for based on the function parameters
    col_param_name = param_type
    match_str = [s for s in col_names if col_param_name in s]
    #   find which string is the mu and which is the stdv
    mu_col = [r for r in match_str if 'mu' in r]
    std_col = [r for r in match_str if 'std' in r]
    #   find the values in the table
    mu_val = df.loc[df[[col_names[0]] == coscat_id], mu_col].values[0]
    std_val = df.loc[df[col_names[0]] == coscat_id, std_col].values[0]
    #   return the final values
    return mu_val, std_val

"""
Function that generates a set of randomly generated values based on a lognormal distribution.
The input variables are the mu_val and std_val create in the previous function.

mu_in = mu_val
std_in = std_val
len_lst = 100
title = 'RCH input values per column'
y_label = 'RCH rate in mm/d'
"""

def generate_ln_rand_lst(rand_seed_val, mu_in, std_in, len_lst, title, y_label, fig_out_dir, plot = True):
    #   set the random seed for this function
    np.random.seed(rand_seed_val)
    #   generate an array of values drawn from the normal distribution
    rand_vals = np.exp(np.random.normal(mu_in, std_in, size = len_lst))
    #   if the plotting is set to True also give the output plots
    if plot is True:
        #   create an X value list
        x_col = np.linspace(0, len_lst - 1, len_lst)
        #   define window size, output and axes
        fig, ax = plt.subplots(figsize=[8,6])
        ax.bar(x_col, rand_vals)
        #   set plot title
        ax.set_title(title)
        #   set x-axis name
        ax.set_xlabel("MODFLOW column number")
        #   set y-axis name
        ax.set_ylabel(y_label)
        ax = plt.gca()
        ax.yaxis.grid()
        #   save the figure
        plt.savefig(fig_out_dir, dpi = 300)
        plt.close()
        del fig
    #   return the list of randomly generated values
    return rand_vals.tolist()

"""
Function that finds and provides the geological input parameters for each COSCAT region.

coscat_id = 1413
csv_dir = r'g:\Water_Nexus\_A2\_models_final\coscat_geology_input.csv'

"""

def read_geo_params(coscat_id, csv_dir):

    #   get the sand and mud % for the given coscat region
    df = pd.read_csv(csv_dir, index_col = False, header = 0)
    col_names = list(df.columns.values)
    sand_val = df.loc[df[col_names[0]] == coscat_id, 'Sand_gl'].values[0]
    mud_val = df.loc[df[col_names[0]] == coscat_id, 'Mud_gl'].values[0]
    y_exact_val = df.loc[df[col_names[0]] == coscat_id, 'Y1'].values[0]
    qs_val = df.loc[df[col_names[0]] == coscat_id, 'QS'].values[0]
    sm_val = df.loc[df[col_names[0]] == coscat_id, 'SM'].values[0]
    y_val = df.loc[df[col_names[0]] == coscat_id, 'Y'].values[0]
    shlf_mud_val = df.loc[df[col_names[0]] == coscat_id, 'Mud_shlf'].values[0]
    slp_mud_val = df.loc[df[col_names[0]] == coscat_id, 'Mud_slp'].values[0]
    #   since the total sum of these two (sand and mud) doesnt amount to 100%
    add_val = (100. - (sand_val + mud_val)) / 2.
    sand_pct, mud_pct = sand_val + add_val, mud_val + add_val
    #   calculate the % for the reworking parameter - basically multiply by 5 since the
    #   highest Y1 value is ~20 (100/20 = 5)
    y_val_out = y_exact_val * 5.

    #   return the final output values
    return qs_val, sm_val, y_val, y_val_out, sand_pct, mud_pct, shlf_mud_val, slp_mud_val

"""
Function that loads in the final output budget file and for each time step computes how much
recharge gets drained for the total model domain.

budget_in = r'g:\Water_Nexus\_A2\_models_testing_1413\coscat_1413_geo_scenario_1_rch_p_min_et\eq_1\_cbc.npy'

rch_csv = r'g:\Water_Nexus\_A2\_models_final\_COSCAT_representative_models_RCH_stats.csv'
rch_param_p_min_et_ln = read_param_from_csv(1413, rch_csv, 'henry_other', 'cs_p_min_et_rch')

np.random.seed(1)
#   generate an array of values drawn from the normal distribution
rch_lst_in = np.exp(np.random.normal(rch_param_p_min_et_ln[0], rch_param_p_min_et_ln[1], size = 217))

"""

def model_res_analysis_rch_drn(budget_in, rch_lst_in):

    #   load the budget dictionary
    dict_in = np.load(budget_in).item()
    #   loop through all the keys of the dictionary and get the RCH and DRN arrays
    for key in dict_in.keys():

        if key != 0:
            rch_arr = dict_in[key]['q_rch'][1][0]
            drn_arr = dict_in[key]['q_drn']

            drn_sum, rch_sum = 0., 0.

            for i in range(len(drn_arr)):
                rch_val = rch_arr[i]
                drn_val = drn_arr[i][1]
                rch_in = rch_lst_in[i] * 0.001

                drn_sum += drn_val
                rch_sum += rch_val

                print(rch_in, rch_val, drn_val)

            print(rch_sum, drn_sum)

#   transform the point water head to fresh water head array
def pt_hd_to_frsh_hd(pt_hd_arr, conc_arr, densref, denseslp, top_elev, bot_lst):

    top_bot_lst = [top_elev] + bot_lst
    frsh_hd_arr = pt_hd_arr * 0.0

    for i in range(pt_hd_arr.shape[0]):
        for j in range(pt_hd_arr.shape[-1]):

            pt_head = pt_hd_arr[i, 0, j]
            conc = denseslp * conc_arr[i, 0, j] + densref
            z = (top_bot_lst[i] + top_bot_lst[i + 1]) / 2

            frsh_hd_arr[i, 0, j] = (conc / densref) * pt_head - ((conc - densref) / densref) * z

    return frsh_hd_arr

#   gets the volumes and % of freshwater in different zones of the model domain
"""
arr_ibound = model.ibound_arr
arr_conc = conc_arr
idx_cst = cst_idx_0  #int(abs(model.x_start) * 10)
idx_shelf_edge = idx_shelf_edge_0  #int((cont_shelf_edge[0] - model.x_start) * 10)

"""
def get_frsh_vol_pct(arr_ibound, arr_conc, idx_cst, idx_shelf_edge):
    #   calculate the volume and % in the inland zone
    tot_inland_cells, fresh_inland_cells = 0, 0
    for a in range(idx_cst):
        ibound_act_lay_idxs = [i for i, x in enumerate(arr_ibound[:, 0, a].tolist()) if x == 1]
        #   loop through the active layers and check whether the concentration is fresh or not
        for x in range(len(ibound_act_lay_idxs)):
            if arr_conc[ibound_act_lay_idxs[x], 0, a] <= 0.1:
                fresh_inland_cells += 1
        tot_inland_cells += len(ibound_act_lay_idxs)

    #   calculate the volume and % in the shelf zone
    tot_shelf_cells, fresh_shelf_cells = 0, 0
    for b in range(idx_cst, min(idx_shelf_edge, arr_conc.shape[-1])):
        ibound_act_lay_idxs = [i for i, x in enumerate(arr_ibound[:, 0, b].tolist()) if x == 1]
        #   loop through the active layers and check whether the concentration is fresh or not
        for y in range(len(ibound_act_lay_idxs)):
            if arr_conc[ibound_act_lay_idxs[y], 0, b] <= 0.1:
                fresh_shelf_cells += 1
        tot_shelf_cells += len(ibound_act_lay_idxs)

    return tot_inland_cells, fresh_inland_cells, tot_shelf_cells, fresh_shelf_cells

#   define a function to plot the GHB boundary and top system summary (DRN and RCH)
"""
ghb_cell_head_lst = model.ghb_head_diff_lst
ghb_cell_head_max_diff = model.ghb_head_check_max_diff
ghb_in_lst = model.ghb_input_lst
rch_lst = rch_p_min_et_lst_m_d
q_rch = qrch
q_drn = qdrains
q_ghb = qghb
delcol = model.del_col
ncol = model.ncol

arr_hk = model.hk_arr
cond_lst = model.ghb_input_lst
index_coast = idx_cst

top_el = model.top_elev
x_st = model.x_start
x_end = model.x_end
index_coast = model.rch_extent
"""

def plot_ghb_drn_rch_summary(index_coast, ghb_cell_head_lst, ghb_cell_head_max_diff, rch_lst, q_rch, q_drn, q_ghb, top_el, x_st, x_end, delcol, ncol, arr_hk, cond_lst, save_dir):

    #index_coast = int(abs(x_st) * 10.)
    fig = plt.figure(figsize = (20, 12))
    #   create a figure object and assign all the parts
    ax1 = plt.subplot2grid((3, 1), (0, 0))  #
    ax2 = plt.subplot2grid((3, 1), (1, 0))  #
    ax3 = plt.subplot2grid((3, 1), (2, 0))  #
    ax2b = ax2.twinx()  # instantiate a second axes that shares the same x-axis
    ax3b = ax3.twinx()  # instantiate a second axes that shares the same x-axis
    #   set the exact positions for each axis
    ax1.set_position([0.05, 0.675, 0.9, 0.25]) # [left, bottom, width, height]
    ax2.set_position([0.05, 0.35, 0.9, 0.25])
    ax3.set_position([0.05, 0.025, 0.9, 0.25])

    #   create the first plot that will show the RCH rates and the GHB difference between assigned and modelled heads
    x_axis_pts = np.linspace(x_st + (delcol / (2 * 1000.)), x_end - (delcol / (2 * 1000.)), ncol)

    #   prepare the individual type of internal flow types for plotting
    qrch_to_plot = q_rch[1].tolist()[0]
    qdrn_to_plot = [round(i[1], 6) for i in q_drn.tolist()] + (ncol - len([round(i[1], 6) for i in q_drn.tolist()])) * [0.]
    qghb_to_plot = len([round(i[1], 6) for i in q_drn.tolist()]) * [0.] + [round(i[1], 6) for i in q_ghb.tolist()][:ncol - len([round(i[1], 6) for i in q_drn.tolist()])]

    tot_lst = qrch_to_plot + qdrn_to_plot + qghb_to_plot

    ax1.bar(x_axis_pts, qrch_to_plot, color = 'blue', width = 0.1, label = 'RCH flow in the cell')
    ax1.bar(x_axis_pts, qdrn_to_plot, color = 'red', width = 0.1, label = 'DRN flow in the cell')
    ax1.bar(x_axis_pts, qghb_to_plot, color = 'green', width = 0.1, label = 'GHB flow in the cell')
    ax1.axis([x_st, x_end, 0., max(list(rch_lst[:index_coast + 1])) * 1000.])
    ax1.set_ylabel('Flow rate (m3/d)')
    ax1.axhline(y = 0., linewidth = 1, color = 'k')
    ax1.set_xlim([x_st, x_end])
    ax1.set_ylim([math.floor(min(tot_lst) * 10.) / 10., math.ceil(max(tot_lst) * 10.) / 10.])
    ax1.set_title('Top system and boundary flow rates in the model domain', fontsize = 14, y = 1.01)
    ax1.legend(loc = 'best')

    rch_to_plot = list([i * 1000. for i in rch_lst[:index_coast]])
    rch_to_plot.extend([0] * (ncol - index_coast))
    ax2.bar(x_axis_pts, rch_to_plot, width = 0.1, label = 'RCH rate')
    #ax2.plot(list(x_axis_pts[:index_coast]), list([i * 1000. for i in rch_lst[:index_coast]]), 'co', markersize = 3, label = 'GEBCO elevation')
    ax2.axis([x_st, x_end, 0., max(list(rch_lst[:index_coast])) * 1000.])
    ax2.set_ylabel('Recharge rate (mm/d)')

    ghb_to_plt_1 = [y[-1] for y in ghb_cell_head_lst if y[2] >= index_coast]
    ghb_to_plt_y = [0] * (ncol - len(ghb_to_plt_1)) + ghb_to_plt_1

    mask1 = np.asarray(ghb_to_plt_y) < 0.0001
    mask2 = np.asarray(ghb_to_plt_y) >= 0.0001
    if x_axis_pts[mask1] != []:
        ax2b.bar(x_axis_pts[mask1], np.asarray(ghb_to_plt_y)[mask1], width = 0.1, color = 'green', label = 'GHB head diff < 0.0001')
    if x_axis_pts[mask2] != []:
        ax2b.bar(x_axis_pts[mask2], np.asarray(ghb_to_plt_y)[mask2], width = 0.1, color = 'red', label = 'GHB head diff > 0.0001')
    ax2b.set_ylim([0., min(.25, round(max(ghb_to_plt_y), 5))])
    ax2b.set_ylabel('GHB head difference (m) between assigned and simulated head')
    ax2.set_title('Recharge rate and GHB head difference (assigned vs. computed) in the model domain', fontsize = 14, y = 1.01)

    lines, labels = ax2.get_legend_handles_labels()
    lines2, labels2 = ax2b.get_legend_handles_labels()
    ax2.legend(lines + lines2, labels + labels2, loc = 0)

    #   get the conductivity of the top active cell in each column
    hk_lst = []
    for  d in range(ncol):
        hk_lst.append(arr_hk[:, 0, d].tolist()[[i for i, x in enumerate(arr_hk[:, 0, d].tolist()) if not math.isnan(x)][0]])
    lst_cond_to_plot = len([round(i[1], 6) for i in q_drn.tolist()]) * [0.] + [i[-1] for i in cond_lst][:ncol - len([round(i[1], 6) for i in q_drn.tolist()])]

    ax3.axis([x_st, x_end, 0., math.ceil(max(hk_lst))])
    ax3.set_ylabel('Hydraulic conductivity (m/d)')
    ax3b.plot(x_axis_pts, lst_cond_to_plot, linewidth = 0.1, color = 'blue', label = 'GHB conductance')
    hk_mask1 = np.asarray(hk_lst) < 0.01
    hk_mask2 = np.asarray(hk_lst) >= 0.01
    if x_axis_pts[hk_mask1] != []:
        ax3.bar(x_axis_pts[hk_mask1], np.asarray([math.ceil(max(hk_lst)) * 0.5] * ncol)[hk_mask1], width = 0.1, color = 'red', label = 'Hk, clay cells')
    if x_axis_pts[hk_mask2] != []:
        ax3.bar(x_axis_pts[hk_mask2], np.asarray(hk_lst)[hk_mask2], width = 0.1, color = 'green', label = 'Hk, non-clay cells')
    ax3b.set_ylabel('Conductance (m2/d)')
    ax3b.set_ylim([0., math.ceil(max(lst_cond_to_plot))])
    ax3.set_title('Horizontal hydraulic conductivity and GHB conductance in the model domain', fontsize = 14, y = 1.01)

    lines, labels = ax3.get_legend_handles_labels()
    lines2, labels2 = ax3b.get_legend_handles_labels()
    ax3.legend(lines + lines2, labels + labels2, loc=0)

    if os.path.exists(save_dir):
        print('Figure   ' + save_dir + '   already exists.')
    else:
        #   save the figure
        plt.savefig(save_dir, dpi = 300)
    plt.close()

"""
Function that wraps up at the end of each model simulation and creates the final output files as netcdf files. The input to the function
is just the directory pointing to the folder system with the model results.

model_dir = r'g:\Water_Nexus\_A2\_models_param_runs\_1103\coscat_1103_param_combo_run_1'
summary_folder = r'g:\Water_Nexus\_A2\_models_param_runs\_1103\coscat_1103_param_combo_run_1\summary_dir'

in_dir = model_dir
summary_dir = os.path.join(summary_folder, '_conc_results')
out_name = 'coscat_1103_param_combo_run_1'

char_dir_conc = os.path.join(char_time_dir, '_conc_results')

dict_ex = np.load(r'g:\Water_Nexus\_A2\_models_param_runs\_0403\all\coscat_0403_param_combo_run_1\eq_00\_conc.npy')

"""

def create_conc_tar(in_dir, summary_dir, char_dir_conc, out_name):

    #   initialize the simulation time
    simu_time = 0
    final_dict = dict()

    #   create lists of folders where the _conc dictionaries should be found
    file_list = os.listdir(in_dir)
    file_list_no_char = [i for i in file_list if 'eq' in i and 'time' not in i]
    file_name_list_no_char = [i.split('_')[-1] for i in file_list_no_char]
    file_name_list_no_char = sorted(file_name_list_no_char)
    #   make a special list for the char times results
    file_list_char = [i for i in file_list if 'eq' in i and 'time' in i]
    file_name_list_char = [i.split('_')[1].split('_')[0] for i in file_list_char]
    file_name_list_char = sorted(file_name_list_char)

    #   loop through the char time list first
    for file in file_name_list_char:
        #   create the conc.npy filename and check if it exists
        dict_dir = os.path.join(in_dir, 'eq_' + file + '_char_time')
        dict_path = os.path.join(dict_dir, '_conc.npy')
        if os.path.exists(dict_path):
            print('dict_dir :       ' + dict_path)
            final_dict_char_time = dict()
            #   load the dictionary and individually read the data inside key by key
            conc_dict = np.load(dict_path)[()]
            #   read each key, change the value of the key according to the time stamp (real time since simulation start)
            for key in conc_dict:
                real_time = simu_time + key
                #data = xr.DataArray(np.round(conc_dict[key]['conc'], 3), dims = ('lay', 'row', 'col'), name = real_time)
                final_dict_char_time[real_time] = {'conc': np.round(conc_dict[key]['conc'], 3)}
            fin_dict_char_time_dir = os.path.join(char_dir_conc, out_name + 'eq_' + file + '_char_time' + '.npy')
            final_dict_char_time_ordered = collections.OrderedDict(sorted(final_dict_char_time.items()))
            #   save the dictionary
            np.save(fin_dict_char_time_dir, final_dict_char_time_ordered)

    #   do the same for the list with no_char_time dictionaries
    for file in file_name_list_no_char:
        #   create the conc.npy filename and check if it exists
        dict_dir = os.path.join(in_dir, 'eq_' + file)
        dict_path = os.path.join(dict_dir, '_conc.npy')
        if os.path.exists(dict_path):
            print('dict_dir :       ' + dict_path)
            #   load the dictionary and individually read the data inside key by key
            conc_dict = np.load(dict_path)[()]
            #   read each key, change the value of the key according to the time stamp (real time since simulation start)
            for key in conc_dict:
                real_time = simu_time + key
                final_dict[real_time] = {'conc': np.round(conc_dict[key]['conc'], 3)}
        simu_time += key

    #fin_dict_dir = r'g:\\Water_Nexus\\_A2\\_models_testing_1413\\cartesius_runs\\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1\\eq_31_char_time\\_conc_cmp.npy'
    #fin_dict_tar_dir = r'g:\\Water_Nexus\\_A2\\_models_testing_1413\\cartesius_runs\\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1\\eq_31_char_time\\_conc_cmp.tar.xz'
    fin_dict_dir = os.path.join(summary_dir, out_name + '.npy')
    final_dict_ordered = collections.OrderedDict(sorted(final_dict.items()))
    np.save(fin_dict_dir, final_dict_ordered)
    #fin_dict_tar_dir =  os.path.join(summary_dir, out_name + '.tar.xz')

    #tar = tarfile.open(fin_dict_tar_dir, "w:xz")
    #tar.add(fin_dict_dir)
    #tar.close()
    #os.remove(fin_dict_dir)

"""  Same kind of function, but this time for the heads dictionary   """
def create_head_tar(in_dir, summary_dir, char_dir_head, out_name):

    #   initialize the simulation time
    simu_time = 0
    final_dict = dict()

    #   create lists of folders where the _conc dictionaries should be found
    file_list = os.listdir(in_dir)
    file_list_no_char = [i for i in file_list if 'eq' in i and 'time' not in i]
    file_name_list_no_char = [i.split('_')[-1] for i in file_list_no_char]
    file_name_list_no_char = sorted(file_name_list_no_char)
    #   make a special list for the char times results
    file_list_char = [i for i in file_list if 'eq' in i and 'time' in i]
    file_name_list_char = [i.split('_')[1].split('_')[0] for i in file_list_char]
    file_name_list_char = sorted(file_name_list_char)

    #   loop through the char time list first
    for file in file_name_list_char:
        #   create the conc.npy filename and check if it exists
        dict_dir = os.path.join(in_dir, 'eq_' + file + '_char_time')
        dict_path = os.path.join(dict_dir, '_head.npy')
        if os.path.exists(dict_path):
            print('dict_dir :       ' + dict_path)
            final_dict_char_time = dict()
            #   load the dictionary and individually read the data inside key by key
            head_dict = np.load(dict_path)[()]
            #   read each key, change the value of the key according to the time stamp (real time since simulation start)
            for key in head_dict:
                real_time = simu_time + key
                #data = xr.DataArray(np.round(conc_dict[key]['conc'], 3), dims = ('lay', 'row', 'col'), name = real_time)
                final_dict_char_time[real_time] = {'head': np.round(head_dict[key]['head'], 3)}
            fin_dict_char_time_dir = os.path.join(char_dir_head, out_name + 'eq_' + file + '_char_time' + '.npy')
            final_dict_char_time_ordered = collections.OrderedDict(sorted(final_dict_char_time.items()))
            #   save the dictionary
            np.save(fin_dict_char_time_dir, final_dict_char_time_ordered)

    #   do the same for the list with no_char_time dictionaries
    for file in file_name_list_no_char:
        #   create the conc.npy filename and check if it exists
        dict_dir = os.path.join(in_dir, 'eq_' + file)
        dict_path = os.path.join(dict_dir, '_head.npy')
        if os.path.exists(dict_path):
            print('dict_dir :       ' + dict_path)
            #   load the dictionary and individually read the data inside key by key
            head_dict = np.load(dict_path)[()]
            #   read each key, change the value of the key according to the time stamp (real time since simulation start)
            for key in head_dict:
                real_time = simu_time + key
                final_dict[real_time] = {'head': np.round(head_dict[key]['head'], 3)}
        simu_time += key

    #fin_dict_dir = r'g:\\Water_Nexus\\_A2\\_models_testing_1413\\cartesius_runs\\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1\\eq_31_char_time\\_conc_cmp.npy'
    #fin_dict_tar_dir = r'g:\\Water_Nexus\\_A2\\_models_testing_1413\\cartesius_runs\\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1\\eq_31_char_time\\_conc_cmp.tar.xz'
    fin_dict_dir = os.path.join(summary_dir, out_name + '.npy')
    final_dict_ordered = collections.OrderedDict(sorted(final_dict.items()))
    np.save(fin_dict_dir, final_dict_ordered)

"""  Same kind of function, but this time for the CBC dictionary   """
def create_cbc_tar(in_dir, summary_dir, char_dir_cbc, out_name):

    #   initialize the simulation time
    simu_time = 0
    final_dict = dict()

    #   create lists of folders where the _conc dictionaries should be found
    file_list = os.listdir(in_dir)
    file_list_no_char = [i for i in file_list if '_to_' in i]
    file_name_list_no_char = file_list_no_char#[i.split('_')[-1] for i in file_list_no_char]

    #   do the same for the list with no_char_time dictionaries
    for file in file_name_list_no_char:
        #   create the conc.npy filename and check if it exists
        dict_dir = os.path.join(in_dir, file)
        dict_path = os.path.join(dict_dir, '_cbc.npy')
        if os.path.exists(dict_path):
            print('dict_dir :       ' + dict_path)
            #   load the dictionary and individually read the data inside key by key
            cbc_dict = np.load(dict_path, allow_pickle = True)[()]
            #   read each key, change the value of the key according to the time stamp (real time since simulation start)
            for key in cbc_dict:
                real_time = simu_time + key
                final_dict[real_time] = {'q_ghb': cbc_dict[key]['q_ghb'],\
                                         'q_drn': cbc_dict[key]['q_drn'],\
                                         'q_rch': cbc_dict[key]['q_rch']}
        simu_time += key

    #fin_dict_dir = r'g:\\Water_Nexus\\_A2\\_models_testing_1413\\cartesius_runs\\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1\\eq_31_char_time\\_conc_cmp.npy'
    #fin_dict_tar_dir = r'g:\\Water_Nexus\\_A2\\_models_testing_1413\\cartesius_runs\\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1\\eq_31_char_time\\_conc_cmp.tar.xz'
    fin_dict_dir = os.path.join(summary_dir, out_name + '.npy')
    final_dict_ordered = collections.OrderedDict(sorted(final_dict.items()))
    np.save(fin_dict_dir, final_dict_ordered)

"""  Same kind of function, but this time for the GHB check dictionary   """
def create_ghb_check_tar(in_dir, summary_dir, char_dir_ghb_check, out_name):

    #   initialize the simulation time
    simu_time = 0
    final_dict = dict()

    #   create lists of folders where the _conc dictionaries should be found
    file_list = os.listdir(in_dir)
    file_list_no_char = [i for i in file_list if '_to_' in i]
    file_name_list_no_char = file_list_no_char#[i.split('_')[-1] for i in file_list_no_char]

    #   do the same for the list with no_char_time dictionaries
    for file in file_name_list_no_char:
        #   create the conc.npy filename and check if it exists
        dict_dir = os.path.join(in_dir, file)
        dict_path = os.path.join(dict_dir, '_ghb_check.npy')
        if os.path.exists(dict_path):
            print('dict_dir :       ' + dict_path)
            #   load the dictionary and individually read the data inside key by key
            ghb_check_dict = np.load(dict_path, allow_pickle = True)[()]
            #   read each key, change the value of the key according to the time stamp (real time since simulation start)
            for key in ghb_check_dict:
                real_time = simu_time + key
                final_dict[real_time] = {'ghb_check': ghb_check_dict[key]['ghb_check'],\
                                         'ghb_head_diff_lst': ghb_check_dict[key]['ghb_head_diff_lst'],\
                                         'ghb_head_diff_max': ghb_check_dict[key]['ghb_head_diff_max'],\
                                         'succ_cnt': ghb_check_dict[key]['succ_cnt'],\
                                         'fail_cnt': ghb_check_dict[key]['fail_cnt']}
        simu_time += key

    #fin_dict_dir = r'g:\\Water_Nexus\\_A2\\_models_testing_1413\\cartesius_runs\\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1\\eq_31_char_time\\_conc_cmp.npy'
    #fin_dict_tar_dir = r'g:\\Water_Nexus\\_A2\\_models_testing_1413\\cartesius_runs\\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1\\eq_31_char_time\\_conc_cmp.tar.xz'
    fin_dict_dir = os.path.join(summary_dir, out_name + '.npy')
    final_dict_ordered = collections.OrderedDict(sorted(final_dict.items()))
    np.save(fin_dict_dir, final_dict_ordered)

"""  Same kind of function, but this time for the List dictionary

in_dir = walk_dir
summary_dir = list_dict_dir
char_dir_list = list_dict_dir_ct
out_name = subdir + '_list_dict'

"""
def create_list_tar(in_dir, summary_dir, char_dir_list, out_name):

    #   initialize the simulation time
    simu_time = 0
    final_dict = dict()

    #   create lists of folders where the _conc dictionaries should be found
    file_list = os.listdir(in_dir)
    file_list_no_char = [i for i in file_list if '_to_' in i]
    file_name_list_no_char = file_list_no_char#[i.split('_')[-1] for i in file_list_no_char]

    #   do the same for the list with no_char_time dictionaries
    for file in file_name_list_no_char:
        #   create the conc.npy filename and check if it exists
        dict_dir = os.path.join(in_dir, file)
        dict_path = os.path.join(dict_dir, '_list.npy')
        if os.path.exists(dict_path):
            print('dict_dir :       ' + dict_path)
            #   load the dictionary and individually read the data inside key by key
            list_dict = np.load(dict_path, allow_pickle = True)[()]
            #   read each key, change the value of the key according to the time stamp (real time since simulation start)
            for key in list_dict:
                real_time = simu_time + key
                final_dict[real_time] = {'STORAGE_IN': np.round(list_dict[key]['STORAGE_IN'], 4),\
                                         'CONSTANT_HEAD_IN': np.round(list_dict[key]['CONSTANT_HEAD_IN'], 4),\
                                         'DRAINS_IN': np.round(list_dict[key]['DRAINS_IN'], 4),\
                                         'HEAD_DEP_BOUNDS_IN': np.round(list_dict[key]['HEAD_DEP_BOUNDS_IN'], 4),\
                                         'DCDT_IN': np.round(list_dict[key]['DCDT_IN'], 4),\
                                         'TOTAL_IN': np.round(list_dict[key]['TOTAL_IN'], 4),\
                                         'STORAGE_OUT': np.round(list_dict[key]['STORAGE_OUT'], 4),\
                                         'CONSTANT_HEAD_OUT': np.round(list_dict[key]['CONSTANT_HEAD_OUT'], 4),\
                                         'HEAD_DEP_BOUNDS_OUT': np.round(list_dict[key]['HEAD_DEP_BOUNDS_OUT'], 4),\
                                         'RECHARGE_OUT': np.round(list_dict[key]['RECHARGE_OUT'], 4),\
                                         'DCDT_OUT': np.round(list_dict[key]['DCDT_OUT'], 4),\
                                         'TOTAL_OUT': np.round(list_dict[key]['TOTAL_OUT'], 4),\
                                         'IN-OUT': np.round(list_dict[key]['IN-OUT'], 4),\
                                         'PERCENT_DISCREPANCY': np.round(list_dict[key]['PERCENT_DISCREPANCY'], 4)}
        simu_time += key

    #fin_dict_dir = r'g:\\Water_Nexus\\_A2\\_models_testing_1413\\cartesius_runs\\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1\\eq_31_char_time\\_conc_cmp.npy'
    #fin_dict_tar_dir = r'g:\\Water_Nexus\\_A2\\_models_testing_1413\\cartesius_runs\\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1\\eq_31_char_time\\_conc_cmp.tar.xz'
    fin_dict_dir = os.path.join(summary_dir, out_name + '.npy')
    final_dict_ordered = collections.OrderedDict(sorted(final_dict.items()))
    np.save(fin_dict_dir, final_dict_ordered)

"""
function that combines all the csv results into one final csv ouptut file

dir_in = walk_dir
dir_summary = csv_dir
id_sc = sc_id
folder_name_lst = eq_lst
"""
def create_summary_csv_srm(dir_in, dir_summary, folder_name_lst, id_sc):

    #   initialize the simulation time
    simu_time = 0

    #   add 0s to the scenario id to get a good naming structutre
    if id_sc < 10:
        id_sc_str = '00' + str(id_sc)
    elif id_sc < 100 and id_sc >= 10:
        id_sc_str = '0' + str(id_sc)
    else:
        id_sc_str = str(id_sc)

    #   create the output CSV file, the headers will match the headers of the usual individual csv file
    csv_dir_ts = os.path.join(dir_summary, 'sc_' + id_sc_str + '_summary_EQs_output.csv')
    f = open(csv_dir_ts,'w')
    f_headers = 'EQ, time_start, time_end, max_diff_head, min_diff_head, max_diff_conc, min_diff_conc, fresh_cell_diff_(end_start), brackish_cell_diff_(end_start),\
                saline_cell_diff_(end_start), frsh_inl_vol, frsh_inl_pct, frsh_shelf_vol, frsh_shelf_pct, prev_tot_cells, tot_cells, ghb_cells_check_fail, ghb_cells_check_succ,\
                ghb_cell_dif_abs_max, rch_in, ghb_in, tot_in, drn_out, ghb_out, tot_out, run_time (s)'
    f.write(" ".join(f_headers.split()))
    f.write('\n')
    f.close()

    #   do the same for the list with no_char_time dictionaries
    for file in folder_name_lst:
        #   create the conc.npy filename and check if it exists
        dict_dir = os.path.join(dir_in, file)
        dict_path = os.path.join(dict_dir, '_time_steps_DH_DC.csv')

        if os.path.exists(dict_path):
            #   open the csv file
            with open(dict_path, 'r') as f_tmp:
                #   copy line by line, but adjust some of the values - EQ number and the total simulation time
                for cnt, line in enumerate(f_tmp):
                    #   don't copy the header
                    if cnt != 0:
                        #   adjust the first three values in the line
                        end_line = line.split(',')[3:]
                        start_line = str(file) + ',' + str(int(float(line.split(',')[1])) + simu_time) + ',' + str(int(float(line.split(',')[2])) + simu_time)
                        new_line = start_line
                        for i in range(len(end_line)):
                            new_line += ',' + end_line[i]
                        #   write the line into the overall file
                        f = open(csv_dir_ts,'a')
                        #f.write("\n")
                        f.write(new_line)
                f.write("\n")
                f.close()
            simu_time = int(new_line.split(',')[2])

    """
    #   also find the other summary file, which is only with the % of concentrations and just copy it to csv_results
    for dirpath, dirnames, filenames in os.walk(dir_in):
        for filename in [f for f in filenames if "res_coscat_summary" in f]:
            new_filename = 'scenario_' + id_sc_str + '_pct_fresh_summary.csv'
            csv_dir_old = os.path.join(dirpath, filename)
            csv_dir_new = os.path.join(dir_summary, new_filename)
            #   copy the file
            shutil.copy(csv_dir_old, csv_dir_new)
    """
    return csv_dir_ts

def create_summary_csv(dir_in, dir_summary, dir_summary_char_times, id_sc):

    #   initialize the simulation time
    simu_time = 0

    #   add 0s to the scenario id to get a good naming structutre
    if id_sc < 10:
        id_sc_str = '00' + str(id_sc)
    elif id_sc < 100 and id_sc >= 10:
        id_sc_str = '0' + str(id_sc)
    else:
        id_sc_str = str(id_sc)

    #   create the output CSV file, the headers will match the headers of the usual individual csv file
    csv_dir_ts = os.path.join(dir_summary, 'sc_' + id_sc_str + '_summary_EQs_output.csv')
    f = open(csv_dir_ts,'w')
    f_headers = 'EQ, time_start, time_end, max_diff_head, min_diff_head, max_diff_conc, min_diff_conc, fresh_cell_diff_(end_start), brackish_cell_diff_(end_start),\
                saline_cell_diff_(end_start), frsh_inl_vol, frsh_inl_pct, frsh_shelf_vol, frsh_shelf_pct, prev_tot_cells, tot_cells, ghb_cells_check_fail, ghb_cells_check_succ,\
                ghb_cell_dif_abs_max, rch_in, ghb_in, tot_in, drn_out, ghb_out, tot_out, run_time (s)'
    f.write(" ".join(f_headers.split()))
    f.write('\n')
    f.close()

    #   create lists of folders where the _conc dictionaries should be found
    file_list = os.listdir(dir_in)
    file_list_no_char = [i for i in file_list if 'eq' in i and 'time' not in i]
    file_name_list_no_char = [i.split('_')[-1] for i in file_list_no_char]
    file_name_list_no_char = sorted(file_name_list_no_char)
    #   make a special list for the char times results
    file_list_char = [i for i in file_list if 'eq' in i and 'time' in i]
    file_name_list_char = [i.split('_')[1].split('_')[0] for i in file_list_char]
    file_name_list_char = sorted(file_name_list_char)

    #   loop through the char time list first
    for file in file_name_list_char:
        #   create the conc.npy filename and check if it exists
        dict_dir = os.path.join(dir_in, 'eq_' + file + '_char_time')
        dict_path = os.path.join(dict_dir, '_time_steps_DH_DC.csv')
        if os.path.exists(dict_path):
            dst_dir = os.path.join(dir_summary_char_times, 'scenario_' + id_sc_str + '_eq' + dict_path.split('eq')[-1].replace('/', ''))
            print('dict_dir :       ' + dict_path)
            print('dst_dir :       ' + dst_dir)
            shutil.copyfile(dict_path, dst_dir)

    #   do the same for the list with no_char_time dictionaries
    for file in file_name_list_no_char:
        #   create the conc.npy filename and check if it exists
        dict_dir = os.path.join(dir_in, 'eq_' + file)
        dict_path = os.path.join(dict_dir, '_time_steps_DH_DC.csv')
        if os.path.exists(dict_path):

            #   open the csv file
            with open(dict_path, 'r') as f_tmp:
                #   copy line by line, but adjust some of the values - EQ number and the total simulation time
                for cnt, line in enumerate(f_tmp):
                    #   don't copy the header
                    if cnt != 0:
                        #   adjust the first three values in the line
                        end_line = line.split(',')[3:]
                        start_line = str(file) + ',' + str(int(float(line.split(',')[1])) + simu_time) + ',' + str(int(float(line.split(',')[2])) + simu_time)
                        new_line = start_line
                        for i in range(len(end_line)):
                            new_line += ',' + end_line[i]
                        if int(float(line.split(',')[1])) + simu_time == 0:
                            print(line)
                            print(new_line)

                        #   write the line into the overall file
                        f = open(csv_dir_ts,'a')
                        #f.write("\n")
                        f.write(new_line)
                f.write("\n")
                f.close()

        simu_time = int(new_line.split(',')[2])
    """
    #   also find the other summary file, which is only with the % of concentrations and just copy it to csv_results
    for dirpath, dirnames, filenames in os.walk(dir_in):
        for filename in [f for f in filenames if "res_coscat_summary" in f]:
            new_filename = 'scenario_' + id_sc_str + '_pct_fresh_summary.csv'
            csv_dir_old = os.path.join(dirpath, filename)
            csv_dir_new = os.path.join(dir_summary, new_filename)
            #   copy the file
            shutil.copy(csv_dir_old, csv_dir_new)
    """
    return csv_dir_ts

"""   Function that will tar a source folder to a destination

src_dir = r'g:\Water_Nexus\_A2\_models_testing_1413\cartesius_runs\_summary'
dst_dir = r'g:\Water_Nexus\_A2\_models_testing_1413\cartesius_runs\_summ_test.tar.xz'
"""
def tar_dir(src_dir, dst_dir):

    tar = tarfile.open(dst_dir, "w:xz")
    tar.add(src_dir)
    tar.close()

"""
Function to rename and gather all the figures created during the model simulation into one folder

main_dir = r'g:\Water_Nexus\_A2\_models_testing_1413\cartesius_runs\coscat_1413_geo_scenarios_GHB_incr_min_100_cond_plots_1'
fig_type_dir = '_ghb_rch_params_pngs'
splitting_str = '_ghb_rch_params_'
dst_dir = r'g:\Water_Nexus\_A2\_models_testing_1413\cartesius_runs\_summary\_figures'
char_time_dir = r'g:\Water_Nexus\_A2\_models_testing_1413\cartesius_runs\_summary\_char_time\_figures'

"""
def gather_figs(main_dir, fig_type_dir, splitting_str, char_time_dir, dst_dir):

    #   first loop through the model folder and find all the plots () and initialize the simulation time
    simu_time = 0
    dst_char_folder = os.path.join(char_time_dir, fig_type_dir)
    dst_folder = os.path.join(dst_dir, fig_type_dir)
    if os.path.exists(dst_char_folder):
        pass
    else:
        os.makedirs(dst_char_folder)

    if os.path.exists(dst_folder):
        pass
    else:
        os.makedirs(dst_folder)

    #   first make a list of all the dictionaries located with that folder structure
    for dirpath, dirnames, filenames in os.walk(main_dir):
        #   if the dirpath contains the fig_type_dir then enter that folder
        if fig_type_dir in dirpath:

            time_end_lst = []

            for filename in os.walk(dirpath):
                for i in range(len(filename[-1])):
                    if filename[-1][i].endswith(".png"):

                        #   if there is the string "diff" in the filename there are two different time stamps, if not theres only one
                        if 'diff' in filename[-1][i]:
                            #   get the old time stamps
                            str_split = filename[-1][i].split('diff_')[-1].split('_to_')
                            t_start_old = int(str_split[0])
                            t_end_old = int(str_split[-1].split('_yrs')[0])
                            #   create new ones, also add 0s to the string
                            t_start_new = t_start_old + simu_time
                            t_end_new = t_end_old + simu_time
                            time_end_lst.append(t_end_old)

                            if t_start_new < 1000:
                                t_start_str = '000' + str(t_start_new)
                            elif t_start_new >= 1000 and t_start_new < 10000:
                                t_start_str = '00' + str(t_start_new)
                            elif t_start_new >= 10000 and t_start_new < 100000:
                                t_start_str = '0' + str(t_start_new)
                            else:
                                t_start_str = str(t_start_new)

                            if t_end_new < 1000:
                                t_end_str = '000' + str(t_end_new)
                            elif t_end_new >= 1000 and t_end_new < 10000:
                                t_end_str = '00' + str(t_end_new)
                            elif t_end_new >= 10000 and t_end_new < 100000:
                                t_end_str = '0' + str(t_end_new)
                            else:
                                t_end_str = str(t_end_new)

                            #   if there is char_time in the name folder than move those to the correspondant folder
                            if 'char_time' in dirpath:
                                eq_num = int(dirpath.split('eq')[-1].split('char_time/')[0].replace('_', ''))
                                new_name = filename[-1][i].split(str(t_start_old))[0] + t_start_str + '_to_' + t_end_str + '_eq_' + str(eq_num) + '.png'
                                new_dir = os.path.join(dst_char_folder, new_name)
                                old_dir = os.path.join(dirpath, filename[-1][i])
                                #   copy the file
                                shutil.copy(old_dir, new_dir)
                            else:
                                eq_num = int(dirpath.split('eq')[-1].split('/')[0].replace('_', ''))
                                new_name = filename[-1][i].split(str(t_start_old))[0] + t_start_str + '_to_' + t_end_str + '_eq_' + str(eq_num) + '.png'
                                new_dir = os.path.join(dst_folder, new_name)
                                old_dir = os.path.join(dirpath, filename[-1][i])
                                #   copy the file
                                shutil.copy(old_dir, new_dir)

                        #   if there is the string "diff" in the filename there are two different time stamps, if not theres only one
                        else:
                            #   get the old time stamps
                            #splitting_str = fig_type_dir.split('pngs')[0].split('_')[1].replace('_', '')
                            str_split = filename[-1][i].split(splitting_str)[-1].split('_yrs')
                            t_old = int(str_split[0])
                            #   create new ones, also add 0s to the string
                            t_new = t_old + simu_time
                            time_end_lst.append(t_old)

                            if t_new < 1000:
                                t_str = '000' + str(t_new)
                            elif t_new >= 1000 and t_new < 10000:
                                t_str = '00' + str(t_new)
                            elif t_new >= 10000 and t_new < 100000:
                                t_str = '0' + str(t_new)
                            else:
                                t_str = str(t_new)

                            #   if there is char_time in the name folder than move those to the correspondant folder
                            if 'char_time' in dirpath:
                                eq_num = int(dirpath.split('eq')[-1].split('char_time/')[0].replace('_', ''))
                                new_name = filename[-1][i].split(str(t_old))[0] + t_str + '_eq_' + str(eq_num) + '.png'
                                new_dir = os.path.join(dst_char_folder, new_name)
                                old_dir = os.path.join(dirpath, filename[-1][i])
                                #   copy the file
                                print(old_dir, new_dir)
                                shutil.copy(old_dir, new_dir)
                            else:
                                eq_num = int(dirpath.split('eq')[-1].split('/')[0].replace('_', ''))
                                new_name = filename[-1][i].split(str(t_old))[0] + t_str + '_eq_' + str(eq_num) + '.png'
                                new_dir = os.path.join(dst_folder, new_name)
                                old_dir = os.path.join(dirpath, filename[-1][i])
                                #   copy the file
                                print(old_dir, new_dir)
                                shutil.copy(old_dir, new_dir)

            if 'char_time' not in dirpath:
                simu_time += max(time_end_lst)


# -*- coding: utf-8 -*-
# @Author  : Tian Hongrong
# @Time    : 2023/1/15 13:12
# @Function: input data pre-processing, binarize iris dataset

import numpy as np
from sklearn.datasets import load_iris

iris_data = load_iris()
input_data = iris_data.data
binary_data = input_data

"""
    use 2-bit representation to represent iris flower's 4 features, hence expand the original
    4 input to 8 input, then the input matrix is (data_num *  8) = (150 * 8)
"""

new_2bit_data = np.zeros(shape=(150 * 8))
SeLen = input_data[:, 0]
SeWidth = input_data[:, 1]
PeLen = input_data[:, 2]
PeWidth = input_data[:, 3]

def sort(feature):
    MAX = np.max(feature)
    MIN = np.min(feature)
    A = (MAX - MIN) / 4

    i = 0
    for i in range(150):
        if feature[i] < MIN + A and feature[i] >= MIN:
            feature[i] = 0
        elif feature[i] < MIN + 2 * A and feature[i] >= A + MIN:
            feature[i] = 1
        elif feature[i] < MIN + 3 * A and feature[i] >= 2 * A + MIN:
            feature[i] = 2
        elif feature[i] <= MAX and feature[i] >= 3 * A + MIN:
            feature[i] = 3
    return (feature)

SeLen_sort = sort(SeLen)
SeWidth_sort = sort(SeWidth)
PeLen_sort = sort(PeLen)
PeWidth_sort = sort(PeWidth)

def binaries(feature):
    b = np.zeros(shape=(150, 2))
    i = 0
    j = 0
    for i in range(150):
        for j in range(2):
            if feature[i] == 0:
                b[i][0] = -1
                b[i][1] = -1
            elif feature[i] == 1:
                b[i][0] = 1
                b[i][1] = -1
            elif feature[i] == 2:
                b[i][0] = -1
                b[i][1] = 1
            elif feature[i] == 3:
                b[i][0] = 1
                b[i][1] = 1
    return b

SeLen_binary = binaries(SeLen_sort)
SeWidth_binary = binaries(SeWidth_sort)
PeLen_binary = binaries(PeLen_sort)
PeWidth_binary = binaries(PeWidth_sort)

new_binary_data = np.c_[SeLen_binary, SeWidth_binary, PeLen_binary, PeWidth_binary]
np.save('binary_input_data.npy', new_binary_data)


from core.apps.campaign.models import KollabCampaign
from django import forms

class DateInput(forms.DateInput):
    input_type = "date"

class CampaignCreateForm(forms.ModelForm):
    class Meta:
        model = KollabCampaign
        exclude = [
            "business_id",
            "is_active",
            "created_at",
            "updated_at",
            "thumbnail_url",
        ]
        widgets = {
            "start_date": DateInput(),
            "end_date": DateInput(),
        }


# In this program we will use KNN to predict air quality index

# Part 1: Preprocessing

# Importing required packages
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Reading the data
df=pd.read_csv('Real_Combine.csv')
# Checking for null values
sns.heatmap(df.isnull(),yticklabels=False,cbar=False,cmap='viridis')
# Since there are very few null values, we can drop them
df = df.dropna()
# Defining dependent and independent features
X = df.iloc[:, :-1]
y = df.iloc[:, -1]

# Seeing the feature importance using ExtraTreesRegressor
from sklearn.ensemble import ExtraTreesRegressor
import matplotlib.pyplot as plt
model = ExtraTreesRegressor()
model.fit(X,y)

# Plotting the importance using ExtraTreesRegressor
feat_importances = pd.Series(model.feature_importances_, index=X.columns)
feat_importances.nlargest(5).plot(kind='barh')
plt.show()

# Splitting the data using train test split
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

# Part 2: Making K nearest neighbour regressor

# Importing the library
from sklearn.neighbors import KNeighborsRegressor

# Making the model with k value = 1
regressor=KNeighborsRegressor(n_neighbors=1)
# Fitting the data into the model
regressor.fit(X_train,y_train)

# Printing coeficient of determination of the training set
print("Coefficient of determination R^2 <-- on train set: {}".format(regressor.score(X_train, y_train)))
# Printing coeficient of determination of the testing set
print("Coefficient of determination R^2 <-- on train set: {}".format(regressor.score(X_test, y_test)))
# The value for training set is 1, for testing set is 0.54, the model is underfitting

# Printing cross validation score for regressor model with 5 fold cross validation
from sklearn.model_selection import cross_val_score
score=cross_val_score(regressor,X,y,cv=5)
score.mean()
# The mean cross validation score is 0.39

# Part 3: Prediction and evaluation

# Making the prediction
prediction=regressor.predict(X_test)

# Plotting the difference in the test value and the predicted value
sns.distplot(y_test-prediction)
# Very low kurtosis
# Plotting the predicted values against the test values
plt.scatter(y_test,prediction)
# More or less linear with some outliers

# Part 4: Hyper parameter tuning

# We start a loop to take n value from 1 to 40 and give the mean cross validation score with 10 folds
accuracy_rate = []
for i in range(1,40):
    knn = KNeighborsRegressor(n_neighbors=i)
    score=cross_val_score(knn,X,y,cv=10,scoring="neg_mean_squared_error")
    accuracy_rate.append(score.mean())

# Plotting the cross validation score against the n value to arruve at the best n value
plt.figure(figsize=(10,6))
plt.plot(range(1,40),accuracy_rate,color='blue', linestyle='dashed', marker='o',markerfacecolor='red', markersize=10)
plt.title('Accuracy Rate vs. K Value')
plt.xlabel('K')
# Accuracy rate is highest at n=1

# Part 6: Prediction and evalution using the tuned model

# Initiating the model with one neighbour
knn = KNeighborsRegressor(n_neighbors=1)
# Fitting the data onto the model
knn.fit(X_train,y_train)
# Making the predictions
predictions = knn.predict(X_test)

# Plotting the difference of the test value and the predicted values
sns.distplot(y_test-predictions)
# Extremely high kurtosis, this is good

# Plotting the predicted values against the test values
plt.scatter(y_test,predictions)
# Very linear with several outliers

# Printing the MAE, MSE and RMSE
from sklearn import metrics
print('MAE:', metrics.mean_absolute_error(y_test, prediction))
print('MSE:', metrics.mean_squared_error(y_test, prediction))
print('RMSE:', np.sqrt(metrics.mean_squared_error(y_test, prediction)))

# Part 6: Dumping the model in a pickle file for later deployment

# Importing pickkle
import pickle

# opening the file to dump the model
file = open('random_forest_regression_model', 'wb')
# dumping the tuned model into the file
pickle.dump(knn, file)


# -*- coding: utf-8 -*-
"""
Created on Wed May 26 02:18:17 2021

@author: Gaston
"""
from vigilante import vigilar
'''
Ejercicio 10.8
'''
def filematch(lines, substr):
        for line in lines:
            if substr in line:
                yield line

#%%

lines = vigilar('../Data/mercadolog.csv')
naranjas = filematch(lines, 'Naranja')
for line in naranjas:
    print(line)
#%%
'''Ejercicio 10.9'''

import csv
lineas = vigilar('../Data/mercadolog.csv')
filas = csv.reader(lineas)
for fila in filas:
    print(fila)


'''
check if the tree is BST.
This is the min max tracking approach.
'''

class Node:
  def __init__(self, data):
    self.data = data
    self.right = None
    self.left = None

def insert(node, data):
  if node == None:
    return Node(data)
  elif (data < node.data):
    node.left = insert(node.left, data)
  else:
    node.right = insert(node.right, data)

  return node

def inorder(node):
  if node == None:
    return

  if node.left != None:
    inorder(node.left)
  print(node.data, end=" ")
  if node.right != None:
    inorder(node.right)

def isBSTUtil(node, min_val, max_val):
  if node == None:
    return True
  else:
    return (node.data > min_val and node.data < max_val and (isBSTUtil(node.left, min_val, node.data) and isBSTUtil(node.right, node.data, max_val)))

def isBST(node):
  if node == None:
    return True
  else:
    min_val = -1
    max_val = 100
    return (node.data > min_val and node.data < max_val and (isBSTUtil(node.left, min_val, node.data) and isBSTUtil(node.right, node.data, max_val)))

# driver code
def main():
  root = None
  root = insert(root, 50)
  root = insert(root, 30)
  root = insert(root, 20)
  root = insert(root, 40)
  root = insert(root, 70)
  root = insert(root, 60)
  root = insert(root, 80)

  print ("Inorder traversal of the given tree")
  inorder(root)
  print()

  print("Is BST: ", isBST(root))

if __name__ == "__main__":
  main()


import uuid
from flask import Flask
from flask import jsonify
from flask_cors import CORS, cross_origin

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
cors = CORS(app)

@app.route("/")
def index():
    return "Hello, world!"

@app.route("/destinations")
@cross_origin()
def destinations():
    return jsonify([
        {
            "id": 1,
            "name": "example name1",
            "description": "example description",
            "bounds": {
                "north": 127.115048,
                "west": 37.508038,
                "south": 127.115248,
                "east": 37.508238
            }
        },

        {
            "id": 2,
            "name": "example name2",
            "description": "example description",
            "bounds": {
                "north": 127.115048,
                "west": 37.508038,
                "south": 127.115248,
                "east": 37.508238
            }
        }
    ])

@app.route("/destinations/<string:destination_id>")
@cross_origin()
def destination(destination_id):
    return jsonify(
        {
            "id": destination_id,
            "name": "example name",
            "description": "example description",
            "bounds": {
                "north": 127.115048,
                "west": 37.508038,
                "south": 127.115248,
                "east": 37.508238
            }
        }
    )

if __name__ == "__main__":
    app.run()


from middleware.current_user.data import set_current_user
from rest_framework.authentication import TokenAuthentication
from rest_framework import exceptions
from rest_framework import permissions
from datetime import datetime, timedelta
from django.conf import settings
from application_layer.gateway import utils
from data_layer.session_data_layer import get_current_user, get_current_user_scope
import re
from entities import models

class AppTokenAuthentication(TokenAuthentication):
    keyword = 'Bearer'

    def authenticate_credentials(self, key):

        user_session = models.UserSession.objects.filter(token=key).first()

        if not user_session:
            raise exceptions.AuthenticationFailed('Invalid token')

        if user_session.expires < datetime.now():
            raise exceptions.AuthenticationFailed('Token has expired')

        user_session.expires = datetime.now() + timedelta(hours=1)
        user_session.save()

        set_current_user(user_session.user)

        return (user_session.user,
                user_session)

class IsAuthenticated(permissions.BasePermission):

    def url_regex_exact_matched (self, regex, string):
        reg = '^' + regex + '$'
        return True if re.match(reg, string) != None else False

    def has_permission(self, request, view):

        if not request.user and not request.auth:
            return False

        user_context = None

        inputs = utils.get_request_values(request)

        rms_context_allowed_urls = set([
            '/api/v1/auth/login/',
            '/api/v1/auth/current-user/',
            '/api/v1/auth/current-user/scope/'])

        if inputs['client_path'] in rms_context_allowed_urls:
            return True

        user_context = get_current_user(request.user, request.auth)

        if not user_context:
            return False

        if user_context.is_superuser:
            return True

        user_context_scope = get_current_user_scope(request.user, request.auth)

        if not user_context_scope:
            return False

        if user_context_scope['is_admin']:
            return True

        permissions = user_context_scope['service_routes']
        client_path = inputs.get('client_path')
        client_method = inputs.get('client_method')

        return len(
            list(filter(lambda item: self.url_regex_exact_matched(item['url'], client_path)
                                 and item['method'] == client_method,
                        permissions))
        ) > 0

class AllowAny(permissions.BasePermission):

    def has_permission(self, request, view):
        return True


import flet as ft
from customcolorpicker import CustomColorPicker
from palettecolorpicker import PaletteColorPicker

def main(page: ft.Page):
    color_picker = CustomColorPicker(color="#c8df6f")

    d = ft.AlertDialog(content=color_picker)
    page.dialog = d

    def open_color_picker(e):
        d.open = True
        page.update()

    page.add(ft.IconButton(icon=ft.icons.BRUSH, on_click=open_color_picker))

ft.app(target=main)


# in case deps.txt is updated, run this file to update and upload the dependencies so that CI can use them.
# Before running the script, increase the version number found at:
# https://aiinfra.visualstudio.com/Lotus/_artifacts/feed/Lotus/UPack/onnxruntime_build_dependencies/versions
# Run without --do-upload once to verify downloading. Use --do-upload when you are ready to publish.
# python cmake/deps_update_and_upload.py --root-path C:/temp/onnxruntime_deps --version 1.0.82 --do-upload
# update version number in tools\ci_build\github\azure-pipelines\templates\download-deps.yml
import re
import subprocess
import os
import argparse
import tempfile

parser = argparse.ArgumentParser(description="Update dependencies and publish to Azure Artifacts")
parser.add_argument(
    "--root-path", type=str, default=tempfile.gettempdir(), help="Target root path for downloaded files"
)
parser.add_argument("--version", type=str, default="1.0.82", help="Package version to publish")
parser.add_argument("--do-upload", action="store_true", help="Upload the package to Azure Artifacts")
args = parser.parse_args()

with open("cmake/deps.txt") as file:
    text = file.read()

lines = [line for line in text.split("\n") if not line.startswith("#") and ";" in line]

root_path = args.root_path

for line in lines:
    url = re.sub("^[^;]+?;https://([^;]+?);.*", r"https://\1", line)
    filename = re.sub("^[^;]+?;https://([^;]+?);.*", r"\1", line)
    full_path = os.path.join(root_path, filename)
    subprocess.run(["curl", "-sSL", "--create-dirs", "-o", full_path, url])  # noqa: PLW1510

package_name = "onnxruntime_build_dependencies"
version = args.version

# Check if the user is logged in to Azure
result = subprocess.run("az account show", shell=True, capture_output=True, text=True)  # noqa: PLW1510
if "No subscriptions found" in result.stderr:
    # Prompt the user to log in to Azure
    print("You are not logged in to Azure. Please log in to continue.")
    subprocess.run("az login", shell=True)  # noqa: PLW1510

# Publish the package to Azure Artifacts if --no-upload is not specified

cmd = f'az artifacts universal publish --organization https://dev.azure.com/onnxruntime --feed onnxruntime --name {package_name} --version {version} --description "onnxruntime build time dependencies" --path {root_path}'
if args.do_upload:
    subprocess.run(cmd, shell=True)  # noqa: PLW1510
else:
    print("would have run: " + cmd)

cmd = f'az artifacts universal publish --organization https://dev.azure.com/aiinfra --feed Lotus --name {package_name} --version {version} --description "onnxruntime build time dependencies" --path {root_path}'
if args.do_upload:
    subprocess.run(cmd, shell=True)  # noqa: PLW1510
else:
    print("would have run: " + cmd)


#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Definition for a binary tree node.
class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Codec:
    """
    序列化是将一个数据结构或者对象转换为连续的比特位的操作，进而可以将转换后的数据存储在一个文件或者内存中，
    同时也可以通过网络传输到另一个计算机环境，采取相反方式重构得到原数据。

    请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑，
    你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
    """

    def serialize(self, root):
        """
        Encodes a tree to a single string. 前序遍历，用None顶替空节点
        :type root: TreeNode
        :rtype: str
        """
        if not root:
            return ""
        nodes = []
        stack = []
        node = root
        while len(stack) > 0 or node:
            if not node:
                node = stack.pop().right
            while node:
                nodes.append(str(node.val))
                stack.append(node)
                node = node.left
            nodes.append("None")

        return ",".join(nodes)

    def deserialize(self, data):
        """
        Decodes your encoded data to tree.
        :type data: str
        :rtype: TreeNode
        """
        if data == "":
            return None
        vals = data.split(",")

        def deserialize_internal(vals):
            val = vals.pop(0)
            if val == "None":
                return None
            node = TreeNode(int(val))
            node.left = deserialize_internal(vals)
            node.right = deserialize_internal(vals)
            return node

        return deserialize_internal(vals)

# Your Codec object will be instantiated and called as such:
# codec = Codec()
# codec.deserialize(codec.serialize(root))

297. 二叉树的序列化与反序列化.py

297. 二叉树的序列化与反序列化.py


import sys
from functools import reduce

def calc_trees(board, right, down):
    width = len(board[0])
    trees = 0
    col = right
    row = down

    while row < len(board):
        if board[row][col] == "#":
            trees += 1
        row += down
        col = (col + right) % width

    return trees

def main():
    board = []
    for line in sys.stdin:
        board.append(line.rstrip())

    slopes = [[1, 1], [3, 1], [5, 1], [7, 1], [1, 2]]

    slopes = list(map(lambda x: calc_trees(board, x[0], x[1]), slopes))
    total = reduce(lambda x, y: x * y, slopes)

    print(total)

if __name__ == "__main__":
    main()


import os
import json
from utils.logger import Logger
from journey.builder import build
from journey.controller.request.travel import service

logger = Logger('RECOMMENDED')
logger.get()
logger = logger._logger

filepath = os.path.join('./journey/controller/static', 'string_message.json')
LIST_OF_MESSAGE = []
with open(filepath) as message_file:
    LIST_OF_MESSAGE = json.load(message_file)

def choose_recommended(profile, messages, parameters):
    """user choose recommended, astral will provide data wisata place to user based on category"""
    lists = []
    user_id = profile.user_id
    display_name = profile.display_name

    logger.info("%s - %s choose %s" % (display_name, user_id, parameters['travel-tipe']))

    switcher = {
        'Adventure': show_recommended_adventure,
        'Sweet Escape': show_recommended_sweetescape,
        'Culinary': show_recommended_culinary
    }

    fx = switcher.get(parameters['travel-tipe'], "")(profile, messages, parameters)

    if fx is None:
        logger.error("%s - %s | Data : %s" % (display_name, user_id, fx))
        bubble_text = build.show_text(LIST_OF_MESSAGE['message_error_general'])
        lists.append(bubble_text)
    else:
        lists = fx

    return lists

def show_recommended_adventure(profile, messages, parameters):
    user_id = profile.user_id
    display_name = profile.display_name

    logger.info("%s - %s choose %s" % (display_name, user_id, parameters['tipe-adventure']))

    place_type = parameters['tipe-adventure'].lower()
    req_attr = ("", 'chat', place_type, "", "", "y", "", "", user_id)

    lists_data_carousel = service.get_adventure(req_attr)

    lists = build_message(user_id, display_name, messages,  lists_data_carousel)

    return lists

def build_message(user_id, display_name, messages,  lists_data_carousel):
    lists = []

    key = 'errorCode'
    if key in lists_data_carousel:
        logger.error("%s - %s | Data : %s" % (display_name, user_id, lists_data_carousel))
        bubble_text = build.show_text(LIST_OF_MESSAGE['message_error_datanotfound_recommended'])
        lists.append(bubble_text)
    else:
        attr_action = ('message', 'View Detail', 'place_name')
        attr_column = ('url_image', 'place_name', 'short_desc')
        lists_columns = build.populate_carousel_img(lists_data_carousel, attr_action, attr_column, None)

        alt_text = LIST_OF_MESSAGE['alt_recommended']
        bubble_carousel = build.show_carousel_with_img(alt_text, lists_columns)

        if len(messages) > 0:
            bubble_text = build.show_text(messages[0]['speech'])

        lists.append(bubble_text)
        lists.append(bubble_carousel)

    return lists

def show_recommended_sweetescape(profile, messages, parameters):
    user_id = profile.user_id
    display_name = profile.display_name

    logger.info("%s - %s choose %s" % (display_name, user_id, parameters['tipe-sweetescape']))
    pass

def show_recommended_culinary(profile, messages, parameters):
    user_id = profile.user_id
    display_name = profile.display_name

    logger.info("%s - %s choose %s" % (display_name, user_id, parameters['tipe-culinary']))
    pass


# from Grammar import Grammar

VARIABLE_INDICATOR = '0'

def view_grammar(grammar):
    for symbol in grammar.symbols:
        if not symbol.is_terminal() and symbol.productions:
            if symbol.is_terminal():
                print(symbol.symbol, '->', end=' ')
            else:
                print(symbol.symbol + VARIABLE_INDICATOR, '->', end=' ')

            for index, production in enumerate(symbol.productions):
                for production_symbol in production:
                    if production_symbol.is_terminal():
                        print(production_symbol.symbol, end=' ')
                    else:
                        print(production_symbol.symbol + VARIABLE_INDICATOR, end=' ')
                if index != len(symbol.productions) - 1:
                    print('|', end=' ')
            print()
    print()


from django.shortcuts import render, redirect
from django.http import HttpResponse
from .forms import EmployeeForm
from .models import Employee
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializers import EmployeeSerializer

def employee_list(request):
    context = {
        'employee_list': Employee.objects.all(),
    }
    return render(request, "employee_register/employee_list.html", context)

def employee_form(request, id=0):
    if request.method == "GET":
        if id == 0:
            form = EmployeeForm()
        else:
            employee = Employee.objects.get(pk=id)
            form = EmployeeForm(instance=employee)
        return render(request, "employee_register/employee_form.html", {'form': form})
    else:
        if id == 0:
            form = EmployeeForm(request.POST)
        else:
            employee = Employee.objects.get(pk=id)
            form = EmployeeForm(request.POST, instance=employee)
        if form.is_valid():
            form.save()
        return redirect('/employee/list')

def employee_delete(request, id):
    employee = Employee.objects.get(pk=id)
    employee.delete()
    return redirect('/employee/list')

class EmployeeAPI(APIView):

    def get(self, request):
        emp = Employee.objects.all()
        serializer = EmployeeSerializer(emp, many=True)
        return Response(serializer.data)

    def post(self, request):
        pass


from mpp.models import SQLTestCase
import os

'''
Test DML Queries for ORCA
'''
class test_dml(SQLTestCase):
    """
    @optimizer_mode on
    @tags ORCA
    @db_name dmldb
    """
    sql_dir = 'sql/'
    ans_dir = 'expected/'
    out_dir = 'output/'

    def get_substitutions(self):
        MYD = os.path.dirname(os.path.realpath(__file__))
        substitutions = { '%MYD%' : MYD }
        return substitutions

class test_dml_partition(SQLTestCase):
    """
    @optimizer_mode on
    @product_version gpdb: 4.3.99.99, gpdb: [4.3.4.0-]
    @tags ORCA MPP-21090
    @db_name dmldb
    """
    sql_dir = 'sql_partition/'
    ans_dir = 'expected_partition/'
    out_dir = 'output/'


import os
import torch
import torch.optim as optim
import torchvision.datasets as datasets
from src.models.GaussianVAE import GaussianMLP_VAE
from torchvision import transforms
import src.loss as losses

def train(cfg):
    loss_func = getattr(losses, cfg['loss'])

    root_dir = cfg['dataset']['path']
    download =  os.path.isdir(root_dir)  # check if data is already downloaded
    dataset = getattr(datasets, cfg['datasets']['name'])

    transform = transforms.ToTensor()
    train_dataset = dataset(root=root_dir, download=download, transforms=transform)
    train_loader = torch.util.data.DataLoader(train_dataset,
                                              batch_size=cfg['batch_size'],
                                              shuffle=True,
                                              num_workers=cfg['num_workers'])
    test_dataset = dataset(root_dir=root_dir, train=False, download=download, transforms=transform)
    test_loader = torch.util.data.DataLoader(test_dataset,
                                             batch_size=cfg['batch_size'],
                                             shuffle=True,
                                             num_workers=cfg['num_workers'])

    model = GaussianMLP_VAE(cfg)
    model = model.to(cfg['device'])

    optimizer = getattr(optim, cfg['optimizer']['type'])(model.parameters(), **cfg['optimizer']['args'])
    running_loss = 0.0
    for epoch in range(cfg['epochs']):
        for i, (inputs, labels) in enumerate(train_loader):
            inputs, labels = inputs.to(cfg['device']), labels.to(cfg['device'])

            optimizer.zero_grad()

            output, z_mu, z_logvar = model(inputs)

            loss = loss_func(inputs, output, z_mu, z_logvar)
            loss.backward()
            optimizer.step()

            running_loss += loss.item()

            if i % 50 == 49:
                print("[{}, {}] loss: {}".format(epoch + 1, i + 1, running_loss / 50))
                running_loss = 0.0

            #Need to save checkpoints here...

    print("Finished Training")


from __future__ import absolute_import, division, print_function

import getdns

from twisted.trial.unittest import SynchronousTestCase
from twisted.python.filepath import FilePath
from OpenSSL import crypto

from danex import _dane

class TLSADomainNameTests(SynchronousTestCase):
    def test_tlsaDomainName(self):
        """
        L{_dane.tlsaDomainName} returns the port, proto and parent domain as
        labels of a new domain name string.
        """
        self.assertEqual(
            "_443._tcp.example.com",
            _dane.tlsaDomainName('example.com', 443, 'tcp')
        )

class GetdnsResponseErrorTests(SynchronousTestCase):
    def test_errorText(self):
        """
        L{_dane.GetdnsResponseError} has an C{errorText} attribute which is the name
        of the corresponding L{getdns} constant.
        """
        self.assertEqual(
            "GETDNS_RESPSTATUS_NO_NAME",
            _dane.GetdnsResponseError(getdns.GETDNS_RESPSTATUS_NO_NAME).errorText
        )

class TLSARecordTests(SynchronousTestCase):
    def test_matchesCertificateCertTrue(self):
        """
        """
        serverCertBytes = FilePath(__file__).sibling('example_cert.bin').open().read()
        serverCert = crypto.load_certificate(crypto.FILETYPE_ASN1, serverCertBytes)
        self.assertEqual(
            True,
            _dane.TLSARecord(
                payload=serverCertBytes,
                usage=0,
                selector=_dane.SELECTOR.CERT.value,
                matchingType=_dane.MATCHING_TYPE.FULL.value
            ).matchesCertificate(serverCert)
        )

    def test_matchesCertificateCertFalse(self):
        """
        """
        serverCertBytesOriginal = FilePath(__file__).sibling('example_cert.bin').open().read()
        serverCert = crypto.load_certificate(crypto.FILETYPE_ASN1, serverCertBytesOriginal)
        originalSerial = serverCert.get_serial_number()
        serverCert.set_serial_number(100)
        self.assertNotEqual(originalSerial, serverCert.get_serial_number())
        serverCertBytesNew = crypto.dump_certificate(crypto.FILETYPE_ASN1, serverCert)
        self.assertNotEqual(serverCertBytesOriginal, serverCertBytesNew)
        self.assertEqual(
            False,
            _dane.TLSARecord(
                payload=serverCertBytesNew,
                usage=0,
                selector=_dane.SELECTOR.CERT.value,
                matchingType=_dane.MATCHING_TYPE.FULL.value
            ).matchesCertificate(serverCert)
        )
    test_matchesCertificateCertFalse.skip = True

    def test_matchesCertificateSPKITrue(self):
        """
        """
        serverCertBytesOriginal = FilePath(__file__).sibling('example_cert.bin').open().read()
        serverCert = crypto.load_certificate(crypto.FILETYPE_ASN1, serverCertBytesOriginal)
        serverCert.set_serial_number(100)
        serverCertBytes = crypto.dump_certificate(crypto.FILETYPE_ASN1, serverCert)
        self.assertEqual(serverCertBytesOriginal, serverCertBytes)
#        import pdb; pdb.set_trace()
        self.assertEqual(
            False,
            _dane.TLSARecord(
                payload=serverCertBytes + b'xxx',
                usage=0,
                selector=_dane.SELECTOR.SPKI.value,
                matchingType=_dane.MATCHING_TYPE.FULL.value
            ).matchesCertificate(serverCert)
        )
    test_matchesCertificateSPKITrue.skip = True

class FakeGetdns(object):
    """
    An in memory fake of the getdns api for testing.
    """
    def __init__(self, generalResult=None):
        self._generalResult = generalResult

        for k, v in getdns.__dict__.items():
            if k.startswith('GETDNS_'):
                setattr(self, k, v)

    def context_create(self):
        """
        """

    def general(self, context, name, request_type, extensions):
        """
        """
        return self._generalResult

class TLSATests(SynchronousTestCase):
    def test_tlsaCert(self):
        """
        L{_dane.lookup_tlsa_records} returns a L{_dane.TLSARecord} instance if
        the domain name exists and a verified record is found and the record
        selector type is CERT.
        """
        fakeGetdns = FakeGetdns(
            generalResult=createResults(status=getdns.GETDNS_RESPSTATUS_GOOD,
                                        selector=_dane.SELECTOR.CERT.value,
                                        certificate_association_data=b'FOOBAR'))
        _, (res,) = _dane.lookup_tlsa_records(
            'example.com', 443, 'tcp', getdns=fakeGetdns)
        self.assertEqual(
            (_dane.SELECTOR.CERT, b'FOOBAR'),
            (res.selector, res.payload)
        )

    def test_tlsaSPKI(self):
        """
        L{_dane.lookup_tlsa_records} returns a L{_dane.TLSARecord} instance if
        the domain name exists and a verfied record is found and the record
        selector type is SPKI.
        """
        fakeGetdns = FakeGetdns(
            generalResult=createResults(status=getdns.GETDNS_RESPSTATUS_GOOD,
                                        selector=_dane.SELECTOR.SPKI.value,
                                        certificate_association_data=b'FOOBAR'))
        _, (res,) = _dane.lookup_tlsa_records(
            'example.com', 443, 'tcp', getdns=fakeGetdns)
        self.assertEqual(
            (_dane.SELECTOR.SPKI, b'FOOBAR'),
            (res.selector, res.payload)
        )

    def test_tlsaNoname(self):
        """
        L{_dane.lookup_tlsa_records} raises LookupError if the domain name does
        not exist.
        """
        e = self.assertRaises(
            _dane.GetdnsResponseError,
            _dane.lookup_tlsa_records, 'example.com', 443, 'tcp',
            getdns=FakeGetdns(
                generalResult=createResults(
                    status=getdns.GETDNS_RESPSTATUS_NO_NAME
                )
            )
        )
        self.assertEqual(
            getdns.GETDNS_RESPSTATUS_NO_NAME,
            e.errorCode
        )

def createResults(status=getdns.GETDNS_RESPSTATUS_GOOD,
                  selector=None,
                  certificate_association_data=b"",):
    return {'answer_type': 800,
            'canonical_name': '_443._tcp.getdnsapi.org.',
            'just_address_answers': [],
            # 'replies_full': [<read-only buffer ptr 0x7fe2e0029e80, size 636 at 0x7fe2e4e58fb0>],
            'replies_tree': [{'answer': [{'class': 1,
                                          'name': '_443._tcp.getdnsapi.org.',
                                          'rdata': {
                                              'certificate_association_data': certificate_association_data,
                                              'certificate_usage': 3,
                                              'matching_type': 1,
                                              # 'rdata_raw': "",
                                              'selector': selector
                                          },
                                          # 'ttl': 450,
                                          'type': 52,
                                         # {'class': 1,
                                         #  'name': '_443._tcp.getdnsapi.org.',
                                         #  'rdata': {'algorithm': 7,
                                         #            'key_tag': 49262,
                                         #            'labels': 4,
                                         #            'original_ttl': 450,
                                         #            'rdata_raw': <read-only buffer ptr 0x7fe2e0261b70, size 161 at 0x7fe2e4e60130>,
                                         #            'signature': <read-only buffer ptr 0x7fe2e0254c40, size 128 at 0x7fe2e4e60170>,
                                         #            'signature_expiration': 1399325172,
                                         #            'signature_inception': 1398100703,
                                         #            'signers_name': 'getdnsapi.org.',
                                         #            'type_covered': 52},
                                         #  'ttl': 450,
                                         #  'type': 46
                                      }
                                     ],
                               'answer_type': 800,
                              # 'authority': [{'class': 1,
                              #                'name': 'getdnsapi.org.',
                              #                'rdata': {'nsdname': 'ns.secret-wg.org.',
                              #                          'rdata_raw': 'ns.secret-wg.org.'},
                              #                'ttl': 450,
                              #                'type': 2},
                              #               {'class': 1,
                              #                'name': 'getdnsapi.org.',
                              #                'rdata': {'nsdname': 'mcvax.nlnetlabs.nl.',
                              #                          'rdata_raw': 'mcvax.nlnetlabs.nl.'},
                              #                'ttl': 450,
                              #                'type': 2},
                              #               {'class': 1,
                              #                'name': 'getdnsapi.org.',
                              #                'rdata': {'nsdname': 'open.nlnetlabs.nl.',
                              #                          'rdata_raw': 'open.nlnetlabs.nl.'},
                              #                'ttl': 450,
                              #                'type': 2},
                              #               {'class': 1,
                              #                'name': 'getdnsapi.org.',
                              #                'rdata': {'algorithm': 7,
                              #                          'key_tag': 49262,
                              #                          'labels': 2,
                              #                          'original_ttl': 450,
                              #                          'rdata_raw': <read-only buffer ptr 0x7fe2e0261f90, size 161 at 0x7fe2e4e601f0>,
                              #                          'signature': <read-only buffer ptr 0x7fe2e0028120, size 128 at 0x7fe2e4e60230>,
                              #                          'signature_expiration': 1399278072,
                              #                          'signature_inception': 1398093503,
                              #                          'signers_name': 'getdnsapi.org.',
                              #                          'type_covered': 2},
                              #                'ttl': 450,
                              #                'type': 46}],
                              'canonical_name': '_443._tcp.getdnsapi.org.',
                              'dnssec_status': 400,
                              'header': {'aa': 0,
                                         'ad': 1,
                                         'ancount': 2,
                                         'arcount': 0,
                                         'cd': 0,
                                         'id': 0,
                                         'nscount': 4,
                                         'opcode': 0,
                                         'qdcount': 1,
                                         'qr': 1,
                                         'ra': 1,
                                         'rcode': 0,
                                         'rd': 1,
                                         'tc': 0,
                                         'z': 0},
                              'question': {'qclass': 1,
                                           'qname': '_443._tcp.getdnsapi.org.',
                                           'qtype': 52}}],
            'status': status}


from data.indicators.active_list import PreviousActiveList
from data.indicators.arv_restarted import ArvRestartedDuringPeriod
from data.indicators.arv_started_patients import ArvStartedDuringPeriod
from data.indicators.incoming_transfer_patients import ArvIncomingTransferPatientsDuringPeriod
from data.indicators.patient_indicator import PatientIndicator

from data.indicators.lost_back_patients import ArvLostBackPatients

class ReceivedArvDuringPeriod(PatientIndicator):

    def under_arv(self):
        return False

    @classmethod
    def get_key(cls):
        return "ARV_RECEIVED"

    @classmethod
    def get_display_label(cls):
        return "Ayant bénéficié du TARV"

    def __init__(self, fuchia_database):
        super(ReceivedArvDuringPeriod, self).__init__(fuchia_database)
        self.a = PreviousActiveList(self.fuchia_database)
        self.b = ArvStartedDuringPeriod(self.fuchia_database)
        self.c = ArvIncomingTransferPatientsDuringPeriod(self.fuchia_database)
        self.d = ArvLostBackPatients(self.fuchia_database)
        self.e = ArvRestartedDuringPeriod(self.fuchia_database)

    def filter_patients_dataframe(self, limit_date, start_date=None,
                                  include_null_dates=False):
        patients = self.filter_patients_by_category(
            limit_date,
            start_date=None,
            include_null_dates=include_null_dates
        )
        a = self.a.get_filtered_patients_dataframe(
            limit_date,
            start_date=start_date,
            include_null_dates=include_null_dates
        ).index
        b = self.b.get_filtered_patients_dataframe(
            limit_date,
            start_date=start_date,
            include_null_dates=include_null_dates
        ).index
        c = self.c.get_filtered_patients_dataframe(
            limit_date,
            start_date=start_date,
            include_null_dates=include_null_dates
        ).index
        d = self.d.get_filtered_patients_dataframe(
            limit_date,
            start_date=start_date,
            include_null_dates=include_null_dates
        ).index
        e = self.e.get_filtered_patients_dataframe(
            limit_date,
            start_date=start_date,
            include_null_dates=include_null_dates
        ).index
        idx = a.union(b).union(c).union(d).union(e)
        return patients.loc[idx], None

    def get_value(self, limit_date, start_date=None, gender=None,
                  age_min=None, age_max=None, age_is_null=False,
                  include_null_dates=False, post_filter_index=None):
        return (self.a + self.b + self.c + self.d + self.e).get_value(
            limit_date,
            start_date=start_date,
            gender=gender,
            age_min=age_min,
            age_max=age_max,
            age_is_null=age_is_null,
            include_null_dates=include_null_dates,
            post_filter_index=post_filter_index
        )


import builtins

def create(size, first = 0, step = 0) -> list:
    arr = []
    arr.append(first)
    for i in range(1, size):
        arr.append(arr[i-1] + step)

    return arr

def sort(arr) -> list:
    for i in range(1, len(arr)):
        temp = arr[i]
        j = i-1
        while j >=0 and temp < arr[j]:
                arr[j+1] = arr[j]
                j -= 1
        arr[j+1] = temp

    return arr

def print(arr):
    builtins.print("[", arr[0], sep="", end="")
    for i in range(1, len(arr)):
        builtins.print(", ", arr[i], sep="", end="")
    builtins.print("]\n")
    return arr

size, first, step = map(int,input().split(' '))
arr = create(size, first, step)
sort(arr)
print(arr)


import numpy as np
from sklearn.datasets import load_breast_cancer
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, BatchNormalization
from tensorflow.keras.optimizers import RMSprop
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, MinMaxScaler,MaxAbsScaler, RobustScaler
from sklearn.metrics import r2_score
#1. 데이터
# 데이터 로드 및 전처리
datasets = load_breast_cancer()
print(datasets)

#print(datasets)
print(datasets.DESCR) #판다스 : .describe()
print(datasets.feature_names)   #판다스 :  .columns()

x = datasets ['data']
y = datasets.target

scaler = MinMaxScaler()
scaler.fit(x)
x = scaler.transform(x)

print(x.shape, y.shape) #(569, 30) (569,) feature,열,columns 는 30
#print(y) #1010101 은 암에 걸린 사람과 아님

x_train, x_test, y_train, y_test = train_test_split(
    x, y, shuffle=True, random_state=333, test_size=0.2
)

scaler = RobustScaler()
scaler.fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

#. 모델
model = Sequential()
model.add(Dense(64, input_dim=30))
model.add(Dense(32))
model.add(Dense(32))
model.add(Dense(32))
model.add(Dense(1))

#3. 컴파일 훈련
# model.compile(loss='mse', optimizer='adam',metrics=['acc'])
from tensorflow.keras.optimizers import Adam
learnig_rate =0.1
optimizer = Adam(learning_rate=learnig_rate)
model.compile(loss='mse', optimizer=optimizer,metrics=['mae'])

model.fit(x_train,y_train, epochs=10,batch_size=32)

from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
es = EarlyStopping(monitor= 'val_loss', patience=20, mode='min', verbose=1)
rlr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto', verbose=1, factor=0.5)
model.fit(x_train, y_train, epochs=200, batch_size=32, verbose=1, validation_split=0.2,
          callbacks=[es, rlr])

#4. 평가 예측
results = model.evaluate(x_test, y_test)

print("loss :", results)


chrysanthemum = int(input())
rose = int(input())
tulip = int(input())
season = str(input())
day = str(input())
final_price = 0
discount = False
if chrysanthemum + rose + tulip > 20:
    discount = True
if day == "Y":
    if season == "Spring" or season == "Summer":
        final_price = (rose * 4.10 + tulip * 2.50 + chrysanthemum * 2.00) * 1.15
    elif season == "Winter" or season == "Autumn":
        final_price = (rose * 4.50 + tulip * 4.15 + chrysanthemum * 3.75) * 1.15
elif day == "N":
    if season == "Spring" or season == "Summer":
        final_price = (rose * 4.10 + tulip * 2.50 + chrysanthemum * 2.00)
    elif season == "Winter" or season == "Autumn":
        final_price = (rose * 4.50 + tulip * 4.15 + chrysanthemum * 3.75)
if tulip > 7 and season == "Spring":
    final_price *= 0.95
if rose >= 10 and season == "Winter":
    final_price *= 0.90
if discount:
    final_price *= 0.80
final_price += 2
print(f"{final_price:.2f}")