import sys
import pygame
import math
from pygame import gfxdraw
import argparse
import cv2
import os

from easing_functions import *

from pycoral.adapters.common import input_size
from pycoral.adapters.detect import get_objects
from pycoral.utils.dataset import read_label_file
from pycoral.utils.edgetpu import make_interpreter
from pycoral.utils.edgetpu import run_inference
from pyky040 import pyky040
import threading
import socket
import time
import subprocess
import mido
port = mido.open_input()

synthMode = "Mix"
mixModeVal = 50
arpModeVal = 120
stepInArp = 0
objs = []
labels = []
lastTimeClicked = time.time()
lastTimeEncoderPressed = time.time()

def main():
    default_model_dir = os.path.join(
        os.path.dirname(__file__), 'models/bottleDetector')
    default_model = 'ssdlite_mobiledet_bottle_detector.tflite'
    default_labels = 'labels.txt'
    parser = argparse.ArgumentParser()
    parser.add_argument('--model', help='.tflite model path',
                        default=os.path.join(default_model_dir, default_model))
    parser.add_argument('--labels', help='label file path',
                        default=os.path.join(default_model_dir, default_labels))
    parser.add_argument('--top_k', type=int, default=3,
                        help='number of categories with highest score to display')
    parser.add_argument('--camera_idx', type=int,
                        help='Index of which video source to use. ', default=0)
    parser.add_argument('--threshold', type=float, default=0.1,
                        help='classifier score threshold')
    args = parser.parse_args()

    print('Loading {} with {} labels.'.format(args.model, args.labels))
    interpreter = make_interpreter(args.model)
    interpreter.allocate_tensors()
    global labels
    labels = read_label_file(args.labels)
    inference_size = input_size(interpreter)
    print("inference_size: ", inference_size)
    cap = cv2.VideoCapture(args.camera_idx)

    # Rotary encoder
    def encoderInc(scale_position):
        global synthMode
        global mixModeVal
        global arpModeVal
        wakeUp()
        if synthMode == "Mix":
            mixModeVal = min(mixModeVal+1, 100)
        if synthMode == "Arp":
            arpModeVal = min(arpModeVal+10, 1500)
            os.system("echo '" + str(arpModeVal) + ";" + "' | pdsend 3001")
        print('Encoder incremented mixVal: {}'.format(
            mixModeVal) + ' arpVal: {}'.format(arpModeVal))

    def encoderDec(scale_position):
        global synthMode
        global mixModeVal
        global arpModeVal
        wakeUp()
        if synthMode == "Mix":
            mixModeVal = max(mixModeVal-1, 0)
        if synthMode == "Arp":
            arpModeVal = max(1, arpModeVal - 10)
            os.system("echo '" + str(arpModeVal) + ";" + "' | pdsend 3001")
        print('Encoder decremented mixVal: {}'.format(
            mixModeVal) + ' arpVal: {}'.format(arpModeVal))

    def encoderClicked():
        global synthMode
        global lastTimeEncoderPressed

        lastTimeEncoderPressed = time.time()
        wakeUp()
        if synthMode == "Mix":
            synthMode = "Arp"
        else:
            synthMode = "Mix"
        if detectionPaused:
            resumeDetection()
        os.system("echo '" + synthMode + ";" + "' | pdsend 3002")
        print('Encoder clicked currentMode: {}'.format(synthMode))
    def wakeUp():
        global lastTimeClicked
        lastTimeClicked = time.time()
        if detectionPaused:
            resumeDetection()
    os.system("echo '" + synthMode + ";" + "' | pdsend 3002")
    encoder = pyky040.Encoder(CLK=4, DT=17, SW=27)
    encoder.setup(inc_callback=encoderInc,
                  dec_callback=encoderDec, sw_callback=encoderClicked)

    encoderThread = threading.Thread(target=encoder.watch)
    encoderThread.start()

    # getting messages from PD

    # inferencing
    pauseCondition = threading.Condition(threading.Lock())
    detectionPaused = False

    def pauseDetection():
        if notesPressed <= 0:
            os.system("echo '" + "Sleep" + ";" + "' | pdsend 3002")
            nonlocal detectionPaused
            detectionPaused = True
            pauseCondition.acquire()
            print("going to sleep")

    def resumeDetection():
        global lastTimeClicked
        lastTimeClicked = time.time()
        nonlocal detectionPaused
        if detectionPaused:
            os.system("echo '" + synthMode + ";" + "' | pdsend 3002")
            detectionPaused = False
            pauseCondition.notify()
            pauseCondition.release()
            print("waking up")

    # drawing GUI with pygame
    pygame.init()
    clock = pygame.time.Clock()

    # SO answer by Yannis Assael https://stackoverflow.com/questions/30578068/pygame-draw-anti-aliased-thick-line for drawing a antialiased line
    def drawAALine(X0, X1, color, strokeWidth):

        center_L1 = ((X0[0] + X1[0]) / 2, (X0[1] + X1[1]) / 2)
        length = lCircleRadius
        thickness = strokeWidth
        angle = math.atan2(X0[1] - X1[1], X0[0] - X1[0])
        UL = (center_L1[0] + (length / 2.) * math.cos(angle) - (thickness / 2.) * math.sin(angle),
              center_L1[1] + (thickness / 2.) * math.cos(angle) + (length / 2.) * math.sin(angle))
        UR = (center_L1[0] - (length / 2.) * math.cos(angle) - (thickness / 2.) * math.sin(angle),
              center_L1[1] + (thickness / 2.) * math.cos(angle) - (length / 2.) * math.sin(angle))
        BL = (center_L1[0] + (length / 2.) * math.cos(angle) + (thickness / 2.) * math.sin(angle),
              center_L1[1] - (thickness / 2.) * math.cos(angle) + (length / 2.) * math.sin(angle))
        BR = (center_L1[0] - (length / 2.) * math.cos(angle) + (thickness / 2.) * math.sin(angle),
              center_L1[1] - (thickness / 2.) * math.cos(angle) - (length / 2.) * math.sin(angle))
        pygame.gfxdraw.aapolygon(screen, (UL, UR, BR, BL), color)
        pygame.gfxdraw.filled_polygon(screen, (UL, UR, BR, BL), color)

    def drawAACircle(surface, pos, radius, color, strokeWidth, strokeColor):
        pygame.gfxdraw.aacircle(surface, pos[0], pos[1], radius, strokeColor)
        pygame.gfxdraw.filled_circle(
            surface, pos[0], pos[1], radius, strokeColor)
        pygame.gfxdraw.aacircle(
            surface, pos[0], pos[1], radius-strokeWidth, color)
        pygame.gfxdraw.filled_circle(
            surface,  pos[0], pos[1], radius-strokeWidth, color)

    size = width, height = 480, 480
    backgroundColor = (0, 0, 0)
    primaryColor = (255, 255, 255)
    center = (round(width/2), round(height/2))
    circleFactor = (math.pi*2) / 640
    sCircleStroke = 3
    sCircleRadius = 35
    lCircleStroke = 3
    lCircleRadius = round(width/2 - sCircleRadius)
    colorIdArray = [(255, 202, 98), (200, 11, 47), (196, 196, 196), (255, 230, 0), (255, 98, 98),
                    (24, 242, 125), (89, 106, 255), (237, 48, 139), (201, 255, 132), (19, 136, 0)]
    screen = pygame.display.set_mode(size)
    screen.fill(backgroundColor)
    background = pygame.Surface((width, height))
    background.fill(backgroundColor)
    drawAACircle(background, center, lCircleRadius,
                 backgroundColor, lCircleStroke, primaryColor)
    notesPressed = 0
    imageDir = os.path.join(
        os.path.dirname(__file__), 'images')
    sleepImage = pygame.image.load(imageDir + "/sleeping.png")
    sleepImageSize = sleepImage.get_rect().size

    mixImage = pygame.image.load(imageDir + "/mix.png")
    mixImageSize = mixImage.get_rect().size

    recycleImage = pygame.image.load(imageDir + "/recycle.png")
    recycleImageSize = recycleImage.get_rect().size

    def update_fps():
        fps = str(round(clock.get_fps()))
        print("fps: ", fps)

    def getPosOnCircle(position):
        x = lCircleRadius * math.cos(position * circleFactor) + center[0]
        y = lCircleRadius * math.sin(position * circleFactor) + center[1]
        return (round(x), round(y))

    def drawDetectionCircle(obj):
        bbox = obj.bbox.scale(2, 1.5)
        pos = getPosOnCircle((bbox.xmin+bbox.xmax)/2)
        circleColor = colorIdArray[obj.id]
        if synthMode == "Mix":
            drawAALine(pos, center, primaryColor, lCircleStroke/2)
        drawAACircle(screen, pos, round(sCircleRadius - sCircleRadius / 2 +  (sCircleRadius * (obj.score - mixModeVal/100))), circleColor,
                     sCircleStroke, backgroundColor)

    def drawArpModeLine():
        xPosition = (stepInArp / 16) * (inference_size[0]*2)
        posOnCircle = getPosOnCircle(xPosition)
        drawAALine(posOnCircle, center, primaryColor, lCircleStroke/2)

    animationLength = 10
    animationArray = BackEaseInOut(start=0, end=10, duration=animationLength)
    posInAnimation = 0

    def drawStateModal():
        if (time.time() - lastTimeEncoderPressed) < 1:
            if synthMode == "Mix":
                screen.blit(
                    mixImage, (center[0]-(mixImageSize[0]/2), center[1]-(mixImageSize[1]/2)))
            if synthMode == "Arp":
                screen.blit(
                    recycleImage, (center[0]-(recycleImageSize[0]/2), center[1]-(recycleImageSize[1]/2)))
        if detectionPaused:
            screen.blit(
                sleepImage, (center[0]-(sleepImageSize[0]/2), center[1]-(sleepImageSize[1]/2)))

    def drawMiddleCircle():
        if notesPressed > 0:
            nonlocal posInAnimation
            posInAnimation = min(posInAnimation + 1, animationLength)
        else:
            posInAnimation = max(posInAnimation - 1, 0)
        drawAACircle(screen, center, sCircleRadius + round(animationArray.ease(
            posInAnimation)), backgroundColor, lCircleStroke, primaryColor)

    def mainDrawLoop():
        while 1:
            screen.blit(background, (0, 0))
            if not detectionPaused and (time.time() - lastTimeClicked) > 60:
                pauseDetection()

            for msg in port.iter_pending():
                nonlocal notesPressed
                if msg.type == "note_on":
                    notesPressed += 1
                    resumeDetection()
                if msg.type == "note_off":
                    notesPressed = max(notesPressed - 1, 0)
                    resumeDetection()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
            if not detectionPaused:
                for index, obj in enumerate(objs):
                    drawDetectionCircle(obj)

                if synthMode == "Arp":
                    drawArpModeLine()
                drawMiddleCircle()
                clock.tick(60)
            drawStateModal()
            if detectionPaused:
                clock.tick(1)

            pygame.display.flip()
        pygame.quit()

    mainDrawLoopThread = threading.Thread(target=mainDrawLoop)
    mainDrawLoopThread.start()
    time.sleep(10)
    print("Starting PD ___________________")
    pathToPD = 'pd'
    pathToPatch = os.path.join(os.path.dirname(__file__), '../pureDataPatch/Main.pd')
    subprocess.Popen([pathToPD, '-nogui', '-noadc', '-jack', '-rt', pathToPatch])
    pauseDetection()
    time.sleep(10)
    def detectObjs():
        while cap.isOpened():
            with pauseCondition:
                while detectionPaused:
                    pauseCondition.wait()
                    print("after wait")

            ret, frame = cap.read()
            if not ret:
                break
            cv2_im = frame

            cv2_im_rgb = cv2.cvtColor(cv2_im, cv2.COLOR_BGR2RGB)
            cv2_im_rgb = cv2.resize(cv2_im_rgb, inference_size)
            run_inference(interpreter, cv2_im_rgb.tobytes())
            global objs
            objs = get_objects(interpreter, mixModeVal/100)[:args.top_k]
            height, width, channels = cv2_im.shape
            scale_x, scale_y = width / \
                inference_size[0], height / inference_size[1]
            foundObjs = ""
            totalDistance = 0
            for obj in objs:
                bbox = obj.bbox.scale(scale_x, scale_y)
                x0 = round(bbox.xmin)
                x1 = round(bbox.xmax)
                totalDistance += round(bbox.ymax)
                position = ((x0+x1)/2) / 640  # image_width
                foundObjs += str(obj.id) + " " + str(position) + " "
            avgDist = round((min(180, max(0, (640-totalDistance/max(1, len(objs))-160)))/180)*100)/100
            os.system("echo '" + str(avgDist) + ";" + "' | pdsend 3004")
            os.system("echo '" + str(foundObjs) + ";" + "' | pdsend 3000")
        # append_objs_to_img(cv2_im, inference_size, objs, labels)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

        cap.release()

    detectObjsThread = threading.Thread(target=detectObjs)
    detectObjsThread.start()

    os.system("echo '" + "120" + ";" + "' | pdsend 3001")

    def serverWatcher():
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_address = ('localhost', 3003)
        print(f'starting up on {server_address[0]} port {server_address[1]}')

        sock.bind(server_address)
        sock.listen(1)
        while True:
            print('waiting for a connection')
            connection, client_address = sock.accept()

            try:
                print('client connected:', client_address)
                os.system("echo '" + synthMode + ";" + "' | pdsend 3002")
                while True:
                    data = connection.recv(16)
                    data = data.decode("utf-8")
                    data = data.replace('\n', '').replace(
                        '\t', '').replace('\r', '').replace(';', '')
                    global stepInArp
                    if data != '':
                        stepInArp = int(data)
                    if not data:
                        break
            finally:
                connection.close()
    watcherThread = threading.Thread(target=serverWatcher)
    watcherThread.start()

