from flask import Flask, render_template, request
import db
from models import Producto, User, Ventas, Cliente
from werkzeug.security import check_password_hash
import matplotlib.pyplot as plt
import pandas as pd
import sqlite3
import smtplib

app = Flask(__name__)  # En app se encuentra nuestro servidor web de Flask

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

@app.route('/cliente', methods=['GET'])
def cliente():
    todos_los_productos = db.session.query(Producto).all()
    return render_template("cliente.html", lista_de_productos=todos_los_productos)

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

@app.route('/comprador', methods=['POST'])
def crear():
    try:
        creado= Producto(nombreEmpresa=request.form['nombreEmpresa'],
                     telefono=request.form['telefono'],
                     direccion=request.form['direccion'],
                     cif=request.form['cif'],
                     email= request.form['email'],
                     precio=request.form['precio'],
                     porcentaje_descuento=request.form['descuento'],
                     color=request.form['color'],
                     descripcion=request.form['descripcion'],
                     marca=request.form['marca'],
                     cantidad=request.form['cantidad'],
                     referencia=request.form['referencia'])
        db.session.add(creado)
        db.session.commit()
        return render_template("registrado.html")
    except:
        return render_template("error_proveedor.html")

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

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

@app.route('/usuario', methods=['POST'])
def usuario():
    return render_template("password.html")

@app.route('/login', methods=['GET', 'POST'])
def login():
    user = db.session.query(User).filter_by(username=request.form['usuario']).first()
    if user and check_password_hash(user.password, request.form['contrasena']):
        todos_los_productos = db.session.query(Producto).all()
        return render_template("administrador.html", lista_de_adm=todos_los_productos)
    else:
        return render_template("Contraseña.html")

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

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

@app.route('/cantidad_sumar', methods=['GET', 'POST'])
def ana():
    cantidad_proveedor= request.form['cantidad_nueva']
    producto_ref = db.session.query(Producto).filter_by(referencia=request.form['referencia_2']).first()
    try:
        if producto_ref.referencia == request.form['referencia_2']:
            producto_ref.cantidad= Producto.cantidad + cantidad_proveedor
            db.session.commit()
            return render_template("producto_ana.html")
        else:
            return("La referencia es incorrecta")
    except:
        return render_template("referencia_incorrecta.html")

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

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

@app.route('/eliminar_producto', methods=['GET', 'POST'])
def eliminar_producto():
    producto_ref = db.session.query(Producto).filter_by(referencia=request.form['referencia_3']).first()
    try:
        if producto_ref.referencia == request.form['referencia_3']:
            db.session.query(Producto).filter_by(referencia=request.form['referencia_3']).delete()
            db.session.commit()
            return render_template("ele_producto.html")
        else:
            return ("La referencia o el cif son incorrectos")
    except:
        return render_template("ref_eliminar.html")

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

@app.route('/graf', methods=['GET', 'POST'])
def grafica():
    con = sqlite3.connect('database/ProyectoFinal.db')
    cursor = con.cursor()
    df = pd.read_sql_query("SELECT marca,cantidad FROM Producto", con)
    fd = pd.read_sql_query("SELECT referencia,ganancias FROM Ventas", con)
    da = pd.read_sql_query("SELECT venta,referencia FROM Ventas", con)
    cursor.close()
    con.close()
    plt.title("Productos disponibles en la web")
    plt.bar(df.marca, df.cantidad)
    plt.savefig("new_plot.png")
    plt.title("Ganancias")
    plt.bar(fd.referencia, fd.ganancias)
    plt.savefig("ganancia_plot.png")
    plt.title("Ventas de la web")
    plt.bar(da.referencia, da.venta)
    plt.savefig("grafica_ventas.png")
    return render_template("graficos.html", name = 'new_plot.png', name_1='ganancia_plot.png', name_2= 'grafica_ventas.png'  )

@app.route('/grafica', methods=['GET', 'POST'])
def grafico():
    return render_template("graficos.html", name='new_plot.png')

@app.route('/vendido', methods=['GET', 'POST'])
def vender():
    cantidad_venta = request.form['venta']
    pro_ref = db.session.query(Producto).filter_by(referencia=request.form['referencia_4']).first()
    if pro_ref.referencia == request.form['referencia_4'] and pro_ref.cantidad >= int(cantidad_venta):
        pro_ref.cantidad = Producto.cantidad - cantidad_venta
        db.session.commit()
    else:
        return render_template("agotado.html")

    if int(cantidad_venta) >= 0.1*(pro_ref.cantidad):
        message = 'Desde Armario Casual nos gustaria indicarle que el stock de su producto {} se encuentra por debajo del 90%'.format(pro_ref.referencia)
        subject= 'Stock Armario Casual'
        message= 'Subject: {}\n\n {}'.format(subject, message)

        server = smtplib.SMTP('smtp.gmail.com', 587)
        server.starttls()
        server.login('g32pobag@gmail.com', 'policianacional15')
        server.sendmail('g32pobag@gmail.com',pro_ref.email, message)
        server.quit()

    if pro_ref.cantidad >= int(cantidad_venta):
        precio_descuento= (pro_ref.precio-(pro_ref.precio * (pro_ref.porcentaje_descuento/100)))
        precio_final= precio_descuento * int(cantidad_venta)
        ganancias_empresa= precio_final*0.05
        venta= Ventas(venta= request.form['venta'],
                  referencia= request.form['referencia_4'],
                  precio= precio_final,
                  ganancias= ganancias_empresa)
        db.session.add(venta)
        db.session.commit()
        con = sqlite3.connect('database/ProyectoFinal.db')
        cursor = con.cursor()
        seleccion = pd.read_sql_query('SELECT precio FROM Ventas ORDER BY id DESC LIMIT 1', con)
        selec = pd.read_sql_query('SELECT venta FROM Ventas ORDER BY id DESC LIMIT 1', con)
        cursor.close()
        con.close()
        return render_template("precio.html", lista_de_ventas=seleccion.precio.values[0], list= selec.venta.values[0])
    else:
        return render_template("agotado.html")

@app.route('/clientecompra', methods=['GET', 'POST'])
def cliente_com():
        datos = Cliente(nombre=request.form['nombre'],
                    direccion=request.form['direccion'],
                    postal=request.form['postal'],
                    telefono=request.form['telefono'],
                    mail=request.form['mail'])
        db.session.add(datos)
        db.session.commit()
        return render_template("producto_comprado.html")

@app.route('/beneficio', methods=['GET', 'POST'])
def beneficio():
    todos_las_ventas = db.session.query(Ventas).all()
    return render_template("beneficio.html", lista_de_ventas=todos_las_ventas)

if __name__ == '__main__':
    db.Base.metadata.create_all(db.engine)
    app.run(debug=True)


import re
from collections import Counter
from nltk.util import ngrams
from nltk.tokenize import RegexpTokenizer
import emoji

data = {"img": "/assets/img/top5.png", "title": "Top 5's Analysis",
        "analysis": [
            {"title": "Most Popular Emoji's used", "data_usa": ":), :(", "data_ind":  ":), :("},
            {"title": "Most Popular Symbols used", "data_usa": "&, #", "data_ind": "&, #"},
            {"title": "Most Popular common Bi-gram", "data_usa": "super-test, Mario-yet", "data_ind": "super-test, Mario-yet"},
            {"title": "Most Popular common Tri-gram", "data_usa": "chat-gpt-ml", "data_ind": "chat-gpt-ml"},
        ]
}

def most_popular_bigram_trigram(df, col_name='title'):
    tokenizer = RegexpTokenizer(r"[\w']+")
    ng2 = [ngrams(tokenizer.tokenize(t.lower()), n=2) for t in df[col_name]]
    # flatenning the list
    ng2 = [x for y in ng2 for x in y]

    ngrams2 = Counter(ng2).most_common(25)

    tokenizer = RegexpTokenizer(r"[\w']+")
    ng3 = [ngrams(tokenizer.tokenize(t.lower()), n=3) for t in df['title']]
    # flatenning the list
    ng3 = [x for y in ng3 for x in y]

    ngrams3 = Counter(ng3).most_common(25)

    return ngrams2, ngrams3

def most_popular_symbols_emoji(df, col_name='title'):
    all_titles = ' '.join([x.lower() for x in df[col_name]])
    title_symbols = re.sub(r'\w', '', all_titles)
    title_symbols = re.sub(r'\s', '', title_symbols)
    title_symbols = list(title_symbols)
    common_symbol = Counter(title_symbols).most_common(10)

    title_emojis = [x for x in title_symbols if x in emoji.EMOJI_DATA]
    common_emoji = Counter(title_emojis).most_common(10)

    return common_emoji, common_symbol

def filter_top5(data):
    top5 = ""
    for datum in data[0:5]:
        txt = "-".join(datum[0])
        top5 = top5 + f"{txt}; "

    return top5[:-2]

def calc_top5s(df):
    bigram_x, trigram_x = most_popular_bigram_trigram(df)
    emoji_x, symbol_x = most_popular_symbols_emoji(df)

    emoji_x = filter_top5(emoji_x)
    symbol_x = filter_top5(symbol_x)
    bigram_x = filter_top5(bigram_x)
    trigram_x = filter_top5(trigram_x)

    x = [
        emoji_x,
        symbol_x,
        bigram_x,
        trigram_x
    ]

    return x

def update_top5_analysis(x, default_data, country="data_usa"):
    for num_, datum in enumerate(default_data["analysis"]):
        datum[country] = x[num_]

    return default_data

def get_top5_analysis(usa_df, ind_df, default_data=data):
    x = calc_top5s(usa_df)
    y = calc_top5s(ind_df)

    default_data_x = update_top5_analysis(x, default_data, country="data_usa")
    final_data = update_top5_analysis(y, default_data_x, country="data_ind")

    return final_data


from src.GameObject import GameObject
import colorama as clr
import sys

from src.TownHall import TownHall

def getWallIndex(x,y, walls):
    for wall in walls.wallsArray:
        if(wall.posX == x and wall.posY == y and wall.alive):
            return wall
    return None

def manhattanDistance(object1, object2):
    return abs(object1.posX - object2.posX) + abs(object1.posY - object2.posY)