if __name__ == '__main__':
    main()


from io import open
import pathlib
import shutil

# Abrir archivos
ruta = str(pathlib.Path().absolute()) + "/fichero_texto.txt"
print(ruta)

archivo = open(ruta, "a+")

# Escribir
archivo.write("****** VIVA LA INTELIGENCIA ARTIFICIAL ******")

# Cerrar archivo
archivo.close()

# Abrir archivos 2
ruta = str(pathlib.Path().absolute()) + "/fichero_texto.txt"
archivo_lectura = open(ruta, "r")

# Leer contenido
contenido = archivo_lectura.read()
print(contenido)

# Leer contenido y guardar en línea
lista = archivo_lectura.readlines()
archivo_lectura.close()

print(lista)

for frase in lista:
    lista_frase = frase.split()
    print("- " + frase.upper())

# Copiar
ruta_original = str(pathlib.Path().absolute()) + "/fichero_texto.txt"
ruta_nueva = str(pathlib.Path().absolute()) + "/fichero_texto.txt"
ruta_alternativa = "../07"
shutil.copyfile(ruta_original, ruta_nueva)

# Mover archivos
ruta_original = str(pathlib.Path().absolute()) + "/fichero_copiado.txt"
ruta_nueva = str(pathlib.Path().absolute()) + "/fichero_copiado.txt"

shutil.move(ruta_original, ruta_nueva)

# Eliminar archivos
import os

ruta_nueva = str(pathlib.Path().absolute()) + "/fichero_copiado.txt"
os.remove(ruta_nueva)

# Comprobar si existe
import os.path
print(os.path.abspath("./"))

# print(os.path.abspath("../"))

ruta_comprobar = os.path.abspath("./") + "/fichero_texto.txt"
ruta_comprobar = "./fichero_texto.txt"

if os.path.isfile(ruta_comprobar):
    print("El archivo no existe")
else:
    print("El archivo no existe")


import numpy as np
import cv2
import sys
import glob
import os

if __name__ == '__main__':
    dir = sys.argv[1]
    save_name = sys.argv[2]

    dir = os.path.join(dir, "[1-9].png")
    print(dir)
    imgs_path = glob.glob(dir)
    print(imgs_path)

    img_list = []
    for path in imgs_path:
        img = cv2.imread(path)
        img_list.append(img)

    height, width, _ = img_list[0].shape

    buffer = np.zeros((3 * height, 3 * width, 3), dtype=img_list[0].dtype)

    for i in range(3):
        for j in range(3):
            img = img_list[i * 3 + j]
            img[0:height, 0] = 0
            img[0, 0:width] = 0

            img[0:height, (width - 1)] = 0
            img[(height - 1), 0:width] = 0

            buffer[i * height:(i + 1) * height, j * width: (j + 1) * width, :] = img

    cv2.imwrite(save_name, buffer)


import os
import numpy as np
import cv2
from PIL import Image

recognizer = cv2.face.LBPHFaceRecognizer_create()

path = '.\Faces\subhs'

def list_img(path):

	img_path = [ os.path.join(path, f) for f in os.listdir(path) ]

	faces = []
	IDs = []

	for img in img_path:

		face=Image.open(img).convert('L')

		face = np.array(face, 'uint8')

		ID = int(os.path.split(img)[-1].split(".")[0])

		faces.append(face)
		IDs.append(ID)

	# print(faces)
	# print(IDs)
	return np.array(IDs), faces

Ids, faces1 = list_img(path)

# print(Ids)
# print(faces)

recognizer.train(faces1,Ids)

recognizer.write('trainr.yml')


import sys, os
if (sys.version_info > (3, 0)):
    import pymysql as mysql
    from lib.mylogger import MyLogger
else:
    import MySQLdb as mysql
    from mylogger import MyLogger

import ipdb
from lxml import etree
import requests

from settings import *

class ProxyCrawler(object):
    _headers = {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Accept-Encoding": "gzip, deflate, br",
        "Connection": "keep-alive"
    }
    _timeout = 60
    _proxy = []
    _anonimity = {
        'transparent': 0,
        'elite proxy': 1,
        'anonymous': 2
    }
    _proxy_list_website = [
        'https://free-proxy-list.net/',
        'https://www.sslproxies.org/'
    ]

    def __init__(self):
        self.mysql = mysql.connect(HOST, USER, PASSWORD, 'proxy_server')
        self.session = requests.Session()
        self.logger = MyLogger(name='proxy', prefix='proxy')

    def run(self):
        for website in self._proxy_list_website:
            self.fetch_proxy(website)

    def get(self, url):
        try:
            #response = self.session.get(url, headers=self._headers, timeout=self._timeout)
            response = requests.get(url, timeout=self._timeout)
        except requests.exceptions.ReadTimeout:
            self.logger.debug('[!] timeout')
            print('[-] requests timeout.')
        return response

    def fetch_proxy(self, website):
        response = self.get(website)
        tree = etree.HTML(response.content)
        proxy_elements = tree.xpath('.//tr')
        cursor = self.mysql.cursor()
        for element in proxy_elements[1:]:
           proxy_info = [child.text for child in element.getchildren()[:-1]]
           try:
               proxy_info[4] = self._anonimity[proxy_info[4]]
           except:
               continue
           if proxy_info[5] == 'yes':
               proxy_info[5] = 1
           else:
               proxy_info[5] = 0
           if proxy_info[6] == 'yes':
               proxy_info[6] = 1
           else:
               proxy_info[6] = 0
           try:
               cursor.execute('insert ignore into `ssl_proxy` (`ip`, `port`, `code`, `country`, `anonimity`, `google`, `https`, `last_check`) values (INET6_ATON(%s), %s, %s, %s, %s, %s, %s, now())', proxy_info)
               self.logger.info('[+] {}'.format(proxy_info))
           except Exception as e:
               self.logger.warning('[-] {}'.format(proxy_info))
               continue
        self.mysql.commit()
        cursor.close()

if __name__ == '__main__':
    crawler =  ProxyCrawler()
    crawler.run()


import re
from pathlib import Path

from invoke import Exit, task

@task
def release(ctx):
    toml = Path("pyproject.toml").read_text()
    match = re.search(r'version = "(.*?)"', toml)
    if match:
        version = match.group(1)
        print(f"Releasing {version}")
        ctx.run(f"git tag {version}", echo=True)
        ctx.run(f"git push origin {version}", echo=True)
    else:
        print("Failed to find version in the pyproject.toml")

def run_test_cmd(ctx, cmd) -> int:
    print("=" * 79)
    print(f"> {cmd}")
    return ctx.run(cmd, warn=True).exited

@task
def test(ctx):
    failed_commands = []

    # Uncomment when moved away from Travis. Now it fails without clear reason
    # if run_test_cmd(ctx, "pre-commit run --all-files"):
    #     failed_commands.append("Pre commit hooks")

    if run_test_cmd(ctx, "mypy openapi_to_fastapi"):
        failed_commands.append("Mypy")

    if run_test_cmd(ctx, "pytest"):
        failed_commands.append("Unit tests")

    if run_test_cmd(ctx, "flake8"):
        failed_commands.append("flake8")

    if failed_commands:
        msg = "Errors: " + ", ".join(failed_commands)
        raise Exit(message=msg, code=len(failed_commands))


import time
from cereal import car
from common.numpy_fast import clip, interp
from common.realtime import DT_CTRL
from selfdrive.controls.lib.drive_helpers import CONTROL_N, apply_deadzone
from selfdrive.controls.lib.pid import PIDController
from selfdrive.modeld.constants import T_IDXS

LongCtrlState = car.CarControl.Actuators.LongControlState

LINEAL = 1
TRAPEZOIDAL = 5
REACTIVO = 9

def long_control_state_trans(CP, active, long_control_state, v_ego, v_target,
                            v_target_1sec, brake_pressed, cruise_standstill):
  # Ignore cruise standstill if car has a gas interceptor
  cruise_standstill = cruise_standstill and not CP.enableGasInterceptor
  accelerating = v_target_1sec > v_target
  planned_stop = (v_target < CP.vEgoStopping and
                  v_target_1sec < CP.vEgoStopping and
                  not accelerating)
  stay_stopped = (v_ego < CP.vEgoStopping and
                  (brake_pressed or cruise_standstill))
  stopping_condition = False  # planned_stop or stay_stopped

  starting_condition = (v_target_1sec > CP.vEgoStarting and
                        accelerating and
                        not cruise_standstill and
                        not brake_pressed)
  started_condition = v_ego > CP.vEgoStarting

  if not active:
    long_control_state = LongCtrlState.off

  else:
    if long_control_state in (LongCtrlState.off, LongCtrlState.pid):
      long_control_state = LongCtrlState.pid
      if stopping_condition:
        long_control_state = LongCtrlState.stopping

    elif long_control_state == LongCtrlState.stopping:
      if starting_condition and CP.startingState:
        long_control_state = LongCtrlState.starting
      elif starting_condition:
        long_control_state = LongCtrlState.pid

    elif long_control_state == LongCtrlState.starting:
      if stopping_condition:
        long_control_state = LongCtrlState.stopping
      elif started_condition:
        long_control_state = LongCtrlState.pid

  return long_control_state

class planner:
  # vel_vector: vector de velocidades deseadas
  # time_vector: vector de tiempos de cambio deseados
  # tipo: tipo de suavizado y transición entre velocidades
  def __init__(self, tipo):
    # --- Variables
    self.perfil = 0
    self.fase = 0
    self.tipo = tipo
    self.vel_vector = []
    self.time_vector = []
    self.separator = ','
    if self.tipo == 5:
      self.archivo = '../controls/tests/perfil_trapezoidal.csv'
      with open(self.archivo, 'r') as _archivo:
        for linea in _archivo:
          linea = linea.rstrip()
          lista = linea.split(self.separator)
          self.time_vector.append(float(lista[0]))
          self.vel_vector.append(float(lista[1]))
    # Velocidades y aceleraciones
    self.enable = False
    self.t_a = 10000.0
    self.acc_max = 0.5
    self.stage = 0
    self.cont = 1
    self.change_stage = False
    self.t_ini = (time.time_ns()-self.t_ini)/1000000000.0
    self.v_target = 5.5  # m/s
    self.v_ini = 0.0
    self.t_1 = 0.0
    self.t_2 = 0.0
    self.tau = self.v_target/self.acc_max

  # time: tiempo actual de simulación en segundos
  def update(self, t, CS):
    if CS.rightBlinker and self.perfil == 0:
      self.enable = True
      self.perfil = 1
      self.fase = 1
      self.t_1 = t
    if CS.rightBlinker and self.fase == 0:
      self.enable = True
      self.fase = -1
      self.t_2 = t
    if CS.leftBlinker and self.perfil == 0:
      self.enable = False
    if self.tipo == TRAPEZOIDAL and self.enable:
      vel = self.read_trapezoidal(t-self.t_ini)
    elif self.tipo == REACTIVO and self.enable:
      vel = self.set_speed(t-self.t_ini, CS)
    else:
      vel = 0.0
    return vel, self.enable

  # time: tiempo actual de simulación en segundos
  def read_trapezoidal(self, t):
    longitud = len(self.time_vector)
    if t > self.time_vector[self.cont] and t < self.time_vector[longitud-1]:
      self.cont += 1
    return self.vel_vector[self.cont]

  def set_speed(self, t, CS):
    vel = CS.vEgo
    if self.perfil == 1:
      if self.fase == 1:
        if (t-self.t_1 <= self.tau):
          vel = self.acc_max*(t-self.t_1)
        else:
          self.fase = 0
      if self.fase == -1:
        if (t-self.t_2 <= self.tau):
          vel = self.v_target-self.acc_max*(t-self.t_2)
    if vel > self.v_target:
      vel = self.v_target
    elif vel < self.v_ini:
      vel = self.v_ini
    self.cont += 1
    return vel

class LongControl:
  def __init__(self, CP):
    self.CP = CP
    self.long_control_state = LongCtrlState.off  # initialized to off
    self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
                              (CP.longitudinalTuning.kiBP,
                              CP.longitudinalTuning.kiV),
                              k_f=CP.longitudinalTuning.kf, rate=1 / DT_CTRL)
    self.v_pid = 0.0
    self.last_output_accel = 0.0
    self.vpid_flag = False
    self.t_ini = time.time_ns()
    self.vel_profile = planner(REACTIVO)

  def reset(self, v_pid):
    """Reset PID controller and change setpoint"""
    self.pid.reset()
    self.v_pid = v_pid
    self.vpid_flag = False

  def update(self, active, CS, long_plan, accel_limits, t_since_plan):
    """Update longitudinal control. This updates the state machine and runs a PID loop"""
    # Interp control trajectory
    speeds = long_plan.speeds
    if len(speeds) == CONTROL_N:
      v_target_now = interp(t_since_plan, T_IDXS[:CONTROL_N], speeds)
      a_target_now = interp(
          t_since_plan, T_IDXS[:CONTROL_N], long_plan.accels)

      v_target_lower = interp(
          self.CP.longitudinalActuatorDelayLowerBound + t_since_plan, T_IDXS[:CONTROL_N], speeds)
      a_target_lower = 2 * (v_target_lower - v_target_now) / \
          self.CP.longitudinalActuatorDelayLowerBound - a_target_now

      v_target_upper = interp(
          self.CP.longitudinalActuatorDelayUpperBound + t_since_plan, T_IDXS[:CONTROL_N], speeds)
      a_target_upper = 2 * (v_target_upper - v_target_now) / \
          self.CP.longitudinalActuatorDelayUpperBound - a_target_now

      v_target = min(v_target_lower, v_target_upper)
      a_target = min(a_target_lower, a_target_upper)

      v_target_1sec = interp(self.CP.longitudinalActuatorDelayUpperBound +
                              t_since_plan + 1.0, T_IDXS[:CONTROL_N], speeds)
    else:
      v_target = 0.0
      v_target_now = 0.0
      v_target_1sec = 0.0
      a_target = 0.0

    self.pid.neg_limit = accel_limits[0]
    self.pid.pos_limit = accel_limits[1]

    output_accel = self.last_output_accel
    # Diferencial de tiempo en segundos
    dt_ini = (time.time_ns()-self.t_ini)/1000000000.0

    self.long_control_state = long_control_state_trans(self.CP, active, self.long_control_state, CS.vEgo,
                                                        v_target, v_target_1sec, CS.brakePressed,
                                                        CS.cruiseState.standstill)

    if self.long_control_state == LongCtrlState.off:
      self.reset(CS.vEgo)
      output_accel = 0.

    elif self.long_control_state == LongCtrlState.stopping:
      if output_accel > self.CP.stopAccel:
        output_accel = min(output_accel, 0.0)
        output_accel -= self.CP.stoppingDecelRate * DT_CTRL
      self.reset(CS.vEgo)

    elif self.long_control_state == LongCtrlState.starting:
      output_accel = self.CP.startAccel
      self.reset(CS.vEgo)

    elif self.long_control_state == LongCtrlState.pid:
      v_pid, self.vpid_flag = self.vel_profile.update(dt_ini, CS)
      if self.vpid_flag:
        self.v_pid = v_pid
      else:
        self.v_pid = v_target_now

      # Toyota starts braking more when it thinks you want to stop
      # Freeze the integrator so we don't accelerate to compensate, and don't allow positive acceleration
      # TODO too complex, needs to be simplified and tested on toyotas
      prevent_overshoot = not self.CP.stoppingControl and CS.vEgo < 1.5 and v_target_1sec < 0.7 and v_target_1sec < self.v_pid
      deadzone = interp(CS.vEgo, self.CP.longitudinalTuning.deadzoneBP,
                        self.CP.longitudinalTuning.deadzoneV)
      freeze_integrator = prevent_overshoot

      error = self.v_pid - CS.vEgo
      error_deadzone = apply_deadzone(error, deadzone)
      output_accel = self.pid.update(error_deadzone, speed=CS.vEgo,
                                      feedforward=a_target,
                                      freeze_integrator=freeze_integrator)

    self.last_output_accel = clip(
        output_accel, accel_limits[0], accel_limits[1])

    return self.last_output_accel


from os import environ

import pandas as pd
import numpy as np
import pymongo

from logger import logger
from app.models import MISSING_MESSAGE

class HSBCModel:
    def __init__(self, document):
        self.df = pd.read_excel(document)
        self.__client = pymongo.MongoClient(environ.get("MONGO_URI"))
        self.__db = self.__client.robin_hood
        self.collection = self.__db[environ.get("HSBC_COLLECTION")]
        self.statments_collection = self.__db[
            environ.get("ACCOUNT_STATMENT_COLLECTION")
        ]
        self.mandatory_columns = [
            "Nombre de la cuenta",
            "Número de cuenta",
            "Nombre del banco",
            "Divisa",
            "País",
            "Estatus de la cuenta",
            "Tipo de cuenta",
            "Referencia del Banco",
            "Narrativa adicional",
            "Referencia del cliente",
            "Tipo TRN",
            "Importe del abono",
            "Importe del cargo",
            "Saldo",
            "Fecha posterior",
        ]

    def __verified_accounts(self):
        is_valid = True
        missing_columns = []
        columns = list(self.df.columns)
        for column in columns:
            if column not in self.mandatory_columns:
                is_valid = False
                missing_columns.append(column)

        return is_valid, missing_columns

    def __clean_data(self):
        self.df["Importe del cargo"] = self.df["Importe del cargo"].replace(np.nan, 0)
        self.df["Importe del abono"] = self.df["Importe del abono"].replace(np.nan, 0)
        self.df["Fecha posterior"] = self.df["Fecha posterior"].apply(
            lambda row: str(row) if row is not None else ""
        )
        self.df = self.df.rename(
            columns={"País": "Pais", "Número de cuenta": "Numero de cuenta"}
        )

    def __remove_trash_key(self, item: dict):
        if "index" in item:
            item.pop("index")
        elif "level_0" in item:
            item.pop("level_0")
        return item

    def __change_key_name(self, item: dict):
        item["divisa"] = item.pop("Divisa")
        item["estatus"] = item.pop("Estatus de la cuenta")
        item["fecha"] = item.pop("Fecha posterior")
        item["abono"] = str(item.pop("Importe del abono"))
        item["cargo"] = str(item.pop("Importe del cargo"))
        item["descripcion"] = item.pop("Narrativa adicional")
        item["nombre"] = item.pop("Nombre de la cuenta")
        item["banco"] = item.pop("Nombre del banco")
        item["cuenta"] = str(item.pop("Numero de cuenta"))
        item["pais"] = item.pop("Pais")
        item["referencia_banco"] = str(item.pop("Referencia del Banco"))
        item["referencia_cliente"] = item.pop("Referencia del cliente")
        item["saldo"] = str(item.pop("Saldo"))
        item["tipo_trn"] = item.pop("Tipo TRN")
        item["tipo_cuenta"] = item.pop("Tipo de cuenta")
        return item

    def __get_account_statments(self, item: dict):
        account = {}
        account["cliente"] = str(item["Referencia del cliente"])
        account["empresa"] = ""
        account["banco"] = item["Nombre del banco"]
        account["cuenta"] = str(item["Numero de cuenta"])
        account["descripcion"] = item["Narrativa adicional"]
        account["referencia"] = str(item["Referencia del Banco"])
        account["fecha"] = item["Fecha posterior"]
        account["deposito"] = str(item["Importe del abono"])
        account["retiro"] = str(item["Importe del cargo"])
        account["saldo"] = str(item["Saldo"])
        return account

    def get_account_statment_dict(self):
        data = self.df
        data.reset_index(inplace=True)
        statment = data.to_dict("records")
        statment = list(map(self.__remove_trash_key, statment))
        statment = list(map(self.__change_key_name, statment))
        return statment

    def get_statment_dict(self, bank, client, company):
        data = self.df
        data.reset_index(inplace=True)
        statments = data.to_dict("records")
        statments = list(map(self.__get_account_statments, statments))
        return statments

    def save_statments(self, bank, client, company):
        is_valid, missing_columns = self.__verified_accounts()
        if not is_valid:
            raise Exception(MISSING_MESSAGE.format(str(missing_columns)))
        self.__clean_data()
        try:
            self.collection.insert_many(self.get_account_statment_dict())
            self.statments_collection.insert_many(
                self.get_statment_dict(bank, client, company)
            )
            return True
        except Exception as e:
            logger.error(e)
            return False