class Archer(GameObject):
    def __init__(self, posX, posY, char, sizeX, sizeY, color, health):
        GameObject.__init__(self, posX, posY, char, sizeX, sizeY, color, health)
        self.vel = 1
        self.attackdamage = 1
        self.currentTarget = None
        self.attackWall = None
        self.attackTarget = False
        self.townHallPosition = None
        self.range = 8

    def moveAndAttack(self, walls, townHall, cannons, huts, screen, rageSpellActive, wizardTowers):
        # if attacking a wall then decrease wall's health
        if(self.attackWall != None):
            self.attackWall.health -= self.attackdamage
            if(self.attackWall.health <= self.attackWall.maxHealth*2/3):
                self.attackWall.color = clr.Fore.YELLOW
            if(self.attackWall.health <= self.attackWall.maxHealth/3):
                self.attackWall.color = clr.Fore.RED
            if(self.attackWall.health <= 0):
                self.attackWall.alive = False
                self.attackWall.color = clr.Fore.RESET
                # self.attackWall.char = ' '
                self.attackWall = None

        # if attacking target then decrease target's health
        elif(self.attackTarget):
            self.currentTarget.health -= self.attackdamage
            if(self.currentTarget.health <= self.currentTarget.maxHealth*2/3):
                self.currentTarget.color = clr.Fore.YELLOW
            if(self.currentTarget.health <= self.currentTarget.maxHealth/3):
                self.currentTarget.color = clr.Fore.RED
            if(self.currentTarget.health <= 0):
                self.currentTarget.alive = False
                self.currentTarget.color = clr.Fore.RESET
                self.currentTarget = None
                self.attackTarget = False

        # if not attacking then find nearest wall/hut/town hall according to manhattan distance or move towards target
        else:
            # if no target, then set current target to nearest wall/hut/town hall
            if(self.currentTarget == None or self.currentTarget.alive == False):
                # find nearest wall/hut/town hall according to manhattan distance
                minDistance = 99999
                for hut in huts.hutsArray:
                    if(hut.alive):
                        if(abs(self.posX - hut.posX) + abs(self.posY - hut.posY) < minDistance):
                            self.currentTarget = hut
                            minDistance = abs(self.posX - hut.posX) + abs(self.posY - hut.posY)

                for x in range(townHall.posX, townHall.posX + townHall.sizeX):
                    for y in range(townHall.posY, townHall.posY + townHall.sizeY):
                        if(townHall.alive):
                            if(abs(self.posX- x) + abs(self.posY - y) < minDistance):
                                self.currentTarget = townHall
                                self.townHallPosition = (x,y)
                                minDistance = abs(self.posX - x) + abs(self.posY - y)

                for cannon in cannons:
                    if(cannon.alive):
                        if(abs(self.posX - cannon.posX) + abs(self.posY - cannon.posY) < minDistance):
                            self.currentTarget = cannon
                            minDistance = abs(self.posX - cannon.posX) + abs(self.posY - cannon.posY)

                for wizardTower in wizardTowers:
                    if(wizardTower.alive):
                        if(abs(self.posX - wizardTower.posX) + abs(self.posY - wizardTower.posY) < minDistance):
                            self.currentTarget = wizardTower
                            minDistance = abs(self.posX - wizardTower.posX) + abs(self.posY - wizardTower.posY)
            # move towards target
            else:
                if(manhattanDistance(self, self.currentTarget) > self.range):
                    if(self.posX < self.currentTarget.posX):
                        for i in range(self.posX, self.currentTarget.posX):
                            if(getWallIndex(i, self.posY, walls) != None):
                                # self.posX = i - 1
                                self.attackWall = getWallIndex(i, self.posY, walls)
                                break
                        if(self.attackWall == None):
                            self.posX += self.vel
                    elif(self.posX > self.currentTarget.posX):
                        for i in range(self.posX, self.currentTarget.posX, -1):
                            if(getWallIndex(i, self.posY, walls) != None):
                                # self.posX = i + 1
                                self.attackWall = getWallIndex(i, self.posY, walls)
                                break
                        if(self.attackWall == None):
                            self.posX -= self.vel
                    elif(self.posY < self.currentTarget.posY):
                        for i in range(self.posY, self.currentTarget.posY-self.range):
                            if(getWallIndex(self.posX, i, walls) != None):
                                # self.posY = i - 1
                                self.attackWall = getWallIndex(self.posX, i, walls)
                                break
                        if(self.attackWall == None):
                            self.posY += self.vel
                    elif(self.posY > self.currentTarget.posY):
                        for i in range(self.posY-self.range, self.currentTarget.posY, -1):
                            if(getWallIndex(self.posX, i, walls) != None):
                                # self.posY = i + 1
                                self.attackWall = getWallIndex(self.posX, i, walls)
                                break
                        if(self.attackWall == None):
                            self.posY -= self.vel
                else:
                    self.attackTarget = True
            # else:
            #     self.currentTarget.health -= self.attackdamage
            #     if(self.currentTarget.health <= self.currentTarget.maxHealth*2/3):
            #         self.currentTarget.color = clr.Fore.YELLOW
            #     if(self.currentTarget.health <= self.currentTarget.maxHealth/3):
            #         self.currentTarget.color = clr.Fore.RED
            #     if(self.currentTarget.health <= 0):
            #         self.currentTarget.alive = False
            #         self.currentTarget.color = clr.Fore.RESET
            #         self.currentTarget = None


#Author : Aravind
#platform tested : Raspbian(linux based operating system)
#Python 3.2+
#Created on 08/01/2022
#MQTT protocol for less latency/power consuption

import paho.mqtt.client as paho
from time import sleep
import json
import RPi.GPIO as GPIO
import time

MOTOR_PIN = 17 #hardware pin
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED_PIN, GPIO.OUT)

def on_connect(client, userdata, flags, rc):                # func for making connection
	client.subscribe("coffee" , 0 )
	global connflag
	connflag = True

def on_message(client, userdata, msg):                      # Func for receiving msgs
	print(msg.topic)
	if msg.topic == "coffee":
		global topic
		rtopic=((msg.payload))
		payload = json.loads(rtopic)
		if payload["brew"] == "coffee":
			GPIO.output(MOTOR_PIN, GPIO.HIGH)
			time.sleep(7)                                   #exact time to fill a cup of coffee
			GPIO.output(MOTOR_PIN, GPIO.LOW)
			GPIO.cleanup()

mqttc = paho.Client()                                       # mqttc object
mqttc.on_connect = on_connect                               # assign on_connect func
mqttc.on_message = on_message                               # assign on_message func
#mqttc.on_log = on_log

#### Change following parameters ####
awshost = "localhost"     # Endpoint
awsport = 1883            # Port no.

mqttc.connect(awshost, awsport, keepalive=60)               # connect to aws server

mqttc.loop_forever()


from database_setup import User, Room, Move_In, \
    House_Attribute, Attribute, Base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from datetime import datetime
from app.util.aws.s3 import get_images, upload_file_wname
from app.assets.options import months, intervals, others, facilities, school_years, room_types, addresses_generate
from crud import add_user, \
    add_room, add_move_in, add_house_attribute, add_attribute
import os
import random

engine = create_engine('sqlite:///housing.db')
# Bind the engine to the metadata of the Base class so that the
# declaratives can be accessed through a DBSession instance
Base.metadata.bind = engine

DBSession = sessionmaker(bind=engine)
# A DBSession() instance establishes all conversations with the database
# and represents a "staging zone" for all the objects loaded into the
# database session object. Any change made against the objects in the
# session won't be persisted into the database until you call
# session.commit(). If you're not happy about the changes, you can
# revert all of them back to the last commit by calling
# session.rollback()
session = DBSession()

# define constants
CRIS = "cris"
AMIT = "amit"
ADAM = "adam"
KEENAN = "keenan"

descriptions = {
    CRIS: "I recently graduated with my bachelor's and will be working/volunteering fulltime. I do not smoke and I am clean (might misplace things though but)! I am also very sociable and enjoy cooking and baking ðŸ™‚ Hobbies I have are playing the violin, drawing, and watching kdramas! Feel free to message me for further questions ",
    AMIT: "We are pretty chill and very neat and respectful people ",
    ADAM: "Studying Data Science and Mathematics at the University of California, San Diego. Well-versed in Python (SKLearn, Pandas, Dask, etc..), R and Excel.Looking for an internship from June 2021 to September 2021 in the field of Data Science/Analytics where I can combine my mathematical/statistical knowledge and programming abilities with my strong writing and communication skills. ",
    KEENAN: "Software engineer with an attention to detail and strong people skills. Seeking full-time Software Engineering positions. "
}

# Add mock users
cris = add_user(CRIS, "haha@ucsd.edu", datetime.now(), "858-911",
                descriptions[CRIS], 'Third',
                "Data Science", session)
amit = add_user(AMIT, "amit@ucsd.edu", datetime.now(), "858-911989",
                descriptions[AMIT],  'Third',
                "Data Science", session)
adam = add_user(ADAM, "adam@ucsd.edu", datetime.now(), "858-65386",
                descriptions[ADAM], 'Third',
                "Computer Science and Engineering",
                session)
keenan = add_user(KEENAN, "keenan@ucsd.edu", datetime.now(), "858-4675432",
                  descriptions[KEENAN],  'Grad',
                  "Computer Science and Engineering",
                  session)
users = [adam, cris, amit, keenan]
file_dir = '../assets/room_mock_images/'
for user in users:
    # create icons
    icon_path = '../assets/profile_default_icons/'
    selected_icon = random.choice(
        os.listdir(icon_path))
    path_name = "/".join(["user"+str(user.id),
                          'profile', "headshot.jpg"])
    upload_file_wname(icon_path+selected_icon, 'houseit', path_name)