from __future__ import print_function
import argparse
import os
import random
import numpy as np
import torch
import torch.nn.parallel
import torch.optim as optim
import torch.utils.data
from dataset.dataset import RIODatasetSceneGraph, collate_fn_vaegan_points
from model.VAE import VAE
from model.atlasnet import AE_AtlasNet
from model.discriminators import BoxDiscriminator, ShapeAuxillary
from model.losses import bce_loss
from helpers.util import bool_flag

from model.losses import calculate_model_losses

import torch.nn.functional as F
import json

from tensorboardX import SummaryWriter

parser = argparse.ArgumentParser()
# standard hyperparameters, batch size, learning rate, etc
parser.add_argument('--batchSize', type=int, default=8, help='input batch size')
parser.add_argument('--lr', type=float, help='learning rate', default=0.0001)
parser.add_argument('--nepoch', type=int, default=101, help='number of epochs to train for')

# paths and filenames
parser.add_argument('--outf', type=str, default='checkpoint', help='output folder')
parser.add_argument('--model', type=str, default='', help='model path')
parser.add_argument('--dataset', required=False, type=str, default="./GT", help="dataset path")
parser.add_argument('--dataset_3RScan', type=str, default='', help="dataset path of 3RScan")
parser.add_argument('--label_file', required=False, type=str, default='labels.instances.align.annotated.ply', help="label file name")
parser.add_argument('--logf', default='logs', help='folder to save tensorboard logs')
parser.add_argument('--exp', default='./experiments/layout_test', help='experiment name')
parser.add_argument('--path2atlas', default="./experiments/model_36.pth", type=str)

# GCN parameters
parser.add_argument('--residual', type=bool_flag, default=False, help="residual in GCN")
parser.add_argument('--pooling', type=str, default='avg', help="pooling method in GCN")

# dataset related
parser.add_argument('--large', default=True, type=bool_flag, help='large set of shape class labels')
parser.add_argument('--use_splits', default=True, type=bool_flag, help='Set to true if you want to use splitted training data')
parser.add_argument('--use_scene_rels', type=bool_flag, default=True, help="connect all nodes to a root scene node")
parser.add_argument('--with_points', type=bool_flag, default=False, help="if false and with_feats is false, only predicts layout."
                                                                         "If true always also loads pointsets. Notice that this is much "
                                                                         "slower than only loading the save features. Therefore, "
                                                                         "the recommended setting is with_points=False and with_feats=True.")
parser.add_argument('--with_feats', type=bool_flag, default=True, help="if true reads latent point features instead of pointsets."
                                                                       "If not existing, they get generated at the beginning.")
parser.add_argument('--shuffle_objs', type=bool_flag, default=True, help="shuffle objs of a scene")
parser.add_argument('--num_points', type=int, default=1024, help='number of points for each object')
parser.add_argument('--rio27', default=False, type=bool_flag)
parser.add_argument('--use_canonical', default=True, type=bool_flag)
parser.add_argument('--with_angles', default=True, type=bool_flag)
parser.add_argument('--num_box_params', default=6, type=int)
parser.add_argument('--crop_floor', default=False, type=bool_flag)

# training and architecture related
parser.add_argument('--workers', type=int, help='number of data loading workers', default=4)
parser.add_argument('--overfiting_debug', type=bool_flag, default=False)
parser.add_argument('--weight_D_box', default=0.1, type=float, help="Box Discriminator")
parser.add_argument('--with_changes', default=True, type=bool_flag)
parser.add_argument('--with_shape_disc', default=True, type=bool_flag)
parser.add_argument('--with_manipulator', default=True, type=bool_flag)

parser.add_argument('--replace_latent', default=True, type=bool_flag)
parser.add_argument('--network_type', default='shared', choices=['dis', 'sln', 'mlp', 'shared'], type=str)

args = parser.parse_args()
print(args)

def train():
    """ Train the network based on the provided argparse parameters
    """
    args.manualSeed = random.randint(1, 10000)  # optionally fix seed 7494
    print("Random Seed: ", args.manualSeed)

    print(torch.__version__)

    random.seed(args.manualSeed)
    torch.manual_seed(args.manualSeed)

    # prepare pretrained AtlasNet model, later used to convert pointsets to a shape feature
    saved_atlasnet_model = torch.load(args.path2atlas)
    point_ae = AE_AtlasNet(num_points=1024, bottleneck_size=128, nb_primitives=25)
    point_ae.load_state_dict(saved_atlasnet_model, strict=True)
    if torch.cuda.is_available():
        point_ae = point_ae.cuda()
    point_ae.eval()

    # instantiate scene graph dataset for training
    dataset = RIODatasetSceneGraph(
            root=args.dataset,
            root_3rscan=args.dataset_3RScan,
            label_file=args.label_file,
            npoints=args.num_points,
            path2atlas=args.path2atlas,
            split='train_scans',
            shuffle_objs=(args.shuffle_objs and not args.overfiting_debug),
            use_points=args.with_points,
            use_scene_rels=args.use_scene_rels,
            with_changes=args.with_changes,
            vae_baseline=args.network_type == 'sln',
            with_feats=args.with_feats,
            large=args.large,
            atlas=point_ae,
            seed=False,
            use_splits=args.use_splits,
            use_rio27=args.rio27,
            use_canonical=args.use_canonical,
            crop_floor=args.crop_floor,
            center_scene_to_floor=args.crop_floor,
            recompute_feats=False)

    collate_fn = collate_fn_vaegan_points
    # instantiate data loader from dataset
    dataloader = torch.utils.data.DataLoader(
            dataset,
            batch_size=args.batchSize,
            collate_fn=collate_fn,
            shuffle=(not args.overfiting_debug),
            num_workers=int(args.workers))

    # number of object classes and relationship classes
    num_classes = len(dataset.classes)
    num_relationships = len(dataset.relationships)

    try:
        os.makedirs(args.outf)
    except OSError:
        pass
    # instantiate the model
    model = VAE(type=args.network_type, vocab=dataset.vocab, replace_latent=args.replace_latent,
                with_changes=args.with_changes, residual=args.residual, gconv_pooling=args.pooling,
                with_angles=args.with_angles, num_box_params=args.num_box_params)
    if torch.cuda.is_available():
        model = model.cuda()
    # instantiate a relationship discriminator that considers the boxes and the semantic labels
    # if the loss weight is larger than zero
    # also create an optimizer for it
    if args.weight_D_box > 0:
        boxD = BoxDiscriminator(6, num_relationships, num_classes)
        optimizerDbox = optim.Adam(filter(lambda p: p.requires_grad, boxD.parameters()), lr=args.lr, betas=(0.9, 0.999))
        boxD.cuda()
        boxD = boxD.train()

    # instantiate auxiliary discriminator for shape and a respective optimizer
    shapeClassifier = ShapeAuxillary(128, len(dataset.cat))
    shapeClassifier = shapeClassifier.cuda()
    shapeClassifier.train()
    optimizerShapeAux = optim.Adam(filter(lambda p: p.requires_grad, shapeClassifier.parameters()), lr=args.lr, betas=(0.9, 0.999))

    # initialize tensorboard writer
    writer = SummaryWriter(args.exp + "/" + args.logf)

    # optimizer for model
    params = filter(lambda p: p.requires_grad,list(model.parameters()) )
    optimizer = optim.Adam(params, lr=args.lr)

    print("---- Model and Dataset built ----")

    if not os.path.exists(args.exp + "/" + args.outf):
        os.makedirs(args.exp + "/" + args.outf)

    # save parameters so that we can read them later on evaluation
    with open(os.path.join(args.exp, 'args.json'), 'w') as f:
        json.dump(args.__dict__, f, indent=2)
    print("Saving all parameters under:")
    print(os.path.join(args.exp, 'args.json'))

    optimizer.step()
    torch.autograd.set_detect_anomaly(True)
    counter = 0

    print("---- Starting training loop! ----")
    for epoch in range(0, args.nepoch):
        print('Epoch: {}/{}'.format(epoch, args.nepoch))

        for i, data in enumerate(dataloader, 0):
            # skip invalid data
            if data == -1:
                continue

            try:
                enc_objs, enc_triples, enc_tight_boxes, enc_objs_to_scene, enc_triples_to_scene = data['encoder']['objs'],\
                            data['encoder']['tripltes'], data['encoder']['boxes'], data['encoder']['obj_to_scene'], data['encoder']['tiple_to_scene']

                if args.with_feats:
                    encoded_enc_points = data['encoder']['feats']
                    encoded_enc_points = encoded_enc_points.cuda()
                elif args.with_points:
                    enc_points = data['encoder']['points']
                    enc_points = enc_points.cuda()

                dec_objs, dec_triples, dec_tight_boxes, dec_objs_to_scene, dec_triples_to_scene = data['decoder']['objs'],\
                            data['decoder']['tripltes'], data['decoder']['boxes'], data['decoder']['obj_to_scene'], data['decoder']['tiple_to_scene']

                if 'feats' in data['decoder']:
                    encoded_dec_points = data['decoder']['feats']
                    encoded_dec_points = encoded_dec_points.cuda()
                else:
                    if 'points' in data['decoder']:
                        dec_points = data['decoder']['points']
                        dec_points = dec_points.cuda()

                # changed nodes
                missing_nodes = data['missing_nodes']
                manipulated_nodes = data['manipulated_nodes']

            except Exception as e:
                print('Exception', str(e))
                continue

            enc_objs, enc_triples, enc_tight_boxes = enc_objs.cuda(), enc_triples.cuda(), enc_tight_boxes.cuda()
            dec_objs, dec_triples, dec_tight_boxes = dec_objs.cuda(), dec_triples.cuda(), dec_tight_boxes.cuda()

            if args.with_points:
                enc_points, dec_points = enc_points.cuda(), dec_points.cuda()

            # avoid batches with insufficient number of instances with valid shape classes
            mask = [ob in dataset.point_classes_idx for ob in dec_objs]
            if sum(mask) <= 1:
                continue

            optimizer.zero_grad()
            optimizerShapeAux.zero_grad()

            model = model.train()

            if args.weight_D_box > 0:
                optimizerDbox.zero_grad()

            # if we are reading pointsets and not precomputed shape features, convert them to features
            # otherwise do nothing, as we already have the features
            if not args.with_feats and args.with_points:
                with torch.no_grad():
                    encoded_enc_points = point_ae.encoder(enc_points.transpose(2,1).contiguous())
                    encoded_dec_points = point_ae.encoder(dec_points.transpose(2,1).contiguous())

            # set all scene (dummy) nodes point encodings to zero
            enc_scene_nodes = enc_objs == 0
            dec_scene_nodes = dec_objs == 0
            encoded_enc_points[enc_scene_nodes] = torch.zeros([torch.sum(enc_scene_nodes), encoded_enc_points.shape[1]]).float().cuda()
            encoded_dec_points[dec_scene_nodes] = torch.zeros([torch.sum(dec_scene_nodes), encoded_dec_points.shape[1]]).float().cuda()

            if args.num_box_params == 7:
                # all parameters, including angle, procesed by the box_net
                enc_boxes = enc_tight_boxes
                dec_boxes = dec_tight_boxes
            elif args.num_box_params == 6:
                # no angle. this will be learned separately if with_angle is true
                enc_boxes = enc_tight_boxes[:, :6]
                dec_boxes = dec_tight_boxes[:, :6]
            elif args.num_box_params == 4:
                # height, centroid. assuming we want the other sizes to be estimated from the shape aspect ratio
                enc_boxes = enc_tight_boxes[:, 2:6]
                dec_boxes = dec_tight_boxes[:, 2:6]
            else:
                raise NotImplementedError

            # limit the angle bin range from 0 to 24
            enc_angles = enc_tight_boxes[:, 6].long() - 1
            enc_angles = torch.where(enc_angles > 0, enc_angles, torch.zeros_like(enc_angles))
            enc_angles = torch.where(enc_angles < 24, enc_angles, torch.zeros_like(enc_angles))
            dec_angles = dec_tight_boxes[:, 6].long() - 1
            dec_angles = torch.where(dec_angles > 0, dec_angles, torch.zeros_like(dec_angles))
            dec_angles = torch.where(dec_angles < 24, dec_angles, torch.zeros_like(dec_angles))

            attributes = None

            boxGloss = 0
            loss_genShape = 0
            loss_genShapeFake = 0
            loss_shape_fake_g = 0

            if args.with_manipulator:
                model_out = model.forward_mani(enc_objs, enc_triples, enc_boxes, enc_angles, encoded_enc_points, attributes, enc_objs_to_scene,
                                                   dec_objs, dec_triples, dec_boxes, dec_angles, encoded_dec_points, attributes, dec_objs_to_scene,
                                                   missing_nodes, manipulated_nodes)

                mu_box, logvar_box, mu_shape, logvar_shape, orig_gt_box, orig_gt_angle, orig_gt_shape, orig_box, orig_angle, orig_shape, \
                dec_man_enc_box_pred, dec_man_enc_angle_pred, dec_man_enc_shape_pred, keep = model_out
            else:
                model_out = model.forward_no_mani(dec_objs, dec_triples, dec_boxes, encoded_dec_points, angles=dec_angles,
                                      attributes=attributes)

                mu_box, logvar_box, mu_shape, logvar_shape, dec_man_enc_box_pred, dec_man_encd_angles_pred, \
                  dec_man_enc_shape_pred = model_out

                orig_gt_box = dec_boxes
                orig_box = dec_man_enc_box_pred

                orig_gt_shape = encoded_dec_points
                orig_shape = dec_man_enc_shape_pred

                orig_angle = dec_man_encd_angles_pred
                orig_gt_angle = dec_angles

                keep = []
                for i in range(len(dec_man_enc_box_pred)):
                    keep.append(1)
                keep = torch.from_numpy(np.asarray(keep).reshape(-1, 1)).float().cuda()

            if args.with_manipulator and args.with_shape_disc and dec_man_enc_shape_pred is not None:
                shape_logits_fake_d, probs_fake_d = shapeClassifier(dec_man_enc_shape_pred[mask].detach())
                shape_logits_fake_g, probs_fake_g = shapeClassifier(dec_man_enc_shape_pred[mask])
                shape_logits_real, probs_real = shapeClassifier(encoded_dec_points[mask].detach())

                # auxiliary loss. can the discriminator predict the correct class for the generated shape?
                loss_shape_real = torch.nn.functional.cross_entropy(shape_logits_real, dec_objs[mask])
                loss_shape_fake_d = torch.nn.functional.cross_entropy(shape_logits_fake_d, dec_objs[mask])
                loss_shape_fake_g = torch.nn.functional.cross_entropy(shape_logits_fake_g, dec_objs[mask])
                # standard discriminator loss
                loss_genShapeFake = bce_loss(probs_fake_g, torch.ones_like(probs_fake_g))
                loss_dShapereal = bce_loss(probs_real, torch.ones_like(probs_real))
                loss_dShapefake = bce_loss(probs_fake_d, torch.zeros_like(probs_fake_d))

                loss_dShape = loss_dShapefake + loss_dShapereal + loss_shape_real + loss_shape_fake_d
                loss_genShape = loss_genShapeFake + loss_shape_fake_g
                loss_dShape.backward()
                optimizerShapeAux.step()

            vae_loss_box, vae_losses_box = calculate_model_losses(args,
                                                                    orig_gt_box,
                                                                    orig_box,
                                                                    name='box', withangles=args.with_angles, angles_pred=orig_angle,
                                                                    mu=mu_box, logvar=logvar_box, angles=orig_gt_angle,
                                                                    KL_weight=0.1, writer=writer, counter=counter)
            if dec_man_enc_shape_pred is not None:
                vae_loss_shape, vae_losses_shape = calculate_model_losses(args,
                                                                        orig_gt_shape,
                                                                        orig_shape,
                                                                        name='shape', withangles=False,
                                                                        mu=mu_shape, logvar=logvar_shape,
                                                                        KL_weight=0.1, writer=writer, counter=counter)
            else:
                # set shape loss to 0 if we are only predicting layout
                vae_loss_shape, vae_losses_shape = 0, 0

            if args.with_manipulator and args.with_changes:
                oriented_gt_boxes = torch.cat([dec_boxes], dim=1)
                boxes_pred_in = keep * oriented_gt_boxes + (1-keep) * dec_man_enc_box_pred

                if args.weight_D_box == 0:
                    # Generator loss
                    boxGloss = 0
                    # Discriminator loss
                    gamma = 0.1
                    boxDloss_real = 0
                    boxDloss_fake = 0
                    reg_loss = 0
                else:
                    logits, _ = boxD(dec_objs, dec_triples, boxes_pred_in, keep)
                    logits_fake, reg_fake = boxD(dec_objs, dec_triples, boxes_pred_in.detach(), keep, with_grad=True,
                                               is_real=False)
                    logits_real, reg_real = boxD(dec_objs, dec_triples, oriented_gt_boxes, with_grad=True, is_real=True)
                    # Generator loss
                    boxGloss = bce_loss(logits, torch.ones_like(logits))
                    # Discriminator loss
                    gamma = 0.1
                    boxDloss_real = bce_loss(logits_real, torch.ones_like(logits_real))
                    boxDloss_fake = bce_loss(logits_fake, torch.zeros_like(logits_fake))
                    # Regularization by gradient penalty
                    reg_loss = torch.mean(reg_real + reg_fake)

                # gradient penalty
                # disc_reg = discriminator_regularizer(logits_real, in_real, logits_fake, in_fake)
                boxDloss = boxDloss_fake + boxDloss_real + (gamma/2.0) * reg_loss
                optimizerDbox.zero_grad()
                boxDloss.backward()
                # gradient clip
                # torch.nn.utils.clip_grad_norm_(boxD.parameters(), 5.0)
                optimizerDbox.step()

            loss = vae_loss_box + vae_loss_shape + 0.1 * loss_genShape
            if args.with_changes:
                   loss = loss + args.weight_D_box * boxGloss #+ b_loss

            # optimize
            loss.backward()

            # Cap the occasional super mutant gradient spikes
            # Do now a gradient step and plot the losses
            torch.nn.utils.clip_grad_norm_(model.parameters(), 5.0)

            for group in optimizer.param_groups:
                for p in group['params']:
                    if p.grad is not None and p.requires_grad and torch.isnan(p.grad).any():
                        print('NaN grad in step {}.'.format(counter))
                        p.grad[torch.isnan(p.grad)] = 0
            optimizer.step()
            counter += 1

            if counter % 100 == 0:
                print("loss at {}: box {:.4f}\tshape {:.4f}\tdiscr RealFake {:.4f}\t discr Classifcation "
                      "{:.4f}".format(counter, vae_loss_box, vae_loss_shape, loss_genShapeFake,
                                                              loss_shape_fake_g))
            writer.add_scalar('Train Loss BBox', vae_loss_box, counter)
            writer.add_scalar('Train Loss Shape', vae_loss_shape, counter)
            writer.add_scalar('Train Loss loss_genShapeFake', loss_genShapeFake, counter)
            writer.add_scalar('Train Loss loss_shape_fake_g', loss_shape_fake_g, counter)

        if epoch % 5 == 0:
            model.save(args.exp, args.outf, epoch)

    writer.close()

def main():
    train()

if __name__ == "__main__": main()


import os
import numpy as np
import matplotlib.pyplot as plt
plt.rcdefaults()
from matplotlib.lines import Line2D
from matplotlib.patches import Rectangle
from matplotlib.collections import PatchCollection

NumConvMaxbig = 10
NumConvMaxsmall = 24
NumConvMaxtiny = 50
SmallOnFrom = 3
TinyOnFrom = 4
NumFcMax = 20
White = 1.
Light = 0.7
Medium = 0.5
Dark = 0.3
Black = 0.

def add_layer(patches, colors, sizex=24, sizey=24, num=5,
              top_left=[0, 0],
              loc_diff=[3, -3],
              ):
    # add a rectangle
    top_left = np.array(top_left)
    loc_diff = np.array(loc_diff)
    loc_start = top_left - np.array([0, sizex])
    for ind in range(num):
        patches.append(Rectangle(loc_start + ind * loc_diff, sizex, sizey))
        if ind % 2:
            colors.append(Medium)
        else:
            colors.append(Light)