def generateMock(k=30):
    attributes = []
    for attr in others:
        attributes.append(add_attribute(attr, 'other', session))
    for attr in facilities:
        attributes.append(add_attribute(attr, 'facilities', session))
    move_combos = [(random.choice(intervals), months[6],
                    random.choice(intervals), months[7]) for _ in range(k)]
    move_ins = [add_move_in(elem[0], elem[1], elem[2],
                            elem[3], session) for elem in move_combos]
    mock_room_types = [random.choice(room_types) for _ in range(k)]
    mock_prices = [random.randint(200, 1000) for _ in range(k)]
    houses = [random.choice(addresses_generate) for _ in range(k)]
    people = [users[i % len(users)] for i in range(k)]
    negotiables = [random.choice([True, False]) for _ in range(k)]
    mock_stay_periods = [random.choice(list(range(1, 13))) for _ in range(k)]
    mock_eta = [str(random.choice(list(range(1, 30)))) +
                " mins" for _ in range(k)]
    mock_baths = [random.choice(list(range(1, 4))) for _ in range(k)]
    mock_beds = [random.choice(list(range(1, 4))) for _ in range(k)]
    mock_attrs = [list(set(random.sample(attributes, 8))) for _ in range(k)]
    mock_rooms = []
    print(mock_room_types)
    for i in range(k):
        temp_room = add_room(datetime.now(), mock_room_types[i], mock_prices[i], negotiables[i], "Damn it LOOOOOOL", mock_stay_periods[i],
                             mock_eta[i],
                             houses[i],
                             people[i], move_ins[i], mock_beds[i], mock_baths[i], session)
        for temp_attr in mock_attrs[i]:
            add_house_attribute(temp_room, temp_attr, session)
        mock_rooms.append(temp_room)
    for i in range(k):
        path_name = "/".join(["user"+str(people[i].id), 'housing',
                              str(mock_rooms[i].id)])
        random_files = random.sample(os.listdir(file_dir), 4)
        for idx, file_name in enumerate(random_files):
            upload_file_wname(file_dir+file_name, 'houseit',
                              path_name+"/"+str(idx)+".jpg")

generateMock()
print("created Mock Database!")


import pydot

# Create the graph
# include the "bgcolor" argument with a string value.
graph = pydot.Dot("my_graph", graph_type="graph", bgcolor="yellow")

# I have added a node so we can better see that our graph creation has worked. This is naturally a trivial
# graph as it has no edges, but as a minimum working example it suffices.

# Add the node - replace "Node Name" with your desired Node Title in string form
graph.add_node(pydot.Node("Node Name"))

# Save the output
graph.write_png("ChangeBackgroundColour.png")


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

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('wordapp', '0013_remove_translation_some_integer'),
    ]

    operations = [
        migrations.AddField(
            model_name='translation',
            name='some_text',
            field=models.CharField(default=b'something', max_length=200),
            preserve_default=True,
        ),
    ]


#!/usr/bin/env python3

"""A script for converting BAS excel spreadsheets to yaml.
"""

import os
import sys
import argparse
from xlrd import open_workbook, XL_CELL_NUMBER
import yaml
import unicodedata

def main(arguments):
    parser = argparse.ArgumentParser(description=__doc__,
            formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('indir', help="Directory with input files")
    parser.add_argument('-o', '--outdir', help="Output directory", default='')

    args = parser.parse_args(arguments)
    parse_file(os.path.join(args.indir, 'Kontoplan_K1_2016_ver1.xls'),
               os.path.join(args.outdir, 'Kontoplan_K1_2016_ver1.yml'),
               [1, 4])
    parse_file(os.path.join(args.indir, 'Kontoplan_Normal_2016_ver1.xls'),
               os.path.join(args.outdir, 'Kontoplan_Normal_2016_ver1.yml'),
               [2, 5])

def parse_file(infile_path, outfile_path, col_indices):
    outfile = open(outfile_path, 'w')
    wb = open_workbook(filename=infile_path)
    sheet = wb.sheet_by_index(0)
    accounts = []
    for row_index in range(0, sheet.nrows):
        for col_index in col_indices:
            if sheet.cell(row_index, col_index).ctype == XL_CELL_NUMBER:
                iden = sheet.cell(row_index, col_index).value
                desc = sheet.cell(row_index, col_index+1).value
                if iden >= 1000:
                    accounts.append(
                            {
                                'id': int(iden),
                                'description': unicodedata.normalize('NFC',desc.strip()),
                                'type':account_number_to_type(iden)
                            })

    outfile.write(yaml.safe_dump({'accounts': accounts}, default_flow_style=False, allow_unicode=True, explicit_start=True))

def account_number_to_type(number):
    if number < 2000:
        return 'asset'
    if number < 3000:
        return 'liability'
    if number < 4000:
        return 'revenue'
    return 'expense'
    #if number < 8000:
    #    return 'expense'
    #if number < 8000:
    #    return 'financial'
    #if number < 9000:
    #    return 'contra'

if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))


from basic_gui import *
from PyQt5.QtWidgets import (
    QRadioButton,
    QGroupBox,
    QCheckBox,
    QHBoxLayout,
    QTreeWidgetItemIterator,
)
from PyQt5.QtGui import QIcon
import wordsearch_generater

class Communication(Communication):
    super(Communication)
    # signal for puzzle settings
    puzzle_setting = pyqtSignal(list)
    # emits if entered words are korean
    korean = pyqtSignal(bool)
    # siganl to notify that making wordsearch puzzle is complete and to proceed the following
    puzzle_complete = pyqtSignal()
    recursionerrormsg = pyqtSignal()
    valueerrormsg = pyqtSignal()

class Settings(QWidget):
    def __init__(self, c):
        super().__init__()
        self.c = c
        self.puzzle_width = 15
        self.puzzle_height = 15
        self.shape = 0
        self.direction = 1
        self.diff_val = 1
        self.option = "겹치지 않도록"
        self.option_val = 0
        self.init_UI()

    def init_UI(self):
        title_label = QLabel("1. 퍼즐 옵션을 선택하세요.")

        # Group for size
        grp_size = QGroupBox("크기 조정")
        self.label_puzzle_width = QLabel("가로 길이: ")
        self.width_spin = QSpinBox()
        self.width_spin.setMinimum(5)
        self.width_spin.setToolTip("마우스 스크롤 가능합니다.")
        self.width_spin.setValue(15)

        self.label_puzzle_height = QLabel("세로 길이: ")
        self.height_spin = QSpinBox()
        self.height_spin.setMinimum(5)
        self.height_spin.setToolTip("마우스 스크롤 가능합니다.")
        self.height_spin.setValue(15)
        self.height_spin.valueChanged.connect(self.puzzle_height_change)

        # layout width
        hbox_width = QHBoxLayout()
        hbox_width_label = QHBoxLayout()
        hbox_width_label.setAlignment(Qt.AlignRight)
        hbox_width_label.addWidget(self.label_puzzle_width)
        hbox_width.addLayout(hbox_width_label)
        hbox_width_spin = QHBoxLayout()
        hbox_width_spin.setAlignment(Qt.AlignLeft)
        hbox_width_spin.addWidget(self.width_spin)
        hbox_width.addLayout(hbox_width_spin)
        self.width_spin.valueChanged.connect(self.puzzle_width_change)

        # layout height
        hbox_height = QHBoxLayout()
        hbox_height_label = QHBoxLayout()
        hbox_height_label.setAlignment(Qt.AlignRight)
        hbox_height_label.addWidget(self.label_puzzle_height)
        hbox_height_spin = QHBoxLayout()
        hbox_height_spin.setAlignment(Qt.AlignLeft)
        hbox_height_spin.addWidget(self.height_spin)
        hbox_height.addLayout(hbox_height_label)
        hbox_height.addLayout(hbox_height_spin)

        # layout for width, height
        vbox_size = QVBoxLayout()
        vbox_size.addLayout(hbox_width)
        vbox_size.addLayout(hbox_height)

        grp_size.setLayout(vbox_size)

        # Group for word shape
        grp_shape = QGroupBox("단어 모양")
        shape_1 = QRadioButton("가로세로")
        shape_1.setToolTip(
            "
단어를 가로세로로 설정합니다."
        )
        shape_1.setChecked(True)
        shape_2 = QRadioButton("가로세로 + 대각선")
        shape_2.setToolTip(
            "
단어를 가로세로, 대각선으로 설정합니다."
        )

        shape_1.clicked.connect(lambda: self.diff_checked(shape_1))
        shape_2.clicked.connect(lambda: self.diff_checked(shape_2))

        # layout shape
        grp_shape_layout = QVBoxLayout()
        grp_shape_layout.addWidget(shape_1)
        grp_shape_layout.addWidget(shape_2)

        grp_shape.setLayout(grp_shape_layout)

        # Group for word direction
        grp_direction = QGroupBox("단어 방향")
        direction_1 = QRadioButton("정방향")
        direction_1.setChecked(True)
        direction_1.setToolTip(
            "
글자 방향은 정방향으로 설정합니다."
        )
        direction_2 = QRadioButton("정방향 + 역방향")
        direction_2.setToolTip(
            "
글자 방향은 역방향으로 설정합니다."
        )
        direction_1.clicked.connect(lambda: self.diff_checked(direction_1))
        direction_2.clicked.connect(lambda: self.diff_checked(direction_2))

        # layout direction
        grp_direction_layout = QVBoxLayout()
        grp_direction_layout.addWidget(direction_1)
        grp_direction_layout.addWidget(direction_2)

        grp_direction.setLayout(grp_direction_layout)

        grp_option = QGroupBox("옵션")
        option_1 = QRadioButton("글자 겹치지 않게")
        option_1.setToolTip(
            "퍼즐이 쉬워집니다.
채워지는 글자는 되도록 겹치지 않도록 설정합니다."
        )
        option_1.setChecked(True)
        option_2 = QRadioButton("글자 무작위로")
        option_2.setToolTip(
            "퍼즐 난이도는 보통입니다.
채워지는 글자는 되도록 무작위로 설정합니다."
        )
        option_3 = QRadioButton("글자 겹치게")
        option_3.setToolTip(
            "
퍼즐이 어려워집니다.
채워지는 글자는 되도록 겹치도록 설정합니다."
        )
        option_1.clicked.connect(lambda: self.option_checked(option_1))
        option_2.clicked.connect(lambda: self.option_checked(option_2))
        option_3.clicked.connect(lambda: self.option_checked(option_3))
        # layout option
        grp_option_layout = QVBoxLayout()
        grp_option_layout.addWidget(option_1)
        grp_option_layout.addWidget(option_2)
        grp_option_layout.addWidget(option_3)

        grp_option.setLayout(grp_option_layout)

        # layout for diplay
        vbox_display = QVBoxLayout()

        hbox_setting = QHBoxLayout()
        hbox_setting.addWidget(grp_size)
        hbox_setting.addWidget(grp_shape)
        hbox_setting.addWidget(grp_direction)
        hbox_setting.addWidget(grp_option)

        vbox_display.addWidget(title_label)
        vbox_display.addLayout(hbox_setting)

        self.setLayout(vbox_display)
        self.show()

    @pyqtSlot(int)
    def puzzle_width_change(self, value):
        self.puzzle_width = value
        self.c.puzzle_setting.emit(
            [self.puzzle_width, self.puzzle_height, self.diff_val, self.option_val]
        )

    @pyqtSlot(int)
    def puzzle_height_change(self, value):
        self.puzzle_height = value
        self.c.puzzle_setting.emit(
            [self.puzzle_width, self.puzzle_height, self.diff_val, self.option_val]
        )

    @pyqtSlot(QRadioButton)
    def diff_checked(self, diff):
        text = diff.text()
        if text == "가로세로":
            self.shape = 0
        elif text == "가로세로 + 대각선":
            self.shape = 2
        elif text == "정방향":
            self.direction = 1
        elif text == "정방향 + 역방향":
            self.direction = 2

        self.diff_val = self.shape + self.direction
        self.c.puzzle_setting.emit(
            [self.puzzle_width, self.puzzle_height, self.diff_val, self.option_val]
        )

    @pyqtSlot(QRadioButton)
    def option_checked(self, option):
        text = option.text()
        if text == "글자 겹치지 않게":
            self.option_val = 0
        elif text == "글자 무작위로":
            self.option_val = 1
        elif text == "글자 겹치게":
            self.option_val = 2

        self.c.puzzle_setting.emit(
            [self.puzzle_width, self.puzzle_height, self.diff_val, self.option_val]
        )