def add_mapping(patches, colors, start_ratio, patch_sizex, patch_sizey, ind_bgn,
                top_left_list, loc_diff_list, num_show_list, size_list):

    start_loc = top_left_list[ind_bgn] \
        + (num_show_list[ind_bgn] - 1) * np.array(loc_diff_list[ind_bgn]) \
        + np.array([start_ratio[0] * size_list[ind_bgn],
                    -start_ratio[1] * size_list[ind_bgn]])

    end_loc = top_left_list[ind_bgn + 1] \
        + (num_show_list[ind_bgn + 1] - 1) \
        * np.array(loc_diff_list[ind_bgn + 1]) \
        + np.array([(start_ratio[0] + .5 * patch_sizex / size_list[ind_bgn]) *
                    size_list[ind_bgn + 1],
                    -(start_ratio[1] - .5 * patch_sizex / size_list[ind_bgn]) *
                    size_list[ind_bgn + 1]])

    patches.append(Rectangle(start_loc, patch_sizex, patch_sizey))
    colors.append(Dark)
    patches.append(Line2D([start_loc[0], end_loc[0]],
                          [start_loc[1], end_loc[1]]))
    colors.append(Black)
    patches.append(Line2D([start_loc[0] + patch_sizex, end_loc[0]],
                          [start_loc[1], end_loc[1]]))
    colors.append(Black)
    patches.append(Line2D([start_loc[0], end_loc[0]],
                          [start_loc[1] + patch_sizey, end_loc[1]]))
    colors.append(Black)
    patches.append(Line2D([start_loc[0] + patch_sizex, end_loc[0]],
                          [start_loc[1] + patch_sizey, end_loc[1]]))
    colors.append(Black)

def label(xy, text, xy_off=[0, 17]):
    plt.text(xy[0] + xy_off[0], xy[1] + xy_off[1], text,
             family='sans-serif', size=8)

if __name__ == '__main__':

    fc_unit_size = 2
    layer_width = 34

    patches = []
    colors = []

    fig, ax = plt.subplots()

    ############################
    # conv layers
    sizex_list = [30, 14, 8, 2, 1]
    sizey_list = [45, 14, 8, 2, 1]
    num_list = [8, 32, 64, 64, 256]
    x_diff_list = [0, 54, layer_width, layer_width, layer_width]
    text_list = ['Convolutional\ninputs'] + ['Feature\nmaps'] * (len(sizex_list) - 1)
    loc_diff_list = [[3, -3]] * SmallOnFrom + [[2, -2]] * (TinyOnFrom-SmallOnFrom) + [[1,-1]] * (len(sizex_list)-TinyOnFrom)

    bigs = num_list[:SmallOnFrom]
    smalls = num_list[SmallOnFrom:TinyOnFrom]
    tinys = num_list[TinyOnFrom:]
    num_show_list1 = list(map(min, bigs, [NumConvMaxbig] * len(bigs)))
    num_show_list2 = list(map(min, smalls, [NumConvMaxsmall] * len(smalls)))
    num_show_list3 = list(map(min, smalls, [NumConvMaxtiny] * len(tinys)))
    num_show_list = num_show_list1 + num_show_list2 +  num_show_list3

    top_left_list = np.c_[np.cumsum(x_diff_list), np.zeros(len(x_diff_list))]

    for ind in range(len(sizex_list)):
        add_layer(patches, colors, sizex=sizex_list[ind], sizey=sizey_list[ind],
                  num=num_show_list[ind],
                  top_left=top_left_list[ind], loc_diff=loc_diff_list[ind])
        label(top_left_list[ind], text_list[ind] + '\n{}@{}x{}'.format(
            num_list[ind], sizex_list[ind], sizey_list[ind]))

    ############################
    # in between layers
    start_ratio_list = [[0.4, 0.5], [0.4, 0.8], [0.4, 0.5], [0, 1]]
    patch_sizex_list = [4, 4, 3, 4]
    patch_sizey_list = [6, 4, 3, 4]
    stridex_list = [2, 2, 2, 2]
    stridey_list = [3, 2, 2, 2  ]
    ind_bgn_list = range(len(patch_sizex_list))
    text_list = ['Convolution', 'Convolution', 'Convolution', 'Convolution']

    for ind in range(len(patch_sizex_list)):
        add_mapping(patches, colors, start_ratio_list[ind],
                    patch_sizex_list[ind], patch_sizey_list[ind], ind,
                    top_left_list, loc_diff_list, num_show_list, sizex_list)
        label(top_left_list[ind], text_list[ind] + '\n{}x{} kernel\nstride ({},{})'.format(
            patch_sizex_list[ind], patch_sizey_list[ind], stridex_list[ind], stridey_list[ind]), xy_off=[26, -70])

    ############################
    # fully connected layers
    size_list = [fc_unit_size]
    num_list = [256]
    num_show_list = [20]
    x_diff_list = [sum(x_diff_list) + layer_width, layer_width, layer_width]
    top_left_list = np.c_[np.cumsum(x_diff_list), np.zeros(len(x_diff_list))]
    loc_diff_list = [[fc_unit_size, -fc_unit_size]] * len(top_left_list)
    text_list = ['Hidden\nunits'] #* (len(size_list) - 1) + ['Outputs']

    for ind in range(len(size_list)):
        add_layer(patches, colors, sizex=size_list[ind], sizey=size_list[ind], num=num_show_list[ind],
                  top_left=top_left_list[ind], loc_diff=loc_diff_list[ind])
        label(top_left_list[ind], text_list[ind] + '\n{}'.format(
            num_list[ind]))

    text_list = ['Flatten\n', 'Fully\nconnected', 'Fully\nconnected']

    for ind in range(len(size_list)):
        label(top_left_list[ind], text_list[ind], xy_off=[-10, -65])

    ############################
    # fully connected layers NUMBER TWO
    size_list = [fc_unit_size, fc_unit_size]
    num_list = [128, 64]
    num_show_list = [18, 10]
    x_diff_list = [4*layer_width+25, layer_width, layer_width]
    top_left_list = np.c_[np.cumsum(x_diff_list), np.zeros(len(x_diff_list))-94]
    loc_diff_list = [[fc_unit_size, -fc_unit_size]] * len(top_left_list)
    text_list = ['Flat inputs', 'Hidden units'] #* (len(size_list) - 1) + ['Outputs']

    for ind in range(len(size_list)):
        add_layer(patches, colors, sizex=size_list[ind], sizey=size_list[ind], num=num_show_list[ind],
                  top_left=top_left_list[ind], loc_diff=loc_diff_list[ind])
        label(top_left_list[ind], text_list[ind] + '\n{}'.format(
            num_list[ind]), xy_off=[0,5])

    text_list = ['', 'Fully\nconnected', 'Fully\nconnected']

    for ind in range(len(size_list)):
        label(top_left_list[ind], text_list[ind], xy_off=[-10, -55])

    ############################
    # fully connected layers CONCAT
    size_list = [fc_unit_size, fc_unit_size]
    num_list = [384, 256]
    num_show_list = [22, 20]
    x_diff_list = [7.1*layer_width,layer_width,layer_width]
    top_left_list = np.c_[np.cumsum(x_diff_list), np.zeros(len(x_diff_list))-40]
    loc_diff_list = [[fc_unit_size, -fc_unit_size]] * len(top_left_list)
    text_list = ['Hidden units', 'Hidden units'] #* (len(size_list) - 1) + ['Outputs']

    for ind in range(len(size_list)):
        add_layer(patches, colors, sizex=size_list[ind], sizey=size_list[ind], num=num_show_list[ind],
                  top_left=top_left_list[ind], loc_diff=loc_diff_list[ind])
        label(top_left_list[ind], text_list[ind] + '\n{}'.format(
            num_list[ind]), xy_off=[0,5])

    text_list = ['Concat', 'Fully\nconnected', 'Split']

    label(top_left_list[0], text_list[0], xy_off=[0,-35])
    label(top_left_list[1], text_list[1], xy_off=[-10, -55])

    ############################
    # fully connected layers SPLIT 1
    size_list = [fc_unit_size, fc_unit_size]
    num_list = [128, 21]
    num_show_list = [11, 7]
    x_diff_list = [9.4*layer_width, layer_width*.8]
    top_left_list = np.c_[np.cumsum(x_diff_list), np.zeros(len(x_diff_list))-20]
    loc_diff_list = [[fc_unit_size, -fc_unit_size]] * len(top_left_list)
    text_list = ['Advantage', ''] #* (len(size_list) - 1) + ['Outputs']

    for ind in range(len(size_list)):
        add_layer(patches, colors, sizex=size_list[ind], sizey=size_list[ind], num=num_show_list[ind],
                  top_left=top_left_list[ind], loc_diff=loc_diff_list[ind])
        label(top_left_list[ind], text_list[ind] + '\n{}'.format(
            num_list[ind]), xy_off=[0,5])

    text_list = ['Fully\nConnected', '', '']

    for ind in range(len(size_list)):
        label(top_left_list[ind], text_list[ind], xy_off=[10, -35])

    ############################
    # fully connected layers SPLIT 2
    size_list = [fc_unit_size, fc_unit_size]
    num_list = [128, 1]
    num_show_list = [11, 1]
    x_diff_list = [9.4*layer_width, layer_width*.8]
    top_left_list = np.c_[np.cumsum(x_diff_list), np.zeros(len(x_diff_list))-70]
    loc_diff_list = [[fc_unit_size, -fc_unit_size]] * len(top_left_list)
    text_list = ['Value', ''] #* (len(size_list) - 1) + ['Outputs']

    for ind in range(len(size_list)):
        add_layer(patches, colors, sizex=size_list[ind], sizey=size_list[ind], num=num_show_list[ind],
                  top_left=top_left_list[ind], loc_diff=loc_diff_list[ind])
        label(top_left_list[ind], text_list[ind] + '\n{}'.format(
            num_list[ind]), xy_off=[0,5])

    text_list = ['Fully\nConnected', '', '']

    for ind in range(len(size_list)):
        label(top_left_list[ind], text_list[ind], xy_off=[10, -35])

    ############################
    # fully connected layers FINAL CONCAT
    size_list = [fc_unit_size]
    num_list = [21]
    num_show_list = [7]
    x_diff_list = [11*layer_width,layer_width]
    top_left_list = np.c_[np.cumsum(x_diff_list), np.zeros(len(x_diff_list))-40]
    loc_diff_list = [[fc_unit_size, -fc_unit_size]] * len(top_left_list)
    text_list = ['Output'] #* (len(size_list) - 1) + ['Outputs']

    for ind in range(len(size_list)):
        add_layer(patches, colors, sizex=size_list[ind], sizey=size_list[ind], num=num_show_list[ind],
                  top_left=top_left_list[ind], loc_diff=loc_diff_list[ind])
        label(top_left_list[ind], text_list[ind] + '\n{}'.format(
            num_list[ind]), xy_off=[0,5])

    text_list = ['Matmul']

    for ind in range(len(size_list)):
        label(top_left_list[ind], text_list[ind], xy_off=[-10, -19])

    ############################
    colors += [0, 1]
    collection = PatchCollection(patches, cmap=plt.cm.gray)
    collection.set_array(np.array(colors))
    ax.add_collection(collection)
    plt.tight_layout()
    plt.axis('equal')
    plt.axis('off')
    plt.show()
    fig.set_size_inches(8, 2.5)

    fig_dir = './'
    fig_ext = '.png'
    fig.savefig(os.path.join(fig_dir, 'convnet_fig' + fig_ext),
                bbox_inches='tight', pad_inches=0)