class EnterWords(EnterWords):
    def init_UI(self):
        # Title for widget
        title = QLabel("2, 단어를 입력세요.")
        self.grid.addWidget(title, 0, 0)
        super(EnterWords, self).init_UI()

    def set_words(self):
        search_target = self.input_words.toPlainText()
        regex = r"[a-zA-Z]+_?[a-zA-Z]+"
        self.words = list({word.lower() for word in re.findall(regex, search_target)})
        if not self.words:
            regex = r"[가-힣]+_?[가-힣]+"
            self.words = list(
                {word.lower() for word in re.findall(regex, search_target)}
            )
            self.c.korean.emit(True)
        else:
            self.c.korean.emit(False)
        return self.words

class DownloadImage(DownloadImage):
    def __init__(self, c):
        super(DownloadImage, self).__init__(c)
        # initial puzzle settings
        self.width, self.height, self.diff, self.option = 15, 15, 1, 0
        # initialize download numbers
        self.picture_on = False
        # initialize language mode
        self.korean = False
        # initialize chosung or scramble mode
        self.chosung_scramable = False
        # initialize uppercase mode
        self.uppercase = False

    def init_UI(self):
        # Title for widget
        title = QLabel("3. 이미지를 선택하세요.")
        self.grid.addWidget(title, 0, 0)

        super(DownloadImage, self).init_UI()
        # get data of puzzle settings
        self.c.puzzle_setting.connect(self.puzzle_setting)
        # see if its korean or english/ default is english
        self.c.korean.connect(self.korean_on)

        self.uppercase_checkbox = QCheckBox("대문자", self)
        self.uppercase_checkbox.stateChanged.connect(self.uppercase_checkbox_on)

        self.chosung_scramable_checkBox = QCheckBox("scramble word", self)
        self.chosung_scramable_checkBox.setToolTip("단어의 철자가 뒤섞여서 제시됩니다.")
        self.chosung_scramable_checkBox.stateChanged.connect(self.chosung_scramable_on)

        self.make_puzzle_bt = QPushButton("Word Search\n퍼즐 만들기")
        self.make_puzzle_bt.clicked.connect(self.make_puzzle)
        self.make_puzzle_bt.setToolTip("단축키 : Ctrl + D")
        self.make_puzzle_bt.setShortcut("Ctrl+D")
        self.vbox.addWidget(self.uppercase_checkbox)

        self.vbox.addWidget(self.chosung_scramable_checkBox)
        self.vbox.addWidget(self.make_puzzle_bt)

    # define puzzle settings
    @pyqtSlot(list)
    def puzzle_setting(self, puzzle_setting):
        self.width, self.height, self.diff, self.option = (
            puzzle_setting[0],
            puzzle_setting[1],
            puzzle_setting[2],
            puzzle_setting[3],
        )

    @pyqtSlot(bool)
    def korean_on(self, bool):
        self.korean = bool
        if bool is True:
            self.chosung_scramable_checkBox.setText("초성")
            self.chosung_scramable_checkBox.setToolTip("단어의 초성으로 제시됩니다.")
            self.make_puzzle_bt.setText("낱말 퍼즐\n 만들기")
            self.uppercase_checkbox.close()
        else:
            self.chosung_scramable_checkBox.setText("scramble word")
            self.chosung_scramable_checkBox.setToolTip("단어의 철자가 뒤섞여서 제시됩니다.")
            self.make_puzzle_bt.setText("Word Search\n퍼즐 만들기")
            self.uppercase_checkbox.show()
        self.make_puzzle_bt.setToolTip("단축키 : Ctrl + D")
        self.make_puzzle_bt.setShortcut("Ctrl+D")

    @pyqtSlot()
    def uppercase_checkbox_on(self):
        if self.uppercase_checkbox.isChecked() is True:
            self.uppercase = True
        else:
            self.uppercase = False

    @pyqtSlot()
    def chosung_scramable_on(self):
        if self.chosung_scramable_checkBox.isChecked() is True:
            self.chosung_scramable = True
        else:
            self.chosung_scramable = False

    def enable_buttons(self):
        self.download_bt.setEnabled(True)
        self.make_puzzle_bt.setEnabled(True)
        self.c.enable_set_keyword_bt.emit()

    def disable_buttons(self):
        self.download_bt.setEnabled(False)
        self.make_puzzle_bt.setEnabled(False)
        self.c.disable_set_keyword_bt.emit()

    @pyqtSlot()
    def make_puzzle(self):
        word_image = []
        if self.tree.topLevelItemCount() == 0:
            self.start_download()
            return

        self.disable_buttons()

        if self.picture_on:
            iterator = QTreeWidgetItemIterator(
                self.tree, QTreeWidgetItemIterator.HasChildren
            )
        else:
            iterator = QTreeWidgetItemIterator(self.tree, QTreeWidgetItemIterator.All)
            if iterator.value() is None:
                self.c.press_set_keyword_bt.emit()
                q = QMessageBox(self)
                q.information(
                    self,
                    "information",
                    "검색어 키워드가 존재하지 않아요. 그래서 검색어 키워드 버튼을 대신 눌렀습니다~.",
                    QMessageBox.Ok,
                )
                self.enable_buttons()
                return
        while iterator.value():
            item = iterator.value()
            word = item.data(0, 0)
            pic = ""
            if self.picture_on:
                pic = item.path
                if not os.path.exists(pic):
                    self.c.press_set_keyword_bt.emit()
                    self.enable_buttons()
                    q = QMessageBox(self)
                    q.information(
                        self,
                        "information",
                        "선택하신 이미지가 존재하지 않습니다. 다시 다운로드 눌러주세요.",
                        QMessageBox.Ok,
                    )
                    return
            if word.strip().find(" ") != -1:
                if self.korean:
                    word = "가".join(word.split())
                else:
                    word = "a".join(word.split())
            word_image.append([word, pic])
            iterator += 1

        self.path = self.get_save_hwp_dir()
        if self.path:
            puzzle_worker = PuzzleWorker(
                wordsearch_generater.MakeWordSearch,
                word_image,
                self.width,
                self.height,
                self.diff,
                self.option,
                self.picture_on,
                self.korean,
                self.chosung_scramable,
                self.uppercase,
                self.path,
            )
            puzzle_worker.signal.puzzle_complete.connect(self.puzzle_finish)
            puzzle_worker.signal.recursionerrormsg.connect(self.recurerrormsg)
            puzzle_worker.signal.valueerrormsg.connect(self.valerrormsg)
            self.threadpool.start(puzzle_worker)
        else:
            self.enable_buttons()

    def get_save_hwp_dir(self):
        file_path = os.path.join(os.getcwd(), "dir_path.json")
        is_dir_path = os.path.exists(file_path)
        if is_dir_path:
            with open(file_path) as f:
                data = json.load(f)
            if "hwp_dir" in data.keys():
                dir_path = data["hwp_dir"]
                return dir_path
            else:
                q = QMessageBox(self)
                q.information(self, "information", "퍼즐을 저장할 폴더를 선택하세요.", QMessageBox.Ok)
                fname = str(QFileDialog.getExistingDirectory(self, "퍼즐을 저장할 폴더"))
                if fname:
                    data["hwp_dir"] = fname
                    with open(file_path, "w") as f:
                        json.dump(data, f)
                    dir_path = fname
                    return dir_path
                else:
                    return
        else:
            q = QMessageBox(self)
            q.information(self, "information", "퍼즐을 저장할 폴더를 선택하세요.", QMessageBox.Ok)
            fname = str(QFileDialog.getExistingDirectory(self, "퍼즐을 저장할 폴더"))
            if fname:
                with open(file_path, "w") as f:
                    json.dump({"hwp_dir": fname}, f)
                dir_path = fname
                return dir_path
            else:
                return

    @pyqtSlot()
    def puzzle_finish(self):
        q = QMessageBox(self)
        q.information(
            self, "information", "{}에 퍼즐 파일이 저장되었습니다.".format(self.path), QMessageBox.Ok
        )
        self.enable_buttons()

    @pyqtSlot()
    def recurerrormsg(self):
        q = QMessageBox(self)
        q.warning(self, "Warning", "단어의 개수에 비해서 퍼즐의 크기가 너무 작습니다.", QMessageBox.Ok)
        self.enable_buttons()

    @pyqtSlot()
    def valerrormsg(self):
        q = QMessageBox(self)
        q.warning(self, "Warning", "퍼즐의 크기에 비해 단어가 너무 길어요.", QMessageBox.Ok)
        self.enable_buttons()

# thread to download pictures while not stopping the Gui
class PuzzleWorker(QRunnable):
    def __init__(self, fn, *args, **kwargs):
        super(PuzzleWorker, self).__init__()
        self.fn = fn
        self.args = args
        self.kwargs = kwargs
        self.signal = Communication()

    @pyqtSlot()
    def run(self):
        try:
            self.fn(*self.args, **self.kwargs).make_puzzle()
            self.signal.puzzle_complete.emit()
        except RecursionError:
            self.signal.recursionerrormsg.emit()
        except ValueError:
            self.signal.valueerrormsg.emit()