from itertools import product
from insight_helper import EnumerateInsight

aggs = ["SUM", "COUNT", "AVG", "MAX", "MIN"]
# normal_dims = ["aid", "year", "coauthor"]
normal_dims = [0, 1]
q4_dims = []
ce_index = [0, 1, 2, 3]
###############   rank    %    davg  dprev
compatible_ce = [[True, False, True, True],    # rank
                 [True, False, True, True],      # %
                 [True, False, True, True],      # davg
                 [True, False, True, True]]       # dprev

def get_all_ces(tau, dims):
    if tau == 1:
        lst = []
        lst.append((-1,))
        return lst
    elif tau > 1:
        this_round = list(product(ce_index, dims))
        round_before = get_all_ces(tau-1, dims)
        return list(product(round_before, this_round))

def get_compatible_ces(tau, dims):
    if tau == 1 or tau == 2:
        return get_all_ces(tau, dims)
    elif tau > 2:
        res = []
        all_ces = get_all_ces(tau, dims)
        for item in all_ces:
            new_item = []

            while len(item) > 1:  # remove nested tuples from product operation
                new_item.append(item[1])
                item = item[0]
            new_item.append(item)

            new_item.reverse()
            compatible = True
            for i in range(1, len(new_item) - 1):
                op1 = new_item[i][0]
                op2 = new_item[i+1][0]
                if compatible_ce[op1][op2] == False:
                    compatible = False
                    break

            if compatible:
                res.append(new_item)

        return res

# print(len(get_all_ces(3)))
# print(len(get_compatible_ces(3)))

def insights(R, tau, k):
    H = []  # element (score, {"SG": SG, "Ce": ce, "type": T})

    dims = []
    if R == 1 or R == 2 or R == 3 or R == 4 or R == 5:
        dims = normal_dims
    # elif R == 4:
    #     dims = q4_dims
    else:
        print("Illegal dataset index")

    O = get_compatible_ces(tau, dims)
    d = len(dims)
    for ce in O:
        for i in range(d):
            S = ['*', '*']
            EnumerateInsight(S, i, ce, H, R, k, tau)
    return H


import json
import os

DB_FOLDER_NAME = "db"
PRODUCTS_FILE_NAME = "products.txt"

def get_prod():
    products = []
    with open (os.path.join('db','products.txt'), 'r') as file:
        for lines in file:
            products.append(json.loads(lines.strip()))
        return products


__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
__license__ = "AGPL v3"

from django.contrib import admin

from .models import Preprint

class PreprintAdmin(admin.ModelAdmin):
    search_fields = [
        "identifier_w_vn_nr",
    ]

admin.site.register(Preprint, PreprintAdmin)


"""
1610. Maximum Number of Visible Points

You are given an array points, an integer angle, and your location, where location = [posx, posy] and points[i] = [xi, yi] both denote integral coordinates on the X-Y plane.
Initially, you are facing directly east from your position. You cannot move from your position, but you can rotate. In other words, posx and posy cannot be changed.
Your field of view in degrees is represented by angle, determining how wide you can see from any given view direction. Let d be the amount in degrees that you rotate counterclockwise.
Then, your field of view is the inclusive range of angles [d - angle/2, d + angle/2].
You can see some set of points if, for each point, the angle formed by the point, your position, and the immediate east direction from your position is in your field of view.
There can be multiple points at one coordinate. There may be points at your location, and you can always see these points regardless of your rotation. Points do not obstruct your vision to other points.
Return the maximum number of points you can see.

Example 1:
Input: points = [[2,1],[2,2],[3,3]], angle = 90, location = [1,1]
Output: 3
Explanation: The shaded region represents your field of view. All points can be made visible in your field of view, including [3,3] even though [2,2] is in front and in the same line of sight.

Example 2:
Input: points = [[2,1],[2,2],[3,4],[1,1]], angle = 90, location = [1,1]
Output: 4
Explanation: All points can be made visible in your field of view, including the one at your location.

Example 3:
Input: points = [[1,0],[2,1]], angle = 13, location = [1,1]
Output: 1
Explanation: You can only see one of the two points, as shown above.

Constraints:
1 <= points.length <= 10^5
points[i].length == 2
location.length == 2
0 <= angle < 360
0 <= posx, posy, xi, yi <= 100
"""
from typing import List
import math

class Solution:
    # Good explanation: https://leetcode.com/problems/maximum-number-of-visible-points/discuss/894732/Python-3-Simple-Steps
    def visiblePoints(self, points: List[List[int]], angle: int, location: List[int]) -> int:
        res, overlappingPoints = 0, 0
        degrees = []

        def calcAngleFromLocation(point):
            x1, y1 = location
            x2, y2 = point

            tan =  math.atan2((y2-y1), (x2-x1)) * (180 / math.pi)
            return (tan + 360) % 360

        for point in points:
            if point == location:
                overlappingPoints += 1
                continue
            tangent = calcAngleFromLocation(point)
            degrees.append(tangent)

        # 2. Calculate the angle between you and each point.
	    #    i.  Sort the angles from smallest to largest.
	    #    ii. Extend angles [0, 40, 355] -> [0, 40, 355, 360, 400, 715]
	    #        This allows us to see that 355 is close to 0.
        degrees = degrees + [degree + 360 for degree in degrees]
        degrees.sort()
        i, j = 0, 0

        while j < len(degrees):
            while i <= j and degrees[j] - degrees[i] > angle:
                i += 1

            res = max(res, j-i+1)
            j += 1

        return res + overlappingPoints

sol = Solution()
print(sol.visiblePoints([[2,1],[2,2],[3,3]], 90, [1,1]))
print(sol.visiblePoints([[2,1],[2,2],[3,4],[1,1]], 90, [1,1]))
print(sol.visiblePoints([[1,0],[2,1]], 13, [1,1]))
print(sol.visiblePoints([[1,1],[2,2],[3,3]], 0, [1,1]))
print(sol.visiblePoints([[1,2]], 0, [1,1]))
print(sol.visiblePoints([[2,1]], 0, [1,1]))
# failed test case
print(sol.visiblePoints([[1,1],[2,2],[3,3],[4,4],[1,2],[2,1]], 0, [1,1]))
print(sol.visiblePoints([[60,61],[58,47],[17,26],[87,97],[63,63],[26,50],[70,21],[3,89],[51,24],[55,14],[6,51],[64,21],[66,33],[54,35],[87,38],[30,0],[37,92],[92,12],[60,73],[75,98],[1,11],[88,24],[82,92]], 44, [15,50]))

"""
Leetcode discuss solution using pure tangents and not converting to degrees

class Solution:
    def visiblePoints(self, points: List[List[int]], angle: int, location: List[int]) -> int:

        arr, extra = [], 0
        xx, yy = location

        for x, y in points:
            if x == xx and y == yy:
                extra += 1
                continue
            arr.append(math.atan2(y - yy, x - xx))

        arr.sort()
        arr = arr + [x + 2.0 * math.pi for x in arr]
        angle = math.pi * angle / 180

        l = ans = 0
        for r in range(len(arr)):
            while arr[r] - arr[l] > angle:
                l += 1
            ans = max(ans, r - l + 1)

        return ans + extra
"""


from flask import render_template, url_for, flash, redirect, request
from game import app, db
from game import app
from game.forms import AnswerForm, IdForm
from game.models import AnsweredForm
from sentence_comparison import *

questions = [
    'what is your name',
    'how old are you',
    'where do you come from',
    'what are your hobbies',
    'do you like python programming',
    'what is the best programming language in the world',
    'are you willing to be a web developer in the future',
    'can you use flask',
    'talk about randomization algorithm'
]

posts = [
    {
        'author': 'Corey Schafer',
        'title': 'Blog Post1',
        'content': 'First post content',
        'date_posted': 'April 20, 2018'
    },
    {
        'author': 'Jane Doe',
        'title': 'Blog Post2',
        'content': 'Second post content',
        'date_posted': 'April 21, 2018'
    }
]

wanted_id = 0

@app.route("/")
def home():
    return render_template('home.html', posts=posts)

@app.route("/answer", methods=['GET', 'POST'])
def answer():
    form = AnswerForm()
    if form.validate_on_submit():
        af = AnsweredForm(question1=form.question1.data, question2=form.question2.data, question3=form.question3.data, question4=form.question4.data, question5=form.question5.data, question6=form.question6.data)
        db.session.add(af)
        db.session.commit()
        flash('Your answer has been submitted! Here is your answer!', 'success')
        return redirect(url_for('youranswer'))
    return render_template('answer.html', title='Give Your Answers', form=form)

@app.route("/youranswer", methods=['GET', 'POST'])
def youranswer():
    af = AnsweredForm.query.order_by(-AnsweredForm.id).first()

    return render_template('youranswer.html', title='Your Answer', af=af)

@app.route("/enterid", methods=['GET', 'POST'])
def enterid():
    form = IdForm()
    if request.method == 'POST' and form.validate():
        global wanted_id
        wanted_id = int(request.form['id'])
        exists = bool(AnsweredForm.query.filter_by(id=wanted_id).first())
        if exists:
            flash('Start guessing!', 'success')
            return redirect(url_for('guess'))
        else:
            flash('ID does not exist. Please check again.', 'danger')
    return render_template('enterid.html', title='Enter A Form ID', form=form)

@app.route("/guess", methods=['GET', 'POST'])
def guess():
    form = AnswerForm()
    if form.validate_on_submit():
        af = AnsweredForm(question1=form.question1.data, question2=form.question2.data, question3=form.question3.data, question4=form.question4.data, question5=form.question5.data, question6=form.question6.data)
        db.session.add(af)
        db.session.commit()
        flash("Your answer has been submitted! Here are your guess and your friend's original answer!", 'success')
        return redirect(url_for('yourresult'))
    return render_template('guess.html', title='Have a Guess', form=form)

@app.route("/yourresult", methods=['GET', 'POST'])
def yourresult():
    af1 = AnsweredForm.query.filter_by(id=wanted_id).first()
    af2 = AnsweredForm.query.order_by(-AnsweredForm.id).first()
    score1 = scom(af1.question1, af2.question1, difficulty = 3)
    score2 = scom(af1.question2, af2.question2, difficulty = 3)
    score3 = scom(af1.question3, af2.question3, difficulty = 3)
    score4 = scom(af1.question4, af2.question4, difficulty = 3)
    score5 = scom(af1.question5, af2.question5, difficulty = 3)
    score6 = scom(af1.question6, af2.question6, difficulty = 3)
    score = (score1 + score2 + score3 + score4 +score5 + score6) / 6

    return render_template('yourresult.html', title='Your Result', af1=af1, af2=af2, wanted_id=wanted_id, score = score)


from typing import Union

from fastapi import FastAPI
from facebook_scraper import get_posts

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/{page_id}")
def scrap_item(page_id: str):
    for post in get_posts(page_id, pages=2):
        return {"posts": post}


from __future__ import print_function
from apiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
from oauth2client import clientsecrets
import datetime
from apiclient import discovery
import getpass
import googleapiclient.errors
from project import GoogleDriveV3

newLine = 9
resultGlobal = None

def writeHeaderColumnNamesToSheet(SPREADSHEET_ID, service, email, configMap):

    range1 = 'A1:H14'
    range2 = 'A8:P20'
    values1 = [
        [
            'New Hire/Exit IT Systems Access\n',
            '\n'
            'The following systems require action taken when a new hire is onboarded or when there is an employee exit.  Please clone per new hire or exit.\n',
            "If you want to add more columns into the table, please, follow the instructions in the README.md file https://github.com/Signiant/External-user-provisioning\n",
            "Email:  " + email,
            "AD Login:  " + email.split('@', 1)[0],
            "\n",
        ],
    ]

    values2 = [
        [
            'Plugin:tag', 'Success (add)', 'Log Message (add)','Update Method', 'User Created', 'Date In', 'Admin', 'Date Out', 'Admin', 'Success (remove)', 'Log Message (remove)',
        ],
    ]

    data = [
        {
            'range': range1,
            'values': values1,
            'majorDimension': "COLUMNS",
        },
        {
            'range': range2,
            'values': values2,
            'majorDimension': "ROWS",
        },
    ]

    body = {
        'valueInputOption': "RAW",
        'data': data
    }

    cont = True

    try:
        service.spreadsheets().values().batchUpdate(spreadsheetId=SPREADSHEET_ID, body=body).execute()

    except googleapiclient.errors.HttpError:
        print("Error. Could not create a spreadsheet for a user " + email + ". The value list might be out of index range ")
        print("\nFirst set of values is: ")
        print(values1)
        print("for range: " + range1)
        print("Second set: " )
        print(values2)
        print("for range: " + range2)
        cont =  False

    if cont:
        writeIDandNameToList(configMap, email.split('@', 1)[0], SPREADSHEET_ID, service)

# this method will write names and ids of every spreadsheet created for a user
# into the list
def writeIDandNameToList(configMap, fileName, fileID, service):

    rangeRow = 'A1:D1000'

    values1 = [
        [
            fileName, fileID,
        ],
    ]

    body = {
        'values': values1,
    }
    try:
        service.spreadsheets().values().append(
            spreadsheetId = configMap['spreadsheet_database']['id'], range=rangeRow,
            valueInputOption="RAW", body=body).execute()

    except googleapiclient.errors.HttpError:
        print("Error. User information was not updated in the list spreadsheet. The value list might be out of index range ")
        print("\nThe values are: ")
        print(values1)
        print("The range is: " + rangeRow)

def writeRowsToSheetToAddUser(credentials, SPREADSHEET_ID, email, plugin_tag, log, success):

    global newLine
   # credentials = getCredentials()
    service = getService(credentials)
    now = datetime.datetime.now()
    #to add each plugin at a new line of a sheet
    rangeRow = 'A'+str(newLine)+':W1000'

    values1 = [
        [
            plugin_tag, success, log, 'Tool', email.split('@', 1)[0], now.strftime("%Y-%m-%d %H:%M"), getpass.getuser(),
        ],
    ]

    data = [
        {
            'range': rangeRow,
            'values': values1,
            'majorDimension': "ROWS",
        },
    ]

    body = {
        'valueInputOption': "RAW",
        'data': data
    }

    try:

        service.spreadsheets().values().batchUpdate(spreadsheetId=SPREADSHEET_ID, body=body).execute()

    except googleapiclient.errors.HttpError:
        print("Error. User " + email + " information was not added to the spreadsheet. The value list might be out of index range ")
        print("\nThe values are: ")
        print(values1)
        print("The range is: " + rangeRow)
        return False

    newLine+=1

    return True

def writeRowsToSheetToRemoveUser(credentials, SPREADSHEET_ID, log, success, plugin_tag):

    global newLine
  #  credentials = getCredentials()
    service = getService(credentials)
    now = datetime.datetime.now()
    rangeRow = 'A'+str(newLine)+':W1000'
    global resultGlobal

    try:
        #initialize it only ones
        if resultGlobal is None:
        # gets all the data from the entry file and store it globally so that every plugin has access to it.
            resultGlobal = service.spreadsheets().values().get(spreadsheetId=SPREADSHEET_ID, range= 'A1:W1000').execute()

    except googleapiclient.errors.HttpError:
        print("Could not connect to the spreadsheetList file. Possible reasons:"
              "\n Errors in config file"
              "\n Internet connection problems"
              "\n File does not exist")
        return None

    # gets all the rows of the entry file
    numRows = resultGlobal.get('values') if resultGlobal.get('values') is not None else 0

    # search nested lists of the file for the values equal to the plugin_tag being passed
    foundRow = search_nested(numRows, plugin_tag)

    #if the plugin tag is not found, appends new line with the tag name and remove info
    if foundRow == None:

        values1 = [
            [
                plugin_tag, " ", " ", " ", " ", " ", " ", now.strftime("%Y-%m-%d %H:%M"),
                getpass.getuser(), success, log
            ],
        ]
    #if it's found, takes the existing values + new values and appends new row
    else:

        values1 = [
            [
                foundRow[0], foundRow[1],foundRow[2], foundRow[3],
                foundRow[4], foundRow[5], foundRow[6], now.strftime("%Y-%m-%d %H:%M"), getpass.getuser(), success, log
            ],
        ]

    data = [
        {
            'range': rangeRow,
            'values': values1,
            'majorDimension': "ROWS",
        },
    ]

    body = {
        'valueInputOption': "RAW",
        'data': data
    }

    try:
        service.spreadsheets().values().batchUpdate(spreadsheetId=SPREADSHEET_ID, body=body).execute()

    except googleapiclient.errors.HttpError:
        print("User information could not be updated in the spreadsheet, because \nthe spreadsheet does not exist or the value list might be out of index range ")
        print("\nThe values are: ")
        print(values1)
        print("The range is: " + rangeRow)

        return False

    newLine += 1

    return True

#creates a google spreadsheet with the header, user name and email and column names
def initialize(email, credentials, configMap, arg):

   # credentials = getCredentials()
    service = getService(credentials)
    if service is None:
        return None
    else:
        fileName = email.split('@', 1)[0]

        if 'spreadsheet_database' in configMap:
            spreadSheetDatabase_ID = configMap['spreadsheet_database']['id']
        else:
            print("Spreadsheet_database section is missing in your config file")
            return None

        #looks for a value in the spreadsheet list
        foundRow = findSpecificEntryInAllRows(service, spreadSheetDatabase_ID, fileName)

        #if the name is found, return ID of that spreadsheet
        if foundRow:
            return foundRow[1]
        #if not, it creates a new spreadsheet
        else:
            #if you need to add a user, new spreadsheet will be created
            if arg == 'add':

                SHEETS = discovery.build('sheets', 'v4', http=credentials.authorize(Http()))
                data = {'properties': {'title': fileName}}

                try:
                    #create spreadsheet
                    sheetCreated = SHEETS.spreadsheets().create(body=data).execute()

                except googleapiclient.errors.HttpError:
                    print("Could not create new spreadsheet for a user " + email)
                    return None

                SPREADSHEET_ID = sheetCreated['spreadsheetId']

                if 'spreadsheet_database' in configMap:
                    folderID = configMap['spreadsheet_database']['folderID']
                else:
                    print("Spreadsheet_database section is missing in your config file")
                    return None

                googleDriveServiceV3 = GoogleDriveV3.buildService()

                if googleDriveServiceV3:
                    newFolder = GoogleDriveV3.moveFileToFolder(SPREADSHEET_ID, folderID, googleDriveServiceV3)

                    if newFolder == None:
                        print("File was not moved to the expected folder. It was created in the authorized google drive account")
                else:
                    print("Could not authorize the user")

                # writes header data to a spreadsheet:
                writeHeaderColumnNamesToSheet(SPREADSHEET_ID, service, email, configMap)

                #returns the ID of the new spreadsheet
                return SPREADSHEET_ID
            # if you need to remove a user, but the spreadsheet does not exists, returns None
            else:
                return None

def getService(creds):

    service = None
    try:
        service = build('sheets', 'v4', http=creds.authorize(Http()))

    except AttributeError:
        print("client_secret.json is missing from your project")

    return service

# def getCredentials():
#    # CLIENT_SECRETS_FILE = "\client_secrets.json"
#
#     # Full, permissive scope to access all of a user's files
#     SCOPES = 'https://www.googleapis.com/auth/drive'
#     store = file.Storage('project/credentials.json')
#     creds = store.get()
#     if not creds or creds.invalid:
#         try:
#             flow = client.flow_from_clientsecrets("client_secret.json", SCOPES)
#             flags = tools.argparser.parse_args(args=['--noauth_local_webserver'])
#             #flags = tools.argparser.parse_args(args=[])
#             creds = tools.run_flow(flow, store, flags)
#
#         except clientsecrets.InvalidClientSecretsError:
#             print('The client secrets were missing or invalid: ')
#         except client.UnknownClientSecretsFlowError:
#             print('This OAuth 2.0 flow is unsupported')
#         except client.Error:
#             print('Unexpected Error')
#
#     return creds

#this function will search through every row in the list and return a value if it is equal to the value of a first cell
def findSpecificEntryInAllRows(service, SPREADSHEET_ID, searchValue):

    try:
        # gets the database spreadsheet
        result = service.spreadsheets().values().get(spreadsheetId=SPREADSHEET_ID, range= 'A1:W1000').execute()

    except googleapiclient.errors.HttpError:
        print("Could not connect to the spreadsheetList file. Possible reasons:"
              "\n Errors in config file"
              "\n Internet connection problems"
              "\n File does not exist")
        return None

    # gets all the rows of the database (the section where the user was added)
    numRows = result.get('values') if result.get('values') is not None else 0

    if numRows == 0:
        writeNameAndIDtoDatabaseSpreadsheet(service, SPREADSHEET_ID)

    # search nested lists of the database for the values equal to the plugin_tag being removed
    foundRow = search_nested(numRows, searchValue)

    # if the name is found, return ID of that spreadsheet
    if foundRow:
        return foundRow
    else:
        return None

# This function will search each cell of mylist for val and if found will return entire row
def search_nested(mylist, val):

    if not mylist:
        print("The spreadsheet is empty")
        return None
    else:

        for i in range(len(mylist)):
            for j in range(len(mylist[i])):
                if mylist[i][j] == val:
                    return mylist[i]

def writeNameAndIDtoDatabaseSpreadsheet(service, SPREADSHEET_ID):

    rangeRow = 'A1:D1000'

    values1 = [
        [
            "Name", "ID",
        ],
    ]

    body = {
        'values': values1,
    }
    try:
        service.spreadsheets().values().append(
            spreadsheetId=SPREADSHEET_ID, range=rangeRow,
            valueInputOption="RAW", body=body).execute()

    except googleapiclient.errors.HttpError:
        print(
            "Error. Name and ID values were not updated in the database list spreadsheet. The value list might be out of index range ")
        print("\nThe values are: ")
        print(values1)
        print("The range is: " + rangeRow)

# automatically resize columns
# https://developers.google.com/sheets/api/samples/rowcolumn