class MainWindow(MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

    def init_UI(self):
        super(MainWindow, self).init_UI()
        self.setWindowTitle("Word Puzzle generator")
        self.setWindowIcon(QIcon("wordsearch.ico"))
        c = Communication()
        self.vbox.addWidget(Settings(c))
        self.enterwords_widget = EnterWords(c)
        self.vbox.addWidget(self.enterwords_widget)
        self.vbox.addWidget(DownloadImage(c))
        self.vbox.setStretch(0, 1)
        self.vbox.setStretch(1, 1)
        self.vbox.setStretch(2, 7)
        self.addsettingmenu()
        self.addhelpmenu()

    def addsettingmenu(self):
        self.settings_menu = self.mainMenu.addMenu("설정")
        self.set_grad_class_Button = QAction("학년 반 설정하기", self)
        self.set_grad_class_Button.triggered.connect(self.grade_class_dialog)
        self.settings_menu.addAction(self.set_grad_class_Button)

        self.reset_grade_class_Button = QAction("학년 반 초기화하기", self)
        self.reset_grade_class_Button.triggered.connect(self.reset_grade_class)
        self.settings_menu.addAction(self.reset_grade_class_Button)

    def addhelpmenu(self):
        self.help_menu = self.mainMenu.addMenu("도움말")

        self.puzzle_option_menu = self.help_menu.addMenu("퍼즐 옵션")
        self.shape_help = QAction("단어 모양은 무슨 뜻인가요?")
        # self.shape_help.triggered.connect(self.)
        self.puzzle_option_menu.addAction(self.shape_help)

        self.direction_help = QAction("단어 방향은 무슨 뜻인가요?")
        # self.direction_help.triggered.connect(self.)
        self.puzzle_option_menu.addAction(self.direction_help)

        self.option_help = QAction("옵션에서 글자를 겹치게 한다는 것은 무슨 뜻인가요?")
        # self.option_help.triggered.connect(self.)
        self.puzzle_option_menu.addAction(self.option_help)

        self.enter_words_menu = self.help_menu.addMenu("단어 입력")
        self.enterword_help = QAction("단어는 어떻게 입력하나요?")
        # self.enterword_help.triggered.connect(self.)
        self.enter_words_menu.addAction(self.enterword_help)

        self.prefix_help = QAction("실제 사진이 아니라 케릭터 사진을 원하면 어떻게 하나요?")
        # self.prefix_help.triggered.connect(self.)
        self.enter_words_menu.addAction(self.prefix_help)

        self.download_images_menu = self.help_menu.addMenu("이미지")
        self.keyword_help = QAction("원하는 이미지가 안 나올 때는 어떻게 하나요?")
        # self.keyword_help.triggered.connect(self.grade_class_dialog)
        self.download_images_menu.addAction(self.keyword_help)

        self.searchnum_help = QAction("이미지 검색 개수를 어떻게 바꾸나요?")
        # self.searchnum_help.triggered.connect(self.grade_class_dialog)
        self.download_images_menu.addAction(self.searchnum_help)

        self.changepic_help = QAction("원하는 이미지로 어떻게 변경하나요?")
        # self.changepic_help.triggered.connect(self.)
        self.download_images_menu.addAction(self.changepic_help)

        self.scramble_help = QAction("scramble word를 체크하면 어떻게 되나요?")
        # self.scramble_help.triggered.connect(self.)
        self.help_menu.addAction(self.scramble_help)

    def grade_class_dialog(self):
        self.grade_class_input = QWidget()
        hbox_grade = QHBoxLayout()
        grade_label = QLabel("학년")
        self.grade_spin = QSpinBox()
        self.grade_spin.setMinimum(1)
        self.grade_spin.setMaximum(6)
        hbox_grade.addWidget(grade_label)
        hbox_grade.addWidget(self.grade_spin)
        hbox_class = QHBoxLayout()
        class_label = QLabel("반")
        self.class_spin = QSpinBox()
        self.class_spin.setMinimum(1)
        hbox_class.addWidget(class_label)
        hbox_class.addWidget(self.class_spin)

        if os.path.exists("hwp_settings.json"):
            with open("hwp_settings.json") as f:
                data = json.load(f)
                self.grade_spin.setValue(data["grade"])
                self.class_spin.setValue(data["class"])

        ok_button = QPushButton("확인")
        ok_button.clicked.connect(self.set_grade_class)

        vbox_display = QVBoxLayout()
        vbox_display.addLayout(hbox_grade)
        vbox_display.addLayout(hbox_class)
        vbox_display.addWidget(ok_button)

        self.grade_class_input.setLayout(vbox_display)
        self.grade_class_input.show()

    def set_grade_class(self):
        self.grade = self.grade_spin.value()
        self.class_ = self.class_spin.value()
        data = dict()
        data["grade"] = self.grade
        data["class"] = self.class_
        with open("hwp_settings.json", "w") as f:
            json.dump(data, f)
        self.grade_class_input.close()

    def reset_grade_class(self):
        if os.path.exists("hwp_settings.json"):
            os.unlink("hwp_settings.json")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = MainWindow()
    app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
    sys.exit(app.exec_())


import requests
from requests.auth import HTTPBasicAuth
import constants as k

requests.packages.urllib3.disable_warnings()

def API_CALL(method, url, headers, json=True, verify=False, req_data=None, auth=None, body=None):
    r = requests.request(method, url, auth=auth, data=body, headers=headers, verify=verify, json=req_data)
    sc = r.status_code
    if json == True:
        return r.json(), sc
    else:
        return r, sc

def get_token():
    r_token = API_CALL(method="POST",
                             url='https://iam.cloud.ibm.com/identity/token',
                             headers={'Content-Type': 'application/x-www-form-urlencoded'},
                             body={
                                 "grant_type": "urn:ibm:params:oauth:grant-type:apikey",
                                 "apikey": k.api_key
                             })

    return r_token[0]['access_token']

def get_resource_instances():
    r_resources = API_CALL(method="GET",
                                url='https://resource-controller.cloud.ibm.com/v2/resource_instances',
                                headers={'authorization': 'Bearer ' + get_token()}
                                 )

    list_resources = {}
    for s in k.services_to_check:
        list_resources[s] = []

    for r in r_resources[0]['resources']:
        for s in k.services_to_check:
            if s in r['crn']:
                list_resources[s].append(
                    {'guid': r['guid'], 'name': r['name'], 'crn': r['crn'], 'region_id': r['region_id']})

    return list_resources

def get_resource_instances_by_type(t):
    r_resources = API_CALL(method="GET",
                                 url='https://resource-controller.cloud.ibm.com/v2/resource_instances',
                                 headers={'authorization': 'Bearer ' + get_token()}
                                 )
    list_instances = {}

    for r in r_resources[0]['resources']:
        if t in r['crn']:
            list_instances.setdefault(r['name'], {'guid': r['guid'], 'name': r['name'], 'crn': r['crn'], 'region_id': r['region_id']})

    return list_instances

def get_resource_instance(guid):
    r_resource = API_CALL(method="GET",
                                url='https://resource-controller.cloud.ibm.com/v2/resource_instances/ '+ guid,
                                headers={'authorization': 'Bearer ' + get_token()}
                                 )

    return r_resource[0]

def get_resource_key(guid):
    r_key = API_CALL(method="GET",
                    url="https://resource-controller.cloud.ibm.com/v2/resource_instances/" + guid + "/resource_keys",
                    headers={'authorization': 'Bearer ' + get_token()}
                    )

    return r_key[0]['resources'][0]['credentials']['apikey']


from flask import Flask, render_template,redirect
from flask_pymongo import PyMongo
import scrape_mars

#Create an instance of Flask
app=Flask(__name__)

#Setup connection to mongodb
app.config["MONGO_URI"]="mongodb://localhost:27017/mars_app"
mongo = PyMongo(app)

#Create routes and render html templates
@app.route("/")
def index():

    mars_dict=mongo.db.mars_dict.find_one()

    return render_template("index.html",mars=mars_dict)

@app.route("/scrape")
def scrape():

    mars_dict = mongo.db.mars_dict
    mars_data=scrape_mars.scrape()

    mars_dict.update({},mars_data,upsert=True)
    return redirect("/",code=302)

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


import os
import json
import pandas as pd
from pymongo import MongoClient
from google.cloud.storage import client

import src.to_gcs as load
import src.mongodb_transform as transform
from src.logging_task import logger
from src.from_mongodb import extract_mongodb

if __name__=='__main__':
    logger=logger(filename='project_three_logs.log', filemode='w')

    client=MongoClient('mongodb://localhost:27017/')                        # begin extraction
    dbs='test'
    coll_city='city_inspection'
    coll_zips='zips'
    inspection_list_dict=extract_mongodb(client, dbs, coll_city)
    zips_list_dict=extract_mongodb(client, dbs, coll_zips)

    bucket_name='data-engineering-data-sources'                             # load to staging, cloudstorage
    dest_blob_inspection='raw/project_three/city_inspection.json'
    dest_blob_zips='raw/project_three/zips.json'
    source_inspecton='/tmp/city_inspection.json'
    source_zips='/tmp/zips.json'
    with open(source_inspecton,'w') as json_inspection:
        json.dump(inspection_list_dict, json_inspection,indent=1)
    with open(source_zips,'w') as json_zips:
        json.dump(zips_list_dict, json_zips,indent=1)
    load.load_blob(bucket_name, dest_blob_inspection, source_inspecton)
    load.load_blob(bucket_name, dest_blob_zips, source_zips)
    logger.info('extraction is complete, file loaded to gcs at {} and {}'.format(dest_blob_inspection,dest_blob_zips))

    list_of_data=transform.transform_inspection(source_inspecton, source_zips)                          # transformation stage
    list_of_data[0].to_parquet('/tmp/city_inspection.pq',
                                compression='gzip')
    list_of_data[1].to_parquet('/tmp/address.pq',
                                compression='gzip')
    list_of_data[-1].to_parquet('/tmp/zips.pq',
                                 compression='gzip')
    logger.info('extract complete, check file in tmp')

    dest_blob_inspection_transform='transformed/project_three/city_inspection.pq'
    dest_blob_address_transform='transformed/project_three/address.pq'         # after transformation is completed load to staging
    dest_blob_zips_transform='transformed/project_three/zips.pq'               # and to bigquery
    source_inspecton_transform='/tmp/city_inspection.pq'
    source_address_transform='/tmp/address.pq'
    source_zips_transform='/tmp/zips.pq'
    load.load_blob(bucket_name,
                   dest_blob_inspection_transform,
                   source_inspecton_transform)
    load.load_blob(bucket_name,
                   dest_blob_address_transform,
                   source_address_transform)
    load.load_blob(bucket_name,
                   dest_blob_zips_transform,
                   source_zips_transform)

    url_inspection='gs://'+bucket_name+'/'+dest_blob_inspection_transform         #load parquet into coudstorage and bigquery
    url_address='gs://'+bucket_name+'/'+dest_blob_address_transform
    url_zips='gs://'+bucket_name+'/'+dest_blob_zips_transform
    load.pq_gcs_to_bigquery(url_inspection, 'project_three', 'city_inspection','WRITE_TRUNCATE')
    load.pq_gcs_to_bigquery(url_address, 'project_three', 'address','WRITE_TRUNCATE')
    load.pq_gcs_to_bigquery(url_zips, 'project_three', 'zips', 'WRITE_TRUNCATE')
    logger.info('task is succesfull , the data are ready at project_three dataset')

    os.system('cat logs.log')


import os
import re
import copy
import json
import time
import emoji
import queue
import socket
import threading
import netifaces
from datetime import datetime

profile_dict = {}
chat_dict = {}
msg_formats = {}
ip_dict = {}
new_msg_dict = {}

msg_queue = queue.Queue()
profile_struct = {"tag": "", "name": "", "ip": "", "isActiveStatus": False}

isSelfOnline = True
isExit = False
isNotified = True
isLocal = True
listenPid = 5
PORT = 12345

def entry():
    print("Welcome to Chat-In-Python!")
    print("It is a local area chatting application on the commandline.")
    print("P.S. : Environment set 'local' by default.")
    print("For further help, type 'help' and Enter.")
    print("To exit, type 'exit' and Enter.")

def helpy():
    print("- This application is developed for LAN chatting.")
    print("- When you become online, a discovery signal will be sent")
    print("for all possible LAN IP addresses to receive a response")
    print("- After receiving a response, the user that has responded")
    print("to you will become online for you to start chatting.")
    print("- Users inside the program are stored with their <user-tag>")
    print("that is a composition of their names and their last part")
    print("of their LAN IP address.")
    print("e.g. {} ozgurcan-25: ozgurcan@192.168.1.25".format(emoji.emojize(":bust_in_silhouette:")))
    print("-" * 56)
    print(" - GENERAL COMMAND LIST - ")
    print("help:\t\t\t\t Opens general command.")
    print("switch <env>:\t\t\t Changes into any environment.")
    print("\t\t\t\t Either to 'hamachi' or 'local'.")
    print("discover:\t\t\t Discovers the clients in the network.")
    print("profile:\t\t\t Shows your profile.")
    print("whoall:\t\t\t\t Shows all users' profiles.")
    print("show <user_tag>:\t\t Shows the profile of user with")
    print("\t\t\t\t tag <user_tag>.")
    print("whoisonline:\t\t\t Shows all available users in LAN.")
    print("sendmsg <user_tag> <your_msg>:\t Sends message to the user with")
    print("\t\t\t\t tag <user_tag> and message between asterisks.")
    print("chathist <user_tag>:\t\t Opens chat history with <user_tag>")
    print("dumphist <user_tag>:\t\t Dumps chat history in a .txt file")

def ip_extractor():
    ip_list = []
    for if_name in netifaces.interfaces():
        for ip in netifaces.ifaddresses(if_name).get(netifaces.AF_INET, ()):
            ip_list.append(ip["addr"])
    return ip_list

def ip_regex(ip_list):
    global ip_dict
    local_pat = re.compile("^192.168.1.[0-9]{1,3}$")
    hamachi_pat = re.compile("^25.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$")
    for ip in ip_list:
        hamachi_match = hamachi_pat.match(ip)
        local_match = local_pat.match(ip)
        if hamachi_match is not None:
            ip_dict["hamachi"] = hamachi_match.group()
        if local_match is not None:
            ip_dict["local"] = local_match.group()

def switch(env):
    global isLocal
    if env == "local":
        isLocal = True
        env_params("local")
    elif env == "hamachi":
        isLocal = False
        env_params("hamachi")
    else:
        print("Invalid environment. Set to 'local' by default.")
        isLocal = True
        env_params("local")

def hamachi_ip_extract():
    hamachi_ip_file = open("./hamachi_ip_list.txt", "r")
    hamachi_ipl = [hip.strip() for hip in hamachi_ip_file.readlines()]
    hamachi_ip_file.close()
    return hamachi_ipl

def discover():
    if isLocal:
        local_discover()
    else:
        hamachi_discover(hamachi_ip_list)

def env_params(env):
    global profile_dict, ip_dict
    ip_regex(ip_extractor())
    user_name = os.getenv("USER")
    user_ip = ip_dict[env]
    if env == "hamachi":
        user_identifier = ".".join(user_ip.split(".")[1:])
    elif env == "local":
        user_identifier = user_ip.split(".")[-1]
    else:
        raise ValueError("There's no suitable IP address in this platform. Aborted.")

    user_tag = str(user_name).upper() + "-" + str(user_identifier)
    profile_dict["self"] = {"tag": user_tag, "isActiveStatus": False, "name": user_name, "ip": user_ip}
    msg_formatting("self")

def msg_formatting(user_tag):
    global msg_formats
    profile = profile_dict[user_tag]
    discovery = {"NAME": profile["name"], "MY_IP": profile["ip"], "TYPE": "DISCOVER", "PAYLOAD": ""}
    response = {"NAME": profile["name"], "MY_IP": profile["ip"], "TYPE": "RESPOND", "PAYLOAD": ""}
    message = {"NAME": profile["name"], "MY_IP": profile["ip"], "TYPE": "MESSAGE", "PAYLOAD": ""}
    msg_formats["discovery"] = discovery
    msg_formats["response"] = response
    msg_formats["message"] = message

def cmd_input_analysis(cmd_input):
    input_tokens = str(cmd_input).split()
    if len(input_tokens) == 0:
        return
    input_tokens[0] = input_tokens[0].lower()
    if input_tokens[0] == "profile":
        profile_disp()
    elif input_tokens[0] == "refresh":
        print("{} Checking for new messages."
              .format(emoji.emojize(":tropical_drink:")))
    elif input_tokens[0] == "help":
        helpy()
    elif input_tokens[0] == "switch":
        switch(input_tokens[1].lower())
    elif input_tokens[0] == "discover":
        discover()
    elif input_tokens[0] == "whoisonline":
        who_is_online()
    elif input_tokens[0] == "whoall":
        who_all()
    elif input_tokens[0] == "show":
        show_profile(input_tokens[1].lower())
    elif input_tokens[0] == "sendmsg":
        send_message(" ".join(input_tokens[1:]))
    elif input_tokens[0] == "chathist":
        chat_history(input_tokens[1].lower())
    elif input_tokens[0] == "dumphist":
        dump_history(input_tokens[1].lower())
    else:
        print("Invalid input. Try again!")

def tag_generator(name, ip):
    hamachi_pat = re.compile("^25.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$")
    local_pat = re.compile("^192.168.1.[0-9]{1,3}$")
    if local_pat.match(ip) is not None:
        ip_identifier = str(ip).split(".")[-1]
        return "-".join([name, ip_identifier])
    else:
        if hamachi_pat.match(ip) is not None:
            ip_identifier = ".".join(str(ip).split(".")[1:])
            return "-".join([name, ip_identifier])

def profile_disp():
    if isSelfOnline:
        print(emoji.emojize("Status Information: Online :green_apple:"))
        print("Number of Active Chats: {}".format(count_active_chat()))
    else:
        print(emoji.emojize("Status Information: Offline :red_circle:"))
    print(emoji.emojize(" - PROFILE INFO :eyes: -"))
    print("{} User Tag:\t\t\t {}".format(emoji.emojize(":thumbs_up:"), str(profile_dict["self"]["tag"]).upper()))
    print("{} User Name:\t\t\t {}".format(emoji.emojize(":thumbs_up:"), profile_dict["self"]["name"]))
    print("{} User IP:\t\t\t {}".format(emoji.emojize(":thumbs_up:"), profile_dict["self"]["ip"]))

def show_profile(user_tag):
    print(emoji.emojize(" - PROFILE INFO :eyes: -"))
    print("{} User Tag:\t\t\t {}".format(emoji.emojize(":thumbs_up:"), str(profile_dict[user_tag]["tag"]).upper()))
    print("{} User Name:\t\t\t {}".format(emoji.emojize(":thumbs_up:"), profile_dict[user_tag]["name"]))
    print("{} User IP:\t\t\t {}".format(emoji.emojize(":thumbs_up:"), profile_dict[user_tag]["ip"]))

def who_all():
    for tag in profile_dict.keys():
        if tag != "self":
            p = profile_dict[tag]
            print("{} User Tag:{}\t User Name:{}\t User IP:{}"
                  .format(emoji.emojize(":eyes:"), p["tag"], p["name"], p["ip"]))

def count_active_chat():
    active_tags = [tag for tag, chat in chat_dict.items() if len(chat) != 0 and profile_dict[tag]["isActiveStatus"]]
    return len(active_tags)

def who_is_online():
    active_users = [user["tag"] for tag, user in profile_dict.items() if tag != "self" and user["isActiveStatus"]]
    for user in active_users:
        print(emoji.emojize(":bust_in_silhouette: {}".format(user)))

def send_message(msg_info):
    global chat_dict
    msg_info_tokens = msg_info.split()
    recipient_tag = msg_info_tokens[0].lower()
    if recipient_tag not in profile_dict.keys():
        print("The recipient is not recognized. Check the user tag.")
        return
    recipient_profile = profile_dict[recipient_tag]
    msg = " ".join(msg_info_tokens[1:])
    if len(msg) > 140:
        print("Message can be composed with at most 140 characters.")
        return
    chat_dict[recipient_tag].append("+ " + str(msg))
    msg_obj = copy.deepcopy(msg_formats["message"])
    msg_obj["PAYLOAD"] = msg
    msg_obj_srl = json.dumps(msg_obj)

    try:
        socket_send(msg_obj_srl, recipient_profile["ip"])
        print("{} Your message is sent!".format(emoji.emojize(":fire:")))
    except socket.timeout:
        print("{} User with tag {} is not online right now. Try again!"
              .format(emoji.emojize(":no_entry:"), recipient_tag))
        pass

def local_discover():
    global ip_dict
    my_ip = ip_dict["local"].split(".")[-1]
    disc_obj = copy.deepcopy(msg_formats["discovery"])
    disc_obj_srl = json.dumps(disc_obj)
    for ip in range(1, int(my_ip)):
        try:
            socket_send(disc_obj_srl, "192.168.1.{}".format(ip))
        except socket.timeout:
            print("{} User with ip {} is not online right now. Try again!"
                  .format(emoji.emojize(":no_entry:"), "192.168.1.{}".format(ip)))
        except ConnectionRefusedError:
            pass
    for ip in range(int(my_ip)+1, 255):
        try:
            socket_send(disc_obj_srl, "192.168.1.{}".format(ip))
        except socket.timeout:
            print("{} User with ip {} is not online right now. Try again!"
                  .format(emoji.emojize(":no_entry:"), "192.168.1.{}".format(ip)))
        except ConnectionRefusedError:
            pass
    print("{} Local client discovery completed!".format(emoji.emojize(":globe_with_meridians:")))

def hamachi_discover(ip_list):
    hamachi_obj = copy.deepcopy(msg_formats["discovery"])
    hamachi_obj_srl = json.dumps(hamachi_obj)
    for ip in ip_list:
        try:
            socket_send(hamachi_obj_srl, ip)
        except socket.timeout:
            print("{} User with ip {} is not online right now. Try again!"
                  .format(emoji.emojize(":no_entry:"), ip))
        except ConnectionRefusedError:
            pass
    print("{} Hamachi client discovery completed!".format(emoji.emojize(":mushroom:")))

def extract_profile(msg):
    tag = tag_generator(msg["NAME"], msg["MY_IP"])
    new_profile = copy.deepcopy(profile_struct)
    new_profile["tag"] = tag
    new_profile["name"] = msg["NAME"]
    new_profile["ip"] = msg["MY_IP"]
    new_profile["isActiveStatus"] = True
    return new_profile, tag

def discovery_actions(msg):
    new_profile, tag = extract_profile(msg)
    rsp_obj = msg_formats["response"]
    rsp_obj_srl = json.dumps(rsp_obj)
    try:
        socket_send(rsp_obj_srl, msg["MY_IP"])
    except socket.timeout:
        print("{} User with ip {} is not online right now. Try again!"
              .format(emoji.emojize(":no_entry:"), msg["MY_IP"]))
    except ConnectionRefusedError:
        pass
    profile_dict[tag] = new_profile
    chat_dict[tag] = []

def response_actions(msg):
    new_profile, tag = extract_profile(msg)
    profile_dict[tag] = new_profile
    chat_dict[tag] = []

def message_actions(msg):
    global chat_dict, new_msg_dict
    tag = tag_generator(msg["NAME"], msg["MY_IP"])
    message = "- " + str(msg["PAYLOAD"])
    if tag not in chat_dict.keys():
        chat_dict[tag] = []
    chat_dict[tag].append(message)
    if tag not in new_msg_dict.keys():
        new_msg_dict[tag] = 0
    new_msg_dict[tag] += 1

def new_msg_count():
    global isNotified
    if not isNotified:
        print("{} You have new messages!".format(emoji.emojize(":bell:")))
        for tag, nmc in new_msg_dict.items():
            print("{} {} message(s) from {}".format(emoji.emojize(":paperclip:"), nmc, profile_dict[tag]["name"]))

def chat_history(user_tag):
    global chat_dict, isNotified, new_msg_dict
    isNotified = True
    new_msg_dict[user_tag] = 0
    history = chat_dict[user_tag]
    for msg_line in history:
        print(msg_line)

def dump_history(user_tag):
    global chat_dict
    history = chat_dict[user_tag]
    da_ti = datetime.utcnow().strftime("%Y-%m-%d_%H:%M:%S")
    f_name = user_tag + "-" + da_ti + ".txt"
    dump = open(f_name, "w")
    for msg in history:
        dump.write(msg)
        dump.write("\n")
    dump.flush()
    dump.close()

def listener_func():
    global isExit
    while True:
        if isExit:
            break
        socket_listen()

def message_parse():
    global isNotified
    raw_message = msg_queue.get()

    dcd_msg = raw_message.decode("utf-8")
    if dcd_msg != "\n" and dcd_msg != "\r":
        message = dcd_msg.strip("\n")
    else:
        return

    try:
        msg = json.loads(message)
    except json.decoder.JSONDecodeError:
        return
    if msg["TYPE"] == "DISCOVER":
        discovery_actions(msg)
    elif msg["TYPE"] == "RESPOND":
        response_actions(msg)
    elif msg["TYPE"] == "MESSAGE":
        isNotified = False
        message_actions(msg)
    else:
        print("Invalid message type")

def messenger_func():
    while True:
        if isExit:
            break
        message_parse()

def socket_listen():
    if isLocal:
        host_ip = ip_dict["local"]
    else:
        host_ip = ip_dict["hamachi"]
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.bind((host_ip, 12345))
        sock.listen()
        in_conn, addr = sock.accept()
        with in_conn:
            while True:
                in_data = in_conn.recv(1024)
                if in_data:
                    msg_queue.put_nowait(in_data)
                else:
                    break

def socket_send(msg, recp_ip):
    raw_msg = str(msg) + "\n"
    enc_msg = raw_msg.encode("utf-8")

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.settimeout(1)
    sock.connect((recp_ip, 12345))
    sock.sendall(enc_msg)
    sock.close()

def terminate():
    for i in range(0, 2):
        print("\r{} | Prepare to shutdown down gracefully...".format(emoji.emojize(":floppy_disk:")), end=" ")
        time.sleep(.3125)
        print("\r{} / Prepare to shutdown down gracefully...".format(emoji.emojize(":floppy_disk:")), end=" ")
        time.sleep(.3125)
        print("\r{} - Prepare to shutdown down gracefully...".format(emoji.emojize(":floppy_disk:")), end=" ")
        time.sleep(.3125)
        print("\r{} \\ Prepare to shutdown down gracefully...".format(emoji.emojize(":floppy_disk:")), end=" ")
        time.sleep(.3125)
    print("\r\n", end=" ")
    print("\r{} You are exiting in 5 seconds...".format(emoji.emojize(":koala:")), end=" ")
    time.sleep(1)
    print("\r{} You are exiting in 4 seconds...".format(emoji.emojize(":penguin:")), end=" ")
    time.sleep(1)
    print("\r{} You are exiting in 3 seconds...".format(emoji.emojize(":boar:")), end=" ")
    time.sleep(1)
    print("\r{} You are exiting in 2 seconds...".format(emoji.emojize(":camel:")), end=" ")
    time.sleep(1)
    print("\r{} You are exiting in 1 seconds...".format(emoji.emojize(":bird:")), end=" ")
    time.sleep(1)
    print("\r\n", end=" ")
    print("\r{} Till next time!".format(emoji.emojize(":monkey:")), end=" ")

if __name__ == "__main__":
    entry()
    hamachi_ip_list = hamachi_ip_extract()
    listen_func = threading.Thread(target=listener_func)
    listen_func.daemon = True
    message_func = threading.Thread(target=messenger_func)
    message_func.daemon = True

    print("Select your environment to work: type 'local' or 'hamachi'.")
    while True:
        usr_env_input = input(">>> ")
        if usr_env_input.strip().lower() == "local":
            switch("local")
            break
        elif usr_env_input.strip().lower() == "hamachi":
            switch("hamachi")
            break
        else:
            print("{} Enter a valid environment.".format(emoji.emojize(":no_entry:")))
    listen_func.start()
    message_func.start()

    while True:
        usr_input = input(">>> ")
        if usr_input == "exit":
            isExit = True
            break
        else:
            cmd_input_analysis(usr_input)
        new_msg_count()
    print("*" * 24)
    message_func.join(1)
    listen_func.join(1)
    terminate()


from django.shortcuts import render
from django.http import HttpResponse
from django.core import serializers
from mywatchlist.models import MyWatchList

def show_mywatchlist_html(request):
    mywatchlist = MyWatchList.objects.all()
    movies_counter = len(MyWatchList.objects.all())
    movies_counter_watched = len(MyWatchList.objects.filter(watched = True))
    if(movies_counter_watched >= movies_counter/2):
        movies_watched = True
    else:
        movies_watched = False

    context = {
        "nama": "Alvaro Austin",
        "student_id": 2106752180,
        "mywatchlist": mywatchlist,
        "movies_watched": movies_watched
    }

    return render(request, 'mywatchlist.html', context)

def show_mywatchlist_xml(request):
    mywatchlist = MyWatchList.objects.all()
    return HttpResponse(serializers.serialize("xml", mywatchlist), content_type="application/xml")

def show_mywatchlist_json(request):
    mywatchlist = MyWatchList.objects.all()
    return HttpResponse(serializers.serialize("json", mywatchlist), content_type="application/json")


from framework import *
from rand import *

from enum import Enum
import numpy as np
import copy
from queue import PriorityQueue, Queue

class SickType(Enum):
    FIRST = 1
    SECOND = 2
    THIRD = 3

class SickHuman:
    def __init__(self, sick_type):
        self.sick_type = sick_type

    # implement < so type 1 is highest priority
    def __lt__(self, other):
        if self.sick_type == SickType.FIRST and other.sick_type != SickType.FIRST:
            return True
        else:
            return False

class HumanInput(Create):
    # next element is expected to be Hospital
    def __init__(self, name):
        super().__init__(0, name)
        self.sick_type_distribution = {
            SickType.FIRST: 0.5,
            SickType.SECOND: 0.1,
            SickType.THIRD: 0.4
        }

        self.sick_type_delay = {
            SickType.FIRST: 15,
            SickType.SECOND: 40,
            SickType.THIRD: 30
        }

        self.sick_human_to_send = self._generate_next_sick()
        self.tnext = self.tcurr + self.sick_type_delay[self.sick_human_to_send.sick_type]

        self.mean_delay_sum = self.sick_type_delay[self.sick_human_to_send.sick_type]
        self.mean_delay_count = 1

    def out_act(self):
        self.quantity += 1

        sick_human = self._generate_next_sick()
        self.tnext = self.tcurr + self.sick_type_delay[sick_human.sick_type]

        self.mean_delay_sum += self.sick_type_delay[sick_human.sick_type]
        self.mean_delay_count += 1

        if len(self.next_elements) > 1:
            raise Exception('HumanInput has to have exactly 1 next element')

        self.next_elements[0].in_act(copy.deepcopy(self.sick_human_to_send))
        self.sick_human_to_send = sick_human

    def _generate_next_sick(self) -> SickHuman:
        # generate next sick dies to distribution
        sick_type = np.random.choice(np.arange(1, 4), p=[
            self.sick_type_distribution[SickType.FIRST],
            self.sick_type_distribution[SickType.SECOND],
            self.sick_type_distribution[SickType.THIRD]
        ])

        return SickHuman(SickType(sick_type))

    def get_mean_delay(self):
        if self.mean_delay_count != 0:
            return self.mean_delay_sum / self.mean_delay_count
        else:
            return -1

class GeneralSickProcessor(Process):
    def __init__(self, delay_func, name, maxqueue, devices_amount = 1):
        super().__init__(None, name, maxqueue, devices_amount, 0)
        self.sick_human = None
        self.queue = Queue(maxqueue)
        self.delay_func = delay_func

        self.mean_delay_sum = 0
        self.mean_delay_count = 0

        self.mean_between_in_act_sum = 0
        self.mean_between_in_act_count = 0

        self.last_in_act_tcurr = 0

    def do_statistics(self, delta):
        self.meanQueue += (self.queue.qsize() * delta)

    def print_info(self):
        print(f'Name: {self.name}, \
              Quantity: {self.quantity}, \
              Queue: {self.queue.qsize()}, \
              Maxqueue: {self.maxqueue}, \
              Failure: {self.failure}, \
              MeanQueue: {((self.meanQueue/self.tcurr) if self.tcurr != 0.0 else (0.0)):.2f}, \
              Failure probability: {((self.failure / (self.quantity + self.failure)) if (self.quantity + self.failure) > 0 else 0.0):.2f}')
        for device in self.devices:
            print(f'\tDevice: {device.name}, \
                  tnext: {device.tnext:.2f}, \
                  state: {device.state}')

    def can_accept(self):
        return self.queue.full() == False

    def put_in_queue(self, sick_human):
        raise Exception('Not implemented')

    def get_delay_specific(self, sick_human = None):
        raise Exception('Not implemented')

    def get_between_in_act(self):
        if self.mean_between_in_act_count == 0:
            return -1
        return self.mean_between_in_act_sum / self.mean_between_in_act_count

    def in_act(self, sick_human):
        if self.tcurr != 0:
            between_in_act = self.tcurr - self.last_in_act_tcurr
            self.mean_between_in_act_sum += between_in_act
            self.mean_between_in_act_count += 1
            self.last_in_act_tcurr = self.tcurr

        if self.get_free_device() is not None:
            device = self.get_free_device()
            device.state = State.BUSY

            tmp_delay = self.get_delay_specific(sick_human)
            device.tnext = self.tcurr + tmp_delay
            device.data = sick_human

            self.mean_delay_sum += tmp_delay
            self.mean_delay_count += 1
        else:
            if self.queue.qsize() < self.maxqueue:
                self.put_in_queue(sick_human)
            else:
                self.failure += 1

    def out_act(self):
        self.quantity += 1

        min_dev = self.get_min_device()

        min_dev.state = State.FREE
        min_dev.tnext = float(sys.maxsize)
        self.data_to_send = copy.deepcopy(min_dev.data)
        min_dev.data = None

        if self.queue.qsize() > 0:
            element_to_attach = self.queue.get()

            free_device = self.get_free_device()
            free_device.state = State.BUSY

            tmp_delay = self.get_delay_specific(element_to_attach)
            if self.name == 'Room':
                print(f'Room delay: {tmp_delay}')

            free_device.tnext = self.tcurr + tmp_delay
            free_device.data = element_to_attach

            self.mean_delay_sum += tmp_delay
            self.mean_delay_count += 1

        # after super() call in child use self.data_to_send to send where needed

    def get_mean_delay(self):
        if self.mean_delay_count != 0:
            return self.mean_delay_sum / self.mean_delay_count
        else:
            return -1

class Hospital(GeneralSickProcessor):
    def __init__(self, delay_func, name, maxqueue):
        super().__init__(delay_func, name, maxqueue, 2)
        self.queue = PriorityQueue(maxqueue)

    def put_in_queue(self, sick_human):
        if sick_human.sick_type == SickType.FIRST:
            self.queue.put(sick_human)
        else:
            self.queue.put(sick_human)

    def get_delay_specific(self, sick_human = None):
        return self.delay_func()

    def __call_in_act_first_type_in_smo2_other_in_lab(self):
        if len(self.next_elements) != 2:
            raise Exception('Hospital has to have exactly 2 next elements')

        try:
            if self.data_to_send.sick_type == SickType.FIRST:
                self.next_elements[0].in_act(copy.deepcopy(self.data_to_send))
            else:
                self.next_elements[1].in_act(copy.deepcopy(self.data_to_send))
        except:
            raise Exception('Hospital must use Room and LabReg as next elements')

    def out_act(self):
        super().out_act()

        self.__call_in_act_first_type_in_smo2_other_in_lab()

class Room(GeneralSickProcessor): # post hospital room
    def __init__(self, delay_func, name, maxqueue):
        super().__init__(delay_func, name, maxqueue, 3)

    def put_in_queue(self, sick_human):
        self.queue.put(sick_human)

    def get_delay_specific(self, sick_human = None):
        return self.delay_func()

    def out_act(self):
        super().out_act()
        # no in act because it is last element

class LabReg(GeneralSickProcessor):
    def __init__(self, delay_func, name, maxqueue):
        super().__init__(delay_func, name, maxqueue, 1)

    def put_in_queue(self, sick_human):
        self.queue.put(sick_human)

    def get_delay_specific(self, sick_human = None):
        return self.delay_func()

    def out_act(self):
        super().out_act()

        if len(self.next_elements) != 1:
            raise Exception('LabReg has to have exactly 1 next element')

        # send to Lab
        self.next_elements[0].in_act(copy.deepcopy(self.data_to_send))

class Lab(GeneralSickProcessor):
    def __init__(self, delay_func, name, maxqueue):
        super().__init__(delay_func, name, maxqueue, 2)

    def put_in_queue(self, sick_human):
        self.queue.put(sick_human)

    def get_delay_specific(self, sick_human = None):
        return self.delay_func()

    def __call_in_act_for_half_probability(self):
        if len(self.next_elements) != 1:
            raise Exception('Lab has to have exactly 1 next element')

        if np.random.choice([True, False]):
            sick_to_change = copy.deepcopy(self.data_to_send)
            sick_to_change.sick_type = SickType.FIRST
            self.next_elements[0].in_act(sick_to_change)

    def out_act(self):
        super().out_act()

        if len(self.next_elements) != 1:
            raise Exception('LabReg has to have exactly 1 next element')

        # send to PathToHospital
        self.__call_in_act_for_half_probability()

class PathToHospital(GeneralSickProcessor):
    def __init__(self, delay_func, name, maxqueue, devices_amount=1):
        super().__init__(delay_func, name, maxqueue, devices_amount)

    def put_in_queue(self, sick_human):
        self.queue.put(sick_human)

    def get_delay_specific(self, sick_human = None):
        return self.delay_func()

    def out_act(self):
        super().out_act()

        if len(self.next_elements) != 1:
            raise Exception('PathToHospital has to have exactly 1 next element')

        # send to Hospital
        self.next_elements[0].in_act(copy.deepcopy(self.data_to_send))

if __name__ == '__main__':
    human_input = HumanInput('HumanInput')

    hospital = Hospital(lambda: Rand.exp(15), 'Hospital', 10)
    room = Room(lambda: Rand.uniform(3, 8), 'Room', 10)
    lab_reg = LabReg(lambda: Rand.erlang(4.5, 3), 'LabReg', 10)
    lab = Lab(lambda: Rand.erlang(4, 2), 'Lab', 10)
    path_to_hospital = PathToHospital(lambda: Rand.uniform(2, 5), 'PathToHospital', 10)

    human_input.next_elements = [hospital]
    hospital.next_elements = [room, lab_reg]
    room.next_elements = []
    lab_reg.next_elements = [lab]
    lab.next_elements = [path_to_hospital]
    path_to_hospital.next_elements = [hospital]

    model = Model([human_input, hospital, room, lab_reg, lab, path_to_hospital], debug=False)
    model.simulate(1000)

    print('\n')
    print(f'Mean delay for:\n\
        \t{human_input.name}: {human_input.get_mean_delay():.2f},\n\
        \t{hospital.name}: {hospital.get_mean_delay():.2f},\n\
        \t{room.name}: {room.get_mean_delay():.2f},\n\
        \t{lab_reg.name}: {lab_reg.get_mean_delay():.2f},\n\
        \t{lab.name}: {lab.get_mean_delay():.2f},\n\
        \t{path_to_hospital.name}: {path_to_hospital.get_mean_delay():.2f}')

    print('\n')
    sum_time_first = hospital.get_mean_delay() + room.get_mean_delay()
    print(f'Time for type FIRST: {sum_time_first}')

    sum_time_second = hospital.get_mean_delay() + lab_reg.get_mean_delay() + lab.get_mean_delay() + path_to_hospital.get_mean_delay()
    print(f'Time for type SECOND-THIRD cycle: {sum_time_second}')

    sum_time_third = hospital.get_mean_delay() + lab_reg.get_mean_delay() + lab.get_mean_delay()
    print(f'Time for type SECOND-THIRD end after lab: {sum_time_third}')

    print('\n')
    print(f'Between in act for lab: {lab.get_between_in_act():.2f}')


import cv2
import numpy as np
import face_recognition as facerec

def resize(img, size) :
  width = int(img.shape[1]*size)
  height = int(img.shape[0]*size)
  dimension = (width, height)
  return cv2.resize(img, dimension, interpolation=cv2.INTER_AREA)

image = facerec.load_image_file('sample images/IMG-1357.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = resize(image, 0.50)
image_test = facerec.load_image_file('sample images/parvse.JPG')
image_test = cv2.cvtColor(image_test, cv2.COLOR_BGR2RGB)
image_test = resize(image_test, 0.50)

facelocation_image = facerec.face_locations(image)[0]
encode_image = facerec.face_encodings(image)[0]
cv2.rectangle(image, (facelocation_image[3], facelocation_image[0]), (facelocation_image[1], facelocation_image[2]), (255, 0, 255), 3)

facelocation_imagetest = facerec.face_locations(image_test)[0]
encode_imagetest = facerec.face_encodings(image_test)[0]
cv2.rectangle(image_test, (facelocation_imagetest[3], facelocation_imagetest[0]), (facelocation_imagetest[1], facelocation_imagetest[2]), (255, 0, 255), 3)

cv2.imshow('train', image)
cv2.imshow('test', image_test)
cv2.waitKey(0)
cv2.destroyAllWindows()