import time
import sys
import math
import random
import pygame
import operator
from pygame import gfxdraw

window_width = 800
window_height = 600

G = 6.674e-7
critical_mass = 12e12

class Circle:
    """
    A circle is an element that can travel around.
    """

    def __init__(self, x, y, mass, velocity_x=0, velocity_y=0, RGB=(255, 0, 0)):
        self.x = x
        self.y = y
        self.mass = mass
        self.velocity_x = velocity_x
        self.velocity_y = velocity_y
        self.RGB = RGB
        self.deletable = True

    def distance(self, other):
        return math.sqrt((self.x - other.x) ** 2 + (self.y - other.y) ** 2)

    def get_radius(self):
        return (((self.mass * (3 / 4)) / math.pi) ** (1 / 3)) * 10 ** -3

    def vel(self):
        return math.sqrt((self.velocity_x ** 2) + (self.velocity_y ** 2))

    def __sub__(self, other):
        return self.x - other.x, self.y - other.y

    def __repr__(self):
        return "Circle(x = {}, y = {}, mass = {}e10, vel = {}, color = {})".format(
            round(self.x, 2),
            round(self.y, 2),
            round(int(self.mass) / 10e10),
            round(self.vel(), 2),
            self.RGB,
        )

    def draw(self):
        pygame.gfxdraw.filled_circle(
                            gamedisplay,
                            round(self.x),
                            round(self.y),
                            round(self.get_radius()),
                            self.RGB,
                        )

def get_color():
    col = tuple(random.randint(0, 255) for i in range(3))
    if col == (30, 30, 30):
        return get_color()
    else:
        return col

circle = []
circle2 = [
    Circle(x=200, y=500, mass=10e10, velocity_x=0, velocity_y=0, RGB=get_color()),
    Circle(window_width / 2 + 1, window_height / 2 + 1, 20e10, RGB=get_color()),
    Circle(751, 50, 40e10, RGB=get_color()),
    Circle(205, 100, 40e10, 0, RGB=get_color()),
]

divider = 50
fun_mass = (critical_mass) / ((window_width / divider) * (window_height / divider))

def new_balls():
    for x in range(window_width // divider):
        for y in range(window_height // divider):
            circle.append(
                Circle(
                    (x * divider) + (divider / 2),
                    (y * divider) + (divider / 2),
                    fun_mass,
                    RGB=get_color(),
                )
            )

try:
    if sys.argv[1] == "s":
        new_balls()
except:
    pass

def color_picker(a, b):
    color1 = tuple([a.mass * x for x in a.RGB])
    color2 = tuple([b.mass * x for x in b.RGB])
    ab = tuple(map(operator.add, color1, color2))
    abb = tuple([round(x / (a.mass + b.mass)) for x in ab])
    return abb

def ball_in_circle(biggest):
    #print(biggest.x)
    this_mass = 10e10
    distance = 100
    force2 = G * ((biggest.mass * this_mass) / distance**2)
    speed = (math.sqrt((force2 * distance) / (biggest.mass + this_mass))) * 0.03
    biggest.velocity_x -= speed / biggest.mass
    fartlist = [speed, -speed]
    circle.append(
                Circle(
                    biggest.x,
                    biggest.y - distance,
                    10e10,
                    velocity_x= random.choice(fartlist),
                    RGB=get_color(),
                )
            )

pygame.init()
gamedisplay = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("Vindu!")

print(len(circle))
max_mass = 0
crashed = False
max_vel = 0
rounds = 0
while not crashed:
    rounds += 1
    k1 = len(circle)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            crashed = True

        keys = pygame.key.get_pressed()
        if keys[pygame.K_SPACE]:
            circle.append(
                Circle(
                    random.randint(0, window_width),
                    random.randint(0, window_height),
                    10e10,
                    RGB=get_color(),
                )
            )
        if keys[pygame.K_LEFT]:
            circle.append(
                Circle(
                    random.randint(0, window_width),
                    random.randint(0, window_height),
                    10e10,
                    velocity_x=-0.15,
                    RGB=get_color(),
                )
            )
        if keys[pygame.K_RIGHT]:
            circle.append(
                Circle(
                    random.randint(0, window_width),
                    random.randint(0, window_height),
                    10e10,
                    velocity_x=0.15,
                    RGB=get_color(),
                )
            )
        if keys[pygame.K_t]:
            print("New!")
            for x in circle:
                print(x)

        if keys[pygame.K_j]:
            circle = []

        pos_x, pos_y = pygame.mouse.get_pos()

        if event.type == pygame.MOUSEBUTTONDOWN:
            times = time.time()

        if keys[pygame.K_r]:
            max_mass2 = 0
            for c in circle:
                if c.mass > max_mass2:
                    max_mass2 = c.mass
            for c in circle:
                if c.mass == max_mass2:
                    ball_in_circle(c)

        if keys[pygame.K_s]:
            new_balls()

        if event.type == pygame.MOUSEBUTTONUP:
            size = time.time() - times
            circle.append(
                Circle(pos_x, pos_y, max(size * 15 ** 10, 10e2), RGB=get_color())
            )
            print(size)

    keys = pygame.key.get_pressed()
    if keys[pygame.K_DOWN]:
        circle.append(
            Circle(
                random.randint(0, window_width),
                random.randint(0, window_height),
                10e10,
                velocity_x=random.uniform(-0.25, 0.25),
                RGB=get_color(),
            )
        )
    if keys[pygame.K_UP]:
        circle.append(
            Circle(
                random.randint(0, window_width),
                random.randint(0, window_height),
                10e10,
                RGB=get_color(),
            )
        )

    pygame.display.update()
    gamedisplay.fill((30, 30, 30))

    listen = circle[:]

    for c in circle:
        c.x += c.velocity_x
        c.y += c.velocity_y

    for c in circle:
        c.draw()
        if c.x < -10000 or c.x > 10000:
            circle.remove(c)
        elif c.y < -10000 or c.y > 10000:
            circle.remove(c)
        listen.remove(c)

        for d in listen:
            dist = max(c.distance(d), 0.0000001)
            force = G * (c.mass * d.mass / dist ** 2)
            acceleration_c = 0.03 * (force / c.mass)
            acceleration_d = 0.03 * (force / d.mass)
            diff_x, diff_y = c - d
            c.velocity_x -= acceleration_c * diff_x / dist * 0.003
            c.velocity_y -= acceleration_c * diff_y / dist * 0.003
            d.velocity_x += acceleration_d * diff_x / dist * 0.003
            d.velocity_y += acceleration_d * diff_y / dist * 0.003

            if dist < c.get_radius() + d.get_radius():
                new_mass = c.mass + d.mass
                c.x = (c.mass * c.x + d.mass * d.x) / (c.mass + d.mass)
                c.y = (c.mass * c.y + d.mass * d.y) / (c.mass + d.mass)
                c.velocity_x = (c.velocity_x * c.mass + d.velocity_x * d.mass) / (
                    c.mass + d.mass
                )
                c.velocity_y = (c.velocity_y * c.mass + d.velocity_y * d.mass) / (
                    c.mass + d.mass
                )
                c.RGB = color_picker(c, d)
                c.mass = new_mass
                circle.remove(d)
                listen.remove(d)
                if new_mass > critical_mass:
                    if c in circle:
                        f = open("demofile2.txt", "a")
                        f.write("{}\n".format(c.RGB))
                        f.close()
                        circle.remove(c)
                    assert c not in listen
                max_vel = 0

        vel = c.vel()

        if vel > max_vel:
            max_vel = vel

    k2 = len(circle)
    if k1 != k2:
        print(len(circle), max_vel)
    max_vel = 0


'''Código para as páginas e ações da área logada do usúario'''

from flask import Blueprint, render_template, request, flash, redirect, url_for
from flask_login import login_required, current_user
from .models import Lista, Aluno, Trabalho, NotaLista, NotaTrabalho
from . import db

pags = Blueprint('pags', __name__)

@pags.route('/', methods=['GET', 'POST'])
def home():
    '''Função para a página inicial'''
    return render_template("home.html", user=current_user)

@pags.route('/areaLogada', methods=['GET', 'POST'])
@login_required
def areaLogada():
    '''Função para a área logada'''
    nome_usuario = current_user.nome

    if request.method == 'POST':
        if request.form['botao'] == 'Adicionar lista':
            return redirect(url_for('pags.addLista'))

        elif request.form['botao'] == 'Adicionar nota da lista':
            return redirect(url_for('pags.addNotaLista'))

        elif request.form['botao'] == 'Adicionar nota do trabalho':
            return redirect(url_for('pags.addNotaTrab'))

        elif request.form['botao'] == 'Adicionar aluno':
            return redirect(url_for('pags.addAluno'))

        else:
            return redirect(url_for('pags.calcSituacao'))

    return render_template("area_logada.html", user=current_user, nome_usuario=nome_usuario)

@pags.route('/areaLogada/addLista', methods=['GET', 'POST'])
@login_required
def addLista():
    '''Função para adicionar novas listas'''

    if request.method == 'POST':
        lista = request.form.get('lista').title()

        verif_lista = Lista.query.filter(Lista.lista==lista).first() #verifica se a lista já existe

        if verif_lista != None:
            flash('Essa tarefa já existe.', category='error')
        elif len(lista) < 3: #verifica o tamanho do nome da lista
            flash('O nome da lista deve ter mais de 2 caracteres', category='error')
        else:
            nova_lista = Lista(lista=lista) #cria nova lista
            db.session.add(nova_lista)
            db.session.commit() #adiciona nova lista à base de dados
            flash('Lista criada!', category='success')

    return render_template("add_lista.html", user=current_user)

@pags.route('/areaLogada/addAluno', methods=['GET', 'POST'])
@login_required
def addAluno():
    '''Função para adicionar novos alunos'''

    if request.method == 'POST':
        aluno = request.form.get('aluno').title()

        verif_aluno = Aluno.query.filter(Aluno.aluno==aluno).first() #verifica se o aluno já existe

        if verif_aluno != None:
            flash('Essa aluno já existe.', category='error')
        elif len(aluno) < 3: #verifica o tamanho do nome do aluno
            flash('O nome da lista deve ter mais de 2 caracteres', category='error')
        else:
            novo_aluno = Aluno(aluno=aluno) #cria novo aluno
            db.session.add(novo_aluno)
            db.session.commit() #adiciona novo aluno à base de dados
            flash('Aluno adicionado!', category='success')

    return render_template("add_aluno.html", user=current_user)

@pags.route('/areaLogada/addNotaLista', methods=['GET', 'POST'])
@login_required
def addNotaLista():
    '''Função para adicionar nota a uma lista'''

    if request.method == 'POST':
        aluno = request.form.get('aluno')
        lista = request.form.get('lista')
        nota = request.form.get('nota')

        id_aluno = Aluno.query.filter(Aluno.aluno==aluno).first().id #procura o id do aluno na base de dados
        id_lista = Lista.query.filter(Lista.lista==lista).first().id #procura o id da lista na base de dados

        if NotaLista.query.filter(NotaLista.id_aluno==id_aluno, NotaLista.id_lista==id_lista).first() != None: #verifica se a lista já tem nota
            flash('Esse aluno já possui nota nessa tarefa.', category='error')
        else:
            nova_nota = NotaLista(id_aluno=id_aluno, id_lista=id_lista, nota_lista=nota) #cria nova nota
            db.session.add(nova_nota)
            db.session.commit() #adiciona nova nota à base de dados
            flash('Nota adicionada!', category='success')

    busca = Lista.query.all() #busca todas as colunas da tabela Lista
    listas = []
    for lista in busca:
        listas.append(lista.lista) #adiciona na lista todas as linhas da coluna lista

    busca = Aluno.query.all() #busca todas as colunas da tabela Aluno
    alunos = []
    for aluno in busca:
        alunos.append(aluno.aluno) #adiciona na lista todas as linhas da coluna aluno

    return render_template("add_nota_lista.html", user=current_user, listas=listas, alunos=alunos)

@pags.route('/areaLogada/addNotaTrab', methods=['GET', 'POST'])
@login_required
def addNotaTrab():
    '''Função para adicionar nota a um trabalho'''

    if request.method == 'POST':
        aluno = request.form.get('aluno')
        trabalho = request.form.get('trabalho')
        nota = request.form.get('nota')

        id_aluno = Aluno.query.filter(Aluno.aluno==aluno).first().id #procura o id do aluno no banco de dados

        id_trabalho = Trabalho.query.filter(Trabalho.trabalho==trabalho).first() #verifica se o trabalho já existe
        if id_trabalho == None: #caso não exista
            novo_trabalho = Trabalho(trabalho=trabalho) #cria um novo trabalho
            db.session.add(novo_trabalho)
            db.session.commit() #adiciona o novo trabalho à base de dados
            id_trabalho = Trabalho.query.filter(Trabalho.trabalho==trabalho).first().id
        else: #caso já exista
            id_trabalho = id_trabalho.id #armazena na variável o id do trabalho

        if NotaTrabalho.query.filter(NotaTrabalho.id_aluno==id_aluno, NotaTrabalho.id_trabalho==id_trabalho).first() != None: #verifica se a nota já existe
            flash('Esse aluno já possui nota nesse trabalho.', category='error')
        else:
            nova_nota = NotaTrabalho(id_aluno=id_aluno, id_trabalho=id_trabalho, nota_trabalho=nota) #cria nova nota
            db.session.add(nova_nota)
            db.session.commit() #adiciona noca nota à base de dados
            flash('Nota adicionada!', category='success')

    busca= Aluno.query.all() #busca todas as colunas da tabela Aluno
    alunos = []
    for aluno in busca:
        alunos.append(aluno.aluno) #adiciona na lista todas as linhas da coluna aluno

    return render_template("add_nota_trab.html", user=current_user, alunos=alunos)

@pags.route('/areaLogada/calcSituacao', methods=['GET', 'POST'])
@login_required
def calcSituacao():
    '''Função para calcular situação do aluno e sua média'''

    if request.method == 'POST':
        aluno = request.form.get('aluno')

        id_aluno = Aluno.query.filter(Aluno.aluno==aluno).first().id #procura o id do aluno no banco de dados

        if NotaTrabalho.query.filter(NotaTrabalho.id_aluno==id_aluno).first() == None: #verifica se existe algum trabalho com nota
            flash('Não é possível calcular situção, adicione a nota de pelo menos um trabalho.', category='error')
            return render_template("calc_situacao.html", user=current_user)

        parte_trabalhos = 0
        quant = 0
        for nota in NotaTrabalho.query.filter(NotaTrabalho.id_aluno==id_aluno): #cada nota de trabalho é somada
            parte_trabalhos += nota.nota_trabalho
            quant += 1
        parte_trabalhos = (parte_trabalhos/quant)*0.8 #é feita a média das notas e o resultado multiplicado por 0.8

        if NotaLista.query.filter(NotaLista.id_aluno==id_aluno).first() == None: #verifica se existe alguma lista com nota
            flash('Não é possível calcular situção, adicione a nota de pelo menos uma lista.', category='error')
            return render_template("calc_situacao.html", user=current_user)

        parte_listas = 0
        quant = 0
        for nota in NotaLista.query.filter(NotaLista.id_aluno==id_aluno): #cada nota de lista é somada
            parte_listas += nota.nota_lista
            quant += 1
        parte_listas = (parte_listas/quant)*0.2 #é feita a média das notas e o resultado multiplicado por 0.8

        media = parte_trabalhos + parte_listas #os valores obtidos para as listas e trabalhos são somados
        media = round(media, 1) #o valor da média é arredondado para 1 casa decimal

        if media >= 7: #caso a média seja maior ou igual a 7
            situacao = 'Aprovado'
        elif media >= 3: #caso a média seja maior ou igual a 3
            situacao = 'Prova final'
        else: #caso a média seja menor que 3
            situacao = 'Reprovado'

        exibir_situacao = True #variável para permitir a exibição do texto com a situção do aluno

    else: #caso a página seja acessada através do método 'GET'
        media = None
        aluno = None
        situacao = None
        exibir_situacao = False

    busca= Aluno.query.all() #busca todas as colunas da tabela Aluno
    alunos = []
    for busca_aluno in busca:
        alunos.append(busca_aluno.aluno) #adiciona na lista todas as linhas da coluna aluno

    return render_template("calc_situacao.html",
                            user=current_user,
                            media=media,
                            nome_aluno=aluno,
                            situacao=situacao,
                            exibir_situacao=exibir_situacao,
                            alunos=alunos)


players = ['charles', 'martina', 'michael', 'florence', 'eli']
# print(players[0:3])
# print(players[1:3])
# print(players[:4])
# print(players[2:])
# print(players[-3:])

# 遍历切片
print("Here are the first three players on my team!")
# for player in players[:3]:
    # print(player)
    # print(player.title())

# 复制列表
my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods[:]

# print(f'my food are{my_foods}')
# print(f'firens’s food are {friend_foods}')
#
# print('\n')
my_foods.append("cannoli")
friend_foods.append('ice cream')
# print(f'my food are{my_foods}')
# print(f'firens’s food are {friend_foods}')

# 两个变量名关联到同一个地址，指向同一个列表
her_foods = my_foods
my_foods.append("meat")
her_foods.append('grass')
# print(f'my food are{my_foods}')
# print(f'her food are {her_foods}')

# 练习4-10
# print(f'The first three items in the list are:')
# print(my_foods[:3])
#
# print(f'Three items from the middle of the list are:')
# print(my_foods[2:5])

# print(f'The last three items in the list are:')
# print(my_foods[-3:])

# 练习4-11
pizzas = ['A', 'B', 'C']
friend_pizzas = pizzas[:]
pizzas.append("D")
friend_pizzas.append("E")

print(pizzas)
print(friend_pizzas)

print("My favorite pizzas are:")
for me in pizzas:
    print(me)

print("Her favorite pizzas are:")
for me in friend_pizzas:
    print(me)


from sandbox import Automata
from elements import Element
import math

class Conway(Element):
	name = "Conway"
	basecolor = (255, 255, 255)

	def act(self):
		self.regen_near_full()
		self.regen_near_partial()
		neighbors = len(self.nearlistpartial)
		if neighbors < 2:
			self.remove_delayed()
		elif neighbors > 3:
			self.remove_delayed()
		#for pos in self.nearbypos():
		for pos in self.neighbors():
			if self.sandbox.grid[pos[0]][pos[1]] is None:
				self.multiply(pos[0],pos[1])

	def multiply(self, x, y):
		nearlist = self.regen_near_full(x, y)
		if len([z for z in nearlist if z is not None]) == 3:
		#if len([z for z in nearlist if isinstance(z, Conway)]) == 3:
			self.sandbox.post_spawn.append((Conway, x, y))


from math import atan2, sqrt
import random

def cross_product(x1_1, y1_1, x1_2, y1_2, x2_1, y2_1, x2_2, y2_2):
	'''
	Funkce počítá vektorový součin dvou vektorů.

	:param x1_1: Hodnota x prvního bodu první proměnné
	:param y1_1: Hodnota y prvního bodu první proměnné
	:param x1_2: Hodnota x druhého bodu první proměnné
	:param y1_2: Hodnota y druhého bodu první proměnné
	:param x2_1: Hodnota x prvního bodu druhé proměnné
	:param y2_1: Hodnota y prvního bodu druhé proměnné
	:param x2_2: Hodnota x druhého bodu druhé proměnné
	:param y2_2: Hodnota y druhého bodu druhé proměnné
	:return: Vektorový součin
	'''
	first_vector_of_cross_product = [x1_1-x1_2, y1_1-y1_2] 	# Spočítá první vektor
	second_vector_of_cross_product = [x2_1-x2_2, y2_1-y2_2]	# Spočítá druhý vektor
	their_cross_product = first_vector_of_cross_product[0] * second_vector_of_cross_product[1]\
						- first_vector_of_cross_product[1] * second_vector_of_cross_product[0]
	return their_cross_product

def intersection_of_two_vectors(x1_1, y1_1, x1_2, y1_2, x2_1, y2_1, x2_2, y2_2):
	'''
	Funkce určuje, zda se protínají dva vektory, podle hodnot vektorových součinů.
	:param x1_1: Hodnota x prvního bodu první proměnné
	:param y1_1: Hodnota y prvního bodu první proměnné
	:param x1_2: Hodnota x druhého bodu první proměnné
	:param y1_2: Hodnota y druhého bodu první proměnné
	:param x2_1: Hodnota x prvního bodu druhé proměnné
	:param y2_1: Hodnota y prvního bodu druhé proměnné
	:param x2_2: Hodnota x druhého bodu druhé proměnné
	:param y2_2: Hodnota y druhého bodu druhé proměnné
	:return: True - vektory se protínají, False - vektory se neprotínají
	'''
	vector_1 = [x1_1-x1_2, y1_1-y1_2]
	vector_2 = [x2_1-x2_2, y2_1-y2_2]
	if vector_1[0]*vector_2[1]-vector_1[1]*vector_2[0] == 0:
		return False
	else:
		v1 = cross_product(x2_1, y2_1, x2_2, y2_2, x2_1, y2_1, x1_1, y1_1)
		v2 = cross_product(x2_1, y2_1, x2_2, y2_2, x2_1, y2_1, x1_2, y1_2)
		v3 = cross_product(x1_1, y1_1, x1_2, y1_2, x1_1, y1_1, x2_1, y2_1)
		v4 = cross_product(x1_1, y1_1, x1_2, y1_2, x1_1, y1_1, x2_2, y2_2)
		if v1*v2 < 0 and v3*v4 < 0:
			return True
		else:
			return False

def distance(p0, p1=None):
	'''
	Funkce spočítá délku mezi dvěma body.
	:param p0: První bod
	:param p1: Druhý bod
	:return: Délka mezi body
	'''
	if p1 == None:
		p1 = anchor
	y_span = p0[1] - p1[1]
	x_span = p0[0] - p1[0]
	return y_span**2 + x_span**2

def polar_angle(p0, p1=None):
	'''
	Funkce spočítá polární úhel s osou x
	:param p0: První bod
	:param p1: Druhý bod
	:return: Funkce vrátí tangens úhle mezi bodem a osou x
	'''
	if p1 == None:
		p1 = anchor
	y_span = p0[1] - p1[1]
	x_span = p0[0] - p1[0]
	return atan2(y_span, x_span)

def sort_polar_angle(s):
	'''
	Funkce třídí body podle jejich polárních úhlů
	:param s: Souřadnice všech bodů překážek
	:return: Seznam souřadnic
	'''
	if len(s) <= 1:
		return s
	smaller, equal, bigger = [], [], []
	random_anchor_angle = polar_angle(s[random.randint(0, len(s)-1)]) 		# choose random start of separating \
																			# vybirame nahodny start
	for element in s:
		element_angle = polar_angle(element)
		if element_angle < random_anchor_angle:
			smaller.append(element)
		elif element_angle == random_anchor_angle:
			equal.append(element)
		else:
			bigger.append(element)
	return sort_polar_angle(smaller) + sorted(equal, key=distance) + sort_polar_angle(bigger)

def det(p1,p2,p3):
	'''
	Funkce určuje, zda pohyb od bodu 1 k bodu 3 přes bod 2 šel po nebo proti směru hodinových ručíček.
	Pokud return bude < 0, tak pohyb jde po směru hodinových ručíček, pokud return > 0, tak pohyb jde proti.
	:param p1:
	:param p2:
	:param p3:
	:return:
	'''
	return   (p2[0]-p1[0])*(p3[1]-p1[1]) \
			-(p2[1]-p1[1])*(p3[0]-p1[0])

def graham_scan(points):
	'''
	Funkce určuje convexní obaly překážek podle toho, jestli pohyb těmito body jde po nebo proti chodu hodinocých
	ručíček.
	Potřebujeme jít jenom proti směru hodinových ručíček, abyjsme dpstali konvexní obaly, protože jsme setřidili
	body ve vzestupném pořádí polárního úhlu.
	:param points: Souřadnice překážek
	:return: Konvexní obaly
	'''
	global anchor
	min_id = None
	for i, (x, y) in enumerate(points):
		if min_id == None or y < points[min_id][1]:
			min_id = i
		if y == points[min_id][1] and x < points[min_id][0]:
			min_id =  i
	anchor = points[min_id]
	sorted_points = sort_polar_angle(points)
	del sorted_points[sorted_points.index(anchor)]
	konvex_obal = [anchor, sorted_points[0]]
	for s in sorted_points[1:]:
		while det(konvex_obal[-2], konvex_obal[-1], s) <= 0:
			del konvex_obal[-1]
			if len(konvex_obal) < 2:
				break
		konvex_obal.append(s)
	return konvex_obal

def convexni_obal(file_name):
	'''
	Funkce čte souřadnice ze souboru a počítá konvexní obaly každé překážky.
	:param file_name: Jméno souboru
	:return: Convexní obaly překážek
	'''
	coord = []
	length_of_each_string = []
	convexni_obaly = []

	with open(file_name) as pattern_file:
		for line in pattern_file:
			for i in range(len(line.split())):
				coord.append(list(line.split()[i].split()[0].split(',')))
			length_of_each_string.append(len(line.split()))

	for i in range(len(coord)):
		coord[i][0] = int(coord[i][0])
		coord[i][1] = int(coord[i][1])
	start_p = 0
	finish_p = length_of_each_string[0]
	for i in range(len(length_of_each_string)):
		convexni_obaly.append(graham_scan(coord[start_p:finish_p]))
		start_p += length_of_each_string[i]
		if (i+1) == len(length_of_each_string):
			break
		else:
			finish_p += length_of_each_string[i+1]
	return convexni_obaly

def cos_of_vektors(x1, y1, x2, y2):
	'''
	Funcke spočítá cosinus úhlu mezi dvěma vektory
	:param x1: Hodnota x prvního bodu
	:param y1: Hodnota y prvního bodu
	:param x2: Hodnota x druhého bodu
	:param y2: Hodnota y druhého bodu
	:return: cos úhlu
	'''
	cosin = (x1 * x2 + y1 * y2)/((sqrt(x1 * x1 + y1 * y1)) * (sqrt(x2 * x2 + y2 * y2)))
	return cosin

def available_bods(start, finish, prekazky):
	'''
	Funkce vybírá body, kterí leží mezi dvěma rovnoběžnými přímkami, které procházejí přes bod, kde se nachází robot,
	a bod konce pohybu.
	Pokud start a konec leží vně konvexního obalu nějaké překážky,nejkratší cesta může procházet jenom body této roviny.
	:param start: Start pohybu
	:param finish: Konec pohybu
	:param prekazky: Body konvexních obalů
	:return:
	'''
	available = []
	vektor_st_fin = [finish[0] - start[0], finish[1] - start[1]]
	vektor_fin_st = [start[0] - finish[0], start[1] - finish[1]]
	for i in range(len(prekazky)):
		available.append([])
		for k in range(len(prekazky[i])):
			st_point = [prekazky[i][k][0] - start[0], prekazky[i][k][1] - start[1]]
			f_point = [prekazky[i][k][0] - finish[0], prekazky[i][k][1] - finish[1]]
			if cos_of_vektors(vektor_st_fin[0], vektor_st_fin[1], st_point[0], st_point[1]) > 0 and \
					cos_of_vektors(vektor_fin_st[0], vektor_fin_st[1], f_point[0], f_point[1]) > 0:
				available[i].append(prekazky[i][k])
	return available

def vyber_koncovych_bodu(start, finish, st):
	'''
	Funkce spočítá koncové body z každé strany z hlediska robota.
	:param start: Poloha robota
	:param finish: Konec pohybu
	:param st: Konvexní obaly
	:return: Seznam souřadnic konocvých bodů pro každou překážku.
	'''
	prekazky = available_bods([1, 20], [22, 2], st)
	konc_body = []
	for i in range(len(prekazky)):
		konc_body.append([])
		anchor = prekazky[i][random.randint(0, len(prekazky[i])-1)]
		v_anchor = [anchor[0] - start[0], anchor[1]- start[1]]
		min_cos = 1
		for k in range(len(prekazky[i])):
			v_k = [prekazky[i][k][0] - start[0], prekazky[i][k][1] - start[1]]
			if cos_of_vektors(v_anchor[0], v_anchor[1], v_k[0], v_k[1]) < min_cos:
				min_cos = cos_of_vektors(v_anchor[0], v_anchor[1], v_k[0], v_k[1])
				bod_1 = prekazky[i][k]
				v_bod_1 = [bod_1[0] - start[0], bod_1[1] - start[1]]
		min_cos = 1
		for k in range(len(prekazky[i])):
			v_k = [prekazky[i][k][0] - start[0], prekazky[i][k][1] - start[1]]
			if cos_of_vektors(v_bod_1[0], v_bod_1[1], v_k[0], v_k[1]) < min_cos:
				min_cos = cos_of_vektors(v_bod_1[0], v_bod_1[1], v_k[0], v_k[1])
				bod_2 = prekazky[i][k]
		konc_body[i].extend([bod_1, bod_2])
	return konc_body

def delka_mezi_body(x1, y1, x2, y2):
	'''
	Funcke spočítá délku mezi dvěma body.
	:param x1: Hodnota x prvního bodu
	:param y1: Hodnota y prvního bodu
	:param x2: Hodnota x druhého bodu
	:param y2: Hodnota y druhého bodu
	:return: Délka
	'''
	delka = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
	return delka

def our_sides_of_figures(st, start, finish):
	'''
	Funkce nejprve rozdělí konvexní obaly všech překážek na dvě strany, které leží mezi koncovými body překážky.
	A pak vybírá, která strana je bližší.
	:param st: Všechny souřadnice překážek.
	:param start: Poloha robota
	:param finish: Konec pohybu
	:return: Bližší strany každé překážky.
	'''
	dostupne_body = available_bods(start, finish, st)
	koncove_body = vyber_koncovych_bodu(start, finish, st)
	obe_strany = []
	viditelne_body = []
	for i in range(len(koncove_body)):
		obe_strany.append([])
		side_1 = []
		side_2 = []
		if dostupne_body[i].index(koncove_body[i][0]) > dostupne_body[i].index(koncove_body[i][1]):
			side_1 = dostupne_body[i][dostupne_body[i].index(koncove_body[i][0]) : -1] + \
				[dostupne_body[i][-1]] + dostupne_body[i][0 : dostupne_body[i].index(koncove_body[i][1])+1]
			side_2 = dostupne_body[i][dostupne_body[i].index(koncove_body[i][1]) \
									  : dostupne_body[i].index(koncove_body[i][0])+1]
		elif dostupne_body[i].index(koncove_body[i][0]) < dostupne_body[i].index(koncove_body[i][1]):
			side_1 = dostupne_body[i][dostupne_body[i].index(koncove_body[i][0]) \
									  : dostupne_body[i].index(koncove_body[i][1])+1]
			side_2 = dostupne_body[i][dostupne_body[i].index(koncove_body[i][1]) : -1] + \
				[dostupne_body[i][-1]] + dostupne_body[i][0 : dostupne_body[i].index(koncove_body[i][0])+1]
		obe_strany[i].extend([side_1, side_2])
	print(obe_strany)

	for i in range(len(obe_strany)):
		viditelne_body.append([])
		if len(obe_strany[i][0]) > 2 and len(obe_strany[i][1]) > 2:
			if intersection_of_two_vectors(obe_strany[i][0][1][0], obe_strany[i][0][1][1], start[0], start[1], \
										   koncove_body[i][0][0], koncove_body[i][0][1], \
										   koncove_body[i][1][0], koncove_body[i][1][1]) \
				and \
				not intersection_of_two_vectors(obe_strany[i][1][1][0], obe_strany[i][1][1][1], start[0], start[1], \
											koncove_body[i][0][0], koncove_body[i][0][1], \
											koncove_body[i][1][0], koncove_body[i][1][1]):
				viditelne_body[i].extend(obe_strany[i][1])
			elif intersection_of_two_vectors(obe_strany[i][1][1][0], obe_strany[i][1][1][1], start[0], start[1], \
											koncove_body[i][0][0], koncove_body[i][0][1], \
											koncove_body[i][1][0], koncove_body[i][1][1]) \
				and \
				not intersection_of_two_vectors(obe_strany[i][0][1][0], obe_strany[i][0][1][1], start[0], start[1], \
										   koncove_body[i][0][0], koncove_body[i][0][1], \
										   koncove_body[i][1][0], koncove_body[i][1][1]) :
				viditelne_body[i].extend(obe_strany[i][0])
		elif len(obe_strany[i][0]) > 2 and len(obe_strany[i][1]) <= 2:
			if intersection_of_two_vectors(obe_strany[i][0][1][0], obe_strany[i][0][1][1], start[0], start[1], \
										   koncove_body[i][0][0], koncove_body[i][0][1], \
										   koncove_body[i][1][0], koncove_body[i][1][1]):
				viditelne_body[i].extend(obe_strany[i][1])
			else:
				viditelne_body[i].extend(obe_strany[i][0])
		elif len(obe_strany[i][1]) > 2 and len(obe_strany[i][0]) <= 2:
			if intersection_of_two_vectors(obe_strany[i][1][1][0], obe_strany[i][1][1][1], start[0], start[1], \
										   koncove_body[i][0][0], koncove_body[i][0][1], \
										   koncove_body[i][1][0], koncove_body[i][1][1]):
				viditelne_body[i].extend(obe_strany[i][0])
			else:
				viditelne_body[i].extend(obe_strany[i][1])
	return viditelne_body

def global_kon_body(start, body):
	'''
	Funkce vybírá koncové body ze všech bodů všech překážek z hlediska robota.
	:param start: Poloha robota
	:param body: Vsechny souřadnice
	:return:
	'''
	angel_points = []
	viditelne_body = []
	for i in range(len(body)):
		for k in range(len(body[i])):
			viditelne_body.append(body[i][k])
	konc_body = []
	anchor = viditelne_body[random.randint(0, len(viditelne_body) - 1)]
	v_anchor = [anchor[0] - start[0], anchor[1] - start[1]]
	min_cos = 1
	for i in range(len(viditelne_body)):
		v_k = [viditelne_body[i][0] - start[0], viditelne_body[i][1] - start[1]]
		if cos_of_vektors(v_anchor[0], v_anchor[1], v_k[0], v_k[1]) < min_cos:
			min_cos = cos_of_vektors(v_anchor[0], v_anchor[1], v_k[0], v_k[1])
			bod_1 = viditelne_body[i]
	v_bod_1 = [bod_1[0] - start[0], bod_1[1] - start[1]]
	min_cos = 1
	for k in range(len(viditelne_body)):
		v_k = [viditelne_body[k][0] - start[0], viditelne_body[k][1] - start[1]]
		if cos_of_vektors(v_bod_1[0], v_bod_1[1], v_k[0], v_k[1]) < min_cos:
			min_cos = cos_of_vektors(v_bod_1[0], v_bod_1[1], v_k[0], v_k[1])
			bod_2 = viditelne_body[k]
	konc_body.extend([bod_1, bod_2])
	for i in range(len(viditelne_body)):
		if cross_product(start[0], start[1], konc_body[0][0], konc_body[0][1], \
						 start[0], start[1], viditelne_body[i][0], viditelne_body[i][1]) == 0:
			if delka_mezi_body(start[0], start[1], konc_body[0][0], konc_body[0][1]) < \
				delka_mezi_body(start[0], start[1], viditelne_body[i][0], viditelne_body[i][1]):
				continue
			elif delka_mezi_body(start[0], start[1], konc_body[0][0], konc_body[0][1]) > \
				delka_mezi_body(start[0], start[1], viditelne_body[i][0], viditelne_body[i][1]):
				konc_body[0] = viditelne_body[i]
		if cross_product(start[0], start[1], konc_body[1][0], konc_body[1][1], \
						 start[0], start[1], viditelne_body[i][0], viditelne_body[i][1]) == 0:
			if delka_mezi_body(start[0], start[1], konc_body[1][0], konc_body[1][1]) < \
				delka_mezi_body(start[0], start[1], viditelne_body[i][0], viditelne_body[i][1]):
				continue
			elif delka_mezi_body(start[0], start[1], konc_body[1][0], konc_body[1][1]) > \
				delka_mezi_body(start[0], start[1], viditelne_body[i][0], viditelne_body[i][1]):
				konc_body[1] = viditelne_body[i]
	angel_points.extend([bod_1, bod_2])
	v_a_1 = [angel_points[0][0] - start[0], angel_points[0][1] - start[1]]
	for i in range(len(viditelne_body)):
		v_a_2 = [angel_points[1][0] - start[0], angel_points[1][1] - start[1]]
		v_k = [viditelne_body[i][0] - start[0], viditelne_body[i][1] - start[1]]
		if  cos_of_vektors(v_a_1[0], v_a_1[1],v_a_2[0], v_a_2[1]) < \
			cos_of_vektors(v_a_1[0], v_a_1[1], v_k[0], v_k[1]):
			angel_points.insert(1, viditelne_body[i])
	return konc_body, angel_points

def sin_of_vectors(x1, y1, x2, y2):
	'''
	Funkce spočítá sin úhlu mezi dvěma vektory.
	:param x1: Hodnota x prvního bodu
	:param y1: Hodnota y prvního bodu
	:param x2: Hodnota x druhého bodu
	:param y2: Hodnota y druhého bodu
	:return: Sin úhlu
	'''
	return sqrt(1 - cos_of_vektors(x1, y1, x2, y2))

def main():
	st = convexni_obal('coordinates')
	dostupne_body = available_bods([1, 20], [22, 2], st)
	konc_body = vyber_koncovych_bodu([1, 20], [22, 2], dostupne_body)
	strany = our_sides_of_figures(st, [1, 20], [20, 2])
	print(dostupne_body)
	print(konc_body)
	print(strany)

if __name__== "__main__":
  main()

# Program jsme nestihli dokončit, ale byli jsme blízko ke konečné verzi. Zatím náš robot umí spočítat konvexní
# obaly každé překážky, určit koncové body každé překážky, které robot "vidí", určit, které body jsou v rovině mezi
# ním a koncem jeho pohybu. Plánovali jsme, že pak bude robot určovat, do kterých bodů se může pohybovat, počítat
# délku každé cesty a z toho vybírat tu nejkratší.


from future import standard_library
standard_library.install_aliases()
from future.builtins import str, object
import datetime
from bson import ObjectId
from redis.exceptions import LockError
import time
from .exceptions import RetryInterrupt, MaxRetriesInterrupt, AbortInterrupt, MaxConcurrencyInterrupt
from .utils import load_class_by_path, group_iter
import gevent
import objgraph
import random
import gc
from collections import defaultdict
import traceback
import sys
import urllib.parse
import re
import linecache
import fnmatch
import encodings
import copyreg
from . import context

FINAL_STATUSES = {"timeout", "abort", "failed", "success", "interrupt", "retry", "maxretries", "maxconcurrency"}
TRANSIENT_STATUSES = {"cancel", "queued", "started"}

class Job(object):

    timeout = None
    result_ttl = None
    abort_ttl = None
    cancel_ttl = None
    max_retries = None
    retry_delay = None

    # All values above can be overrided from the TASKS config

    progress = 0

    _memory_stop = 0
    _memory_start = 0

    _current_io = None

    # Has this job been inserted in MongoDB yet?
    stored = None

    # List of statuses that don't trigger a storage of this task in MongoDB on raw queues.
    # In task config, use ("started", "success") to avoid storing successful raw tasks at all
    statuses_no_storage = None

    def __init__(self, job_id, queue=None, start=False, fetch=False):
        self.worker = context.get_current_worker()
        self.queue = queue
        self.datestarted = None

        self.collection = context.connections.mongodb_jobs.mrq_jobs

        if job_id is None:
            self.id = None
        else:
            if isinstance(job_id, bytes):
                self.id = ObjectId(job_id.decode('utf-8'))
            else:
                self.id = ObjectId(job_id)

        self.data = None
        self.saved = True

        self.task = None
        self.greenlet_switches = 0
        self.greenlet_time = 0

        self._trace_mongodb = defaultdict(int)

        if start:
            self.fetch(start=True, full_data=False)
        elif fetch:
            self.fetch(start=False, full_data=False)

    @property
    def redis_max_concurrency_key(self):
        """ Returns the global redis key used to control job concurrency """
        return "%s:c:%s" % (context.get_current_config()["redis_prefix"], self.data["path"])

    def exists(self):
        """ Returns True if a job with the current _id exists in MongoDB. """
        return bool(self.collection.find_one({"_id": self.id}, projection={"_id": 1}))

    def fetch(self, start=False, full_data=True):
        """ Get the current job data and possibly flag it as started. """

        if self.id is None:
            return self

        if full_data is True:
            fields = None
        elif isinstance(full_data, dict):
            fields = full_data
        else:
            fields = {
                "_id": 0,
                "path": 1,
                "params": 1,
                "status": 1,
                "retry_count": 1,
            }

        if start:
            self.datestarted = datetime.datetime.utcnow()
            self.set_data(self.collection.find_and_modify(
                {
                    "_id": self.id,
                    "status": {"$nin": ["cancel", "abort", "maxretries"]}
                },
                {"$set": {
                    "status": "started",
                    "datestarted": self.datestarted,
                    "worker": self.worker.id
                },
                "$unset": {
                    "dateexpires": 1 # we don't want started jobs to expire unexpectedly
                }},
                projection=fields)
            )

            context.metric("jobs.status.started")

        else:
            self.set_data(self.collection.find_one({
                "_id": self.id
            }, projection=fields))

        if self.data is None:
            context.log.info(
                "Job %s not found in MongoDB or status was cancelled!" %
                self.id)

        self.stored = True

        return self

    def get_task_config(self):
        cfg = context.get_current_config()
        return cfg.get("tasks", {}).get(
            self.data["path"]
        ) or {}

    def set_data(self, data):
        self.data = data
        if self.data is None:
            return

        if "path" in self.data:
            cfg = context.get_current_config()
            task_def = self.get_task_config()

            self.timeout = task_def.get("timeout", cfg["default_job_timeout"])
            self.default_ttl = task_def.get("default_ttl", cfg["default_job_ttl"])
            self.result_ttl = task_def.get("result_ttl", cfg["default_job_result_ttl"]) # success ttl
            self.abort_ttl = task_def.get("abort_ttl", cfg["default_job_abort_ttl"])
            self.cancel_ttl = task_def.get("cancel_ttl", cfg["default_job_cancel_ttl"])
            self.max_retries = task_def.get("max_retries", cfg["default_job_max_retries"])
            self.retry_delay = task_def.get("retry_delay", cfg["default_job_retry_delay"])

    def set_progress(self, ratio, save=False):
        self.data["progress"] = ratio
        self.saved = False

        # If not saved, will be updated in the next worker report
        if save:
            self.save()

    def save(self):
        """ Persists the current job metadata to MongoDB. Will be called at each worker report. """

        if not self.saved and self.data and "progress" in self.data:
            # TODO should we save more fields?
            self.collection.update({"_id": self.id}, {"$set": {
                "progress": self.data["progress"]
            }})
            self.saved = True

    @classmethod
    def insert(cls, jobs_data, queue=None, statuses_no_storage=None, return_jobs=True, w=None, j=None):
        """ Insert a job into MongoDB """

        now = datetime.datetime.utcnow()
        for data in jobs_data:
            if data["status"] == "started":
                data["datestarted"] = now

        no_storage = (statuses_no_storage is not None) and ("started" in statuses_no_storage)
        if no_storage and return_jobs:
            for data in jobs_data:
                data["_id"] = ObjectId()  # Give the job a temporary ID
        else:
            inserted = context.connections.mongodb_jobs.mrq_jobs.insert(
                jobs_data,
                manipulate=True,
                w=w,
                j=j
            )

        if return_jobs:
            jobs = []
            for data in jobs_data:
                job = cls(data["_id"], queue=queue)
                job.set_data(data)
                job.statuses_no_storage = statuses_no_storage
                job.stored = (not no_storage)
                if data["status"] == "started":
                    job.datestarted = data["datestarted"]
                jobs.append(job)

            return jobs
        else:
            return inserted

    def _attach_original_exception(self, exc):
        """ Often, a retry will be raised inside an "except" block.
            This Keep track of the first exception for debugging purposes """

        original_exception = sys.exc_info()
        if original_exception[0] is not None:
            exc.original_exception = original_exception

    def retry(self, queue=None, delay=None, max_retries=None):
        """ Marks the current job as needing to be retried. Interrupts it. """

        max_retries = max_retries
        if max_retries is None:
            max_retries = self.max_retries

        if self.data.get("retry_count", 0) >= max_retries:
            raise MaxRetriesInterrupt()

        exc = RetryInterrupt()

        exc.queue = queue or self.queue or self.data.get("queue") or "default"
        exc.retry_count = self.data.get("retry_count", 0) + 1
        exc.delay = delay
        if exc.delay is None:
            exc.delay = self.retry_delay

        self._attach_original_exception(exc)

        raise exc

    def abort(self):
        """ Aborts the current task mid-excution. """
        exc = AbortInterrupt()
        self._attach_original_exception(exc)
        raise exc

    def cancel(self):
        """ Markes the current job as cancelled. Doesn't interrupt it. """
        self._save_status("cancel")

    def requeue(self, queue=None, retry_count=0):
        """ Requeues the current job. Doesn't interrupt it """

        if not queue:
            if not self.data or not self.data.get("queue"):
                self.fetch(full_data={"_id": 0, "queue": 1, "path": 1})
            queue = self.data["queue"]

        self._save_status("queued", updates={
            "queue": queue,
            "datequeued": datetime.datetime.utcnow(),
            "retry_count": retry_count
        })

    def perform(self):
        """ Loads and starts the main task for this job, the saves the result. """

        if self.data is None:
            return

        context.log.debug("Starting %s(%s)" % (self.data["path"], self.data["params"]))
        task_class = load_class_by_path(self.data["path"])

        self.task = task_class()

        self.task.is_main_task = True

        if not self.task.max_concurrency:

            result = self.task.run_wrapped(self.data["params"])

        else:

            if self.task.max_concurrency > 1:
                raise NotImplementedError()

            lock = None
            try:

                # TODO: implement a semaphore
                lock = context.connections.redis.lock(self.redis_max_concurrency_key, timeout=self.timeout + 5)
                if not lock.acquire(blocking=True, blocking_timeout=0):
                    raise MaxConcurrencyInterrupt()

                result = self.task.run_wrapped(self.data["params"])

            finally:
                try:
                    if lock:
                        lock.release()
                except LockError:
                    pass

        self.save_success(result)

        if context.get_current_config().get("trace_greenlets"):

            # TODO: this is not the exact greenlet_time measurement because it doesn't
            # take into account the last switch's time. This is why we force a last switch.
            # This does cause a performance overhead. Instead, we should print the
            # last timing directly from the trace() function in context?

            # pylint: disable=protected-access

            gevent.sleep(0)
            current_greenlet = gevent.getcurrent()
            t = (datetime.datetime.utcnow() - self.datestarted).total_seconds()

            context.log.debug(
                "Job %s success: %0.6fs total, %0.6fs in greenlet, %s switches" %
                (self.id,
                 t,
                 current_greenlet._trace_time,
                 current_greenlet._trace_switches - 1)
            )

        else:
            context.log.debug("Job %s success: %0.6fs total" % (
                self.id, (datetime.datetime.utcnow() -
                          self.datestarted).total_seconds()
            ))

        return result

    def wait(self, poll_interval=1, timeout=None, full_data=False):
        """ Wait for this job to finish. """

        end_time = None
        if timeout:
            end_time = time.time() + timeout

        while end_time is None or time.time() < end_time:

            job_data = self.collection.find_one({
                "_id": ObjectId(self.id),
                "status": {"$nin": ["started", "queued"]}
            }, projection=({
                "_id": 0,
                "result": 1,
                "status": 1
            } if not full_data else None))

            if job_data:
                return job_data

            time.sleep(poll_interval)
        raise Exception("Waited for job result for %s seconds, timeout." % timeout)

    def kill(self, block=False, reason="unknown"):
        """ Forcefully kill all greenlets associated with this job """

        current_greenletid = id(gevent.getcurrent())

        trace = "Job killed: %s" % reason
        for greenlet, job in context._GLOBAL_CONTEXT["greenlets"].values():
            greenletid = id(greenlet)
            if job and job.id == self.id and greenletid != current_greenletid:
                greenlet.kill(block=block)
                trace += "\n\n--- Greenlet %s ---\n" % greenletid
                trace += "".join(traceback.format_stack(greenlet.gr_frame))
            context._GLOBAL_CONTEXT["greenlets"].pop(greenletid, None)

        if reason == "timeout" and self.data["status"] != "timeout":
            updates = {
                "exceptiontype": "TimeoutInterrupt",
                "traceback": trace
            }
            self._save_status("timeout", updates=updates, exception=False)

    def save_retry(self, retry_exc):

        # If delay=0, requeue right away, don't go through the "retry" status
        if retry_exc.delay == 0:
            self.requeue(queue=retry_exc.queue, retry_count=retry_exc.retry_count)

        else:

            dateretry = datetime.datetime.utcnow() + datetime.timedelta(seconds=retry_exc.delay)
            updates = {
                "dateretry": dateretry,
                "queue": retry_exc.queue,
                "retry_count": retry_exc.retry_count
            }

            self._save_status("retry", updates, exception=True)

    def _save_traceback_history(self, status, trace, job_exc):
        """ Create traceback history or add a new traceback to history. """
        failure_date = datetime.datetime.utcnow()

        new_history = {
            "date": failure_date,
            "status": status,
            "exceptiontype": job_exc.__name__
        }

        traces = trace.split("---- Original exception: -----")
        if len(traces) > 1:
            new_history["original_traceback"] = traces[1]
        worker = context.get_current_worker()
        if worker:
            new_history["worker"] = worker.id
        new_history["traceback"] = traces[0]
        self.collection.update({
            "_id": self.id
        }, {"$push": {"traceback_history": new_history}})

    def save_success(self, result=None):

        dateexpires = datetime.datetime.utcnow() + datetime.timedelta(seconds=self.result_ttl)
        updates = {
            "dateexpires": dateexpires
        }
        if result is not None:
            updates["result"] = result
        if "progress" in self.data:
            updates["progress"] = 1

        self._save_status("success", updates)

    def save_cancel(self):

        dateexpires = datetime.datetime.utcnow() + datetime.timedelta(seconds=self.cancel_ttl)
        updates = {
            "dateexpires": dateexpires
        }

        self._save_status("cancel", updates)

    def save_abort(self):
        dateexpires = datetime.datetime.utcnow() + datetime.timedelta(seconds=self.abort_ttl)
        updates = {
            "dateexpires": dateexpires
        }

        self._save_status("abort", updates, exception=True)

    def _save_status(self, status, updates=None, exception=False, w=None, j=None):

        if self.id is None:
            return

        # Forbid some status transitions
        if self.data and self.data.get("status") in FINAL_STATUSES and status not in TRANSIENT_STATUSES:
            context.log.error("Can't go from status %s to %s" % (self.data["status"], status))
            return

        context.metric("jobs.status.%s" % status)

        if self.stored is False and self.statuses_no_storage is not None and status in self.statuses_no_storage:
            return

        now = datetime.datetime.utcnow()
        db_updates = {
            "status": status,
            "dateupdated": now
        }

        # we don't want started jobs to expire unexpectedly
        if status not in ["started", "success", "abort", "cancel"] and hasattr(self, "default_ttl") and self.default_ttl is not None:
            db_updates["dateexpires"] = (self.data.get("datequeued") or now) + datetime.timedelta(seconds=self.default_ttl)

        db_updates.update(updates or {})

        if self.datestarted:
            db_updates["totaltime"] = (now - self.datestarted).total_seconds()

        if context.get_current_config().get("trace_greenlets"):
            current_greenlet = gevent.getcurrent()

            # TODO are we sure the current job is doing the save_status() on itself?
            if hasattr(current_greenlet, "_trace_time"):
                # pylint: disable=protected-access
                db_updates["time"] = current_greenlet._trace_time
                db_updates["switches"] = current_greenlet._trace_switches

        if exception:
            trace = traceback.format_exc()
            context.log.error(trace)
            exc, value = sys.exc_info()[0:2]
            if hasattr(value, "subpool_traceback"):
                trace = "Exception first caught in a subpool. Traceback:\n%s\n%s" % (value.subpool_traceback, trace)
            db_updates["traceback"] = trace
            db_updates["exceptiontype"] = exc.__name__

        if self.data:
            self.data.update(db_updates)
            # get all data before updating them
            current_queue = (db_updates or {}).get("queue") or self.data["queue"]
            old_queue = self.data.get("queue")
            old_status = self.data.get("status")
            raw_queue = self.data.get("raw_queue")
            retry_count = self.data.get("retry_count", 0)

        # In the most common case, we allow an optimization on Mongo writes
        if status == "success":
            if w is None:
                w = getattr(self.task, "status_success_update_w", None)
            if j is None:
                j = getattr(self.task, "status_success_update_j", None)

        # This job wasn't inserted because "started" is in statuses_no_storage
        # So we must insert it for the first time instead of updating it.
        if self.stored is False:
            db_updates["queue"] = self.data["queue"]
            db_updates["params"] = self.data["params"]
            db_updates["path"] = self.data["path"]
            self.collection.insert(db_updates, w=w, j=j, manipulate=True)
            self.id = db_updates["_id"]  # Persistent ID assigned by the server
            self.stored = True

        else:
            self.collection.update({
                "_id": self.id
            }, {"$set": db_updates}, w=w, j=j, manipulate=False)

        if exception:
            self._save_traceback_history(status, trace, exc)

        if self.data:
            with context.connections.redis.pipeline(transaction=False) as pipe:
                if status != "started":
                    # Queue change
                    if current_queue != old_queue:
                        pipe.decr("queuesize:%s" % old_queue)
                        if status == "queued":
                            pipe.incr("queuesize:%s" % current_queue)

                    # Regular queues
                    elif status == "queued" and old_status != "started":
                        pipe.incr("queuesize:%s" % current_queue)

                    elif status != "queued" and not raw_queue:
                        pipe.decr("queuesize:%s" % current_queue)

                    # Raw queues retries
                    elif (db_updates or {}).get("retry_count", 0) > retry_count:
                        pipe.incr("queuesize:%s" % current_queue)

                    pipe.expire("queuesize:%s" % current_queue, context.get_current_config().get("queue_ttl"))
                pipe.execute()

    def set_current_io(self, io_data):

        # pylint: disable=protected-access

        if io_data is None:
            if not self._current_io:
                return

            t = time.time() - self._current_io["started"]
            if self.worker and self.data.get("path"):
                self.worker._traced_io["types"][self._current_io["type"]] += t
                self.worker._traced_io["tasks"][self.data["path"]] += t
                self.worker._traced_io["total"] += t

            self._current_io = None

        else:
            io_data["started"] = time.time()
            self._current_io = io_data

    def trace_memory_clean_caches(self):
        """ Avoid polluting results with some builtin python caches """

        urllib.parse.clear_cache()
        re.purge()
        linecache.clearcache()
        copyreg.clear_extension_cache()

        if hasattr(fnmatch, "purge"):
            fnmatch.purge()  # pylint: disable=no-member
        elif hasattr(fnmatch, "_purge"):
            fnmatch._purge()  # pylint: disable=no-member

        if hasattr(encodings, "_cache") and len(encodings._cache) > 0:
            encodings._cache = {}

        for handler in context.log.handlers:
            handler.flush()

    def trace_memory_start(self):
        """ Starts measuring memory consumption """

        self.trace_memory_clean_caches()

        objgraph.show_growth(limit=30)

        gc.collect()
        self._memory_start = self.worker.get_memory()["total"]

    def trace_memory_stop(self):
        """ Stops measuring memory consumption """

        self.trace_memory_clean_caches()

        objgraph.show_growth(limit=30)

        trace_type = context.get_current_config()["trace_memory_type"]
        if trace_type:

            filename = '%s/%s-%s.png' % (
                context.get_current_config()["trace_memory_output_dir"],
                trace_type,
                self.id)

            chain = objgraph.find_backref_chain(
                random.choice(
                    objgraph.by_type(trace_type)
                ),
                objgraph.is_proper_module
            )
            objgraph.show_chain(chain, filename=filename)
            del filename
            del chain

        gc.collect()
        self._memory_stop = self.worker.get_memory()["total"]

        diff = self._memory_stop - self._memory_start

        context.log.debug("Memory diff for job %s : %s" % (self.id, diff))

        # We need to update it later than the results, we need them off memory
        # already.
        self.collection.update(
            {"_id": self.id},
            {"$set": {
                "memory_diff": diff
            }},
            w=1
        )

def get_job_result(job_id):
    job = Job(job_id)
    job.fetch(full_data={"result": 1, "status": 1, "_id": 0})
    return job.data

def queue_raw_jobs(queue, params_list, **kwargs):
    """ Queue some jobs on a raw queue """

    from .queue import Queue
    queue_obj = Queue(queue)
    queue_obj.enqueue_raw_jobs(params_list, **kwargs)
    # No need to store queue size as we already have a fast way to get raw queue size

def queue_job(main_task_path, params, **kwargs):
    """ Queue one job on a regular queue """

    return queue_jobs(main_task_path, [params], **kwargs)[0]

def set_queues_size(size_by_queues, action="incr"):
    if len(size_by_queues) > 0:
        with context.connections.redis.pipeline(transaction=False) as pipe:
            action_func = getattr(pipe, action)
            for queue in size_by_queues:
                action_func("queuesize:%s" % queue, amount=size_by_queues[queue])
                pipe.expire("queuesize:%s" % queue, context.get_current_config().get("queue_ttl"))
            pipe.execute()

def queue_jobs(main_task_path, params_list, queue=None, batch_size=1000):
    """ Queue multiple jobs on a regular queue """
    if len(params_list) == 0:
        return []
    if queue is None:
        task_def = context.get_current_config().get("tasks", {}).get(main_task_path) or {}
        queue = task_def.get("queue", "default")

    from .queue import Queue
    queue_obj = Queue(queue)

    if queue_obj.is_raw:
        raise Exception("Can't queue regular jobs on a raw queue")

    all_ids = []

    for params_group in group_iter(params_list, n=batch_size):

        context.metric("jobs.status.queued", len(params_group))

        # Insert the job in MongoDB
        job_ids = Job.insert([{
            "path": main_task_path,
            "params": params,
            "queue": queue,
            "datequeued": datetime.datetime.utcnow(),
            "status": "queued"
        } for params in params_group], w=1, return_jobs=False)

        all_ids += job_ids

    queue_obj.notify(len(all_ids))
    set_queues_size({queue: len(all_ids)})

    return all_ids


#!/usr/bin/env /usr/bin/python36

input_data_file = "part1.data"

def slurp_input(input_file):
    """
    Read the input file.
    :param input_file:
    :return: A list of sets. Each set represents the given answers in a group.
    """
    temp = open(input_file,'r').read().splitlines()
    return temp

def main():

    # uncomment the next line to read the input data from the test file
    # input_data_file = "part1_test.data"

    all_input = slurp_input(input_data_file)

    laenge = len(all_input[0])

    zeros = []
    ones = []
    most = []
    least = []
    for index in range(0, laenge):
        zeros.append(0)
        ones.append(0)
        most.append(0)
        least.append(0)

    # print(all_input)

    for zeile in all_input:
        index = 0
        zeros.append(0)
        ones.append(0)
        for buchstabe in zeile:
            if buchstabe == "0":
                zeros[index] += 1
            elif buchstabe == "1":
                ones[index] += 1
            else:
                print("Error: {}".format(zeile))
            index += 1

    for index in range(0, len(zeile)):
        if ones[index] > zeros[index]:
            most[index] = "1"
            least[index] = "0"
        elif zeros[index] > ones[index]:
            most[index] = "0"
            least[index] = "1"
        else:
            print("Error: ones and zeros are identical ({}) in column {}".format(zeros[index], index))

    # print("Most: {}".format(most))
    # print("Least: {}".format(least))
    most_string = ''.join(most)
    most_decimal = int(most_string, 2)
    # print("most: {}".format(int(most_string, 2)))
    least_string = ''.join(least)
    least_decimal = int(least_string, 2)

    total = most_decimal * least_decimal
    # print("least: {}".format(int(least_string, 2)))

    print("Total: {}".format(total))

if __name__ == "__main__":
    main()


import asyncio
import os

from discord import team
from guild import guildSignup
import discord
from discord.ext import commands
from jsonDatabase import *
from DiscordPetShop import Inventory
from StarterClass import starterClass
from profileStats import profileStats, inventorys
from quests import guesser, coinFlip
from location import locations
from guild import guildSignup
from levelSystem import *
from petShop import petShops, buyPets
from Shops import *
from lootFromDungeon import *
from fightingSystem import *
from heal import healing
from abilities import *
from artifactStats import *
from Equipment import *
from helpText import helps
client = discord.Client()
client = commands.Bot(command_prefix='-')
client.remove_command('help')
#commands
@client.event
async def on_ready():
    await client.change_presence(activity=discord.Game(name="-help for information"))
@client.command()
async def petshop(ctx):
    await ctx.send(Inventory)
    await ctx.message.author
@client.command()
async def profile(ctx):
    id = ctx.message.author.id
    embed = discord.Embed(title="Profile", description=profileStats(id))
    await ctx.send(embed=embed)
@client.command()
async def starter(ctx):
    check(id)
    firstUser = ctx.message.author.id
    embed = discord.Embed(title="StarterClasses", description=
    '''
    🙤Swordsman
    \t-Swordsman, are more durable, slower than Archer, and it's the most durable class.\n
    🙤Archer
    \t-Archer, are more faster and are better against bosses.\n
    🙤Mage
    \t-Mage, Stronger than Swordsman, but not more durable,not stronger than archer, and it is the slowest class.\n
    Write your desired class, this can't be changed in the future for free!	(─‿‿─)
    ''')
    await ctx.send(embed=embed)
    try:
        msg = await client.wait_for("message", timeout=30, check=lambda message: message.author == ctx.author and
        message.channel == ctx.channel)
    except asyncio.TimeoutError:
        await ctx.message.delete()
    await ctx.send(starterClass(msg, firstUser))
@client.command()
async def quests(ctx):
    embed = discord.Embed(title="Way to Earn Coin", description=
    '''
    🙤Free For Everyone:
    \t-guesser
    \t-coinflip
    \t-find(-location to see all locations)\n
    🙤Guilds only:
    \t-dungeon\n
    🙤Casino only:
    \t(on Progress)
    ''')
    await ctx.send(embed=embed)
@client.command()
async def coinflip(ctx, ammount=0, HorT=None):
    id = ctx.message.author.id
    if getDataValue(id, 'coin') >= 10 and  getDataValue(id, 'coin') >= ammount:
        if HorT != None:
            HorT = HorT.lower()
        if ammount < 10  or ammount > 100 or HorT == None:
            await ctx.send("Choose your bet(min 10, max 100) and guessing side(-coinflip 10 tails or heads)")
        elif HorT == 'heads' or HorT == 'tails':
            await ctx.send(coinFlip(ammount, HorT, id))
        else:
            await ctx.send("Choose your bet(min 10, max 100) and guessing side(-coinflip 10 tails or heads)")
    else:
        await ctx.send("You don't have enough coins. <(￣︶￣)>")

@client.command()
async def guess(ctx, gNum=0, diff=0):
    id = ctx.message.author.id
    if getDataKey(id, 'class'):
        if gNum == None or diff == None:
            await ctx.send("Choose a number and 1 out of what(-guesser 10 10(min 10 no max), this an example, the user picked 10 and it is 1-100) o(≧▽≦)o")
        elif gNum > 0 and diff > 9:
            await ctx.send(guesser(gNum, diff, id))
        else:
            await ctx.send("Choose a number and 1 out of what(-guesser 10 10(min 10 no max), this an example, the user picked 10 and it is 1-100) ٩(｡•́‿•̀｡)۶")
    else:
        await ctx.send("Please choose a class first. (≧◡≦)")
@client.command()
async def guild(ctx):
    id = ctx.message.author.id
    if getDataKey(id, 'guild'):
        await ctx.send("You are already signed in")
    else:
        await ctx.send("Hello, do you want to buy the guild pass for 100 coins? y/n")
        try:
            msg = await client.wait_for("message", timeout=30, check=lambda message: message.author == ctx.author and
            message.channel == ctx.channel)
        except asyncio.TimeoutError:
            await ctx.message.delete()
        await ctx.send(guildSignup(id, msg))

@client.command()
async def find(ctx, location=None):
    id = ctx.message.author.id
    if location != None:
        text = locations(id, location)
    else:
        await ctx.send("You didn't pick a location, do -find (location) ex. forest")
    await ctx.send(text)
@client.command()
async def sell(ctx, item, ammount=1):
    id = ctx.message.author.id
    if item == None:
        ctx.send('Please write the item name after the command.')
    await ctx.send(sells(id, item, ammount))
@client.command()
async def inventory(ctx):
    id = ctx.message.author.id
    text = ''
    for key, value in inventorys(id).items():
        if value != 0:
            text += f"{key}: {value} \n"
    await ctx.send(text)

@client.command()
async def dungeon(ctx, floor=None):
    if floor == None:
        await ctx.send("enter floor number")
    id = ctx.message.author.id
    user = openNewDic(id, 'userStats')
    enemy = openNewDic(id, 'enemy')
    if getDataKey(id, 'guild'):
        enemys(id, floor)
        await ctx.send("entering dungeon")
        enemy = openNewDic(id, 'enemy')
        await ctx.send(f"Enemy Health: {enemy['hp']}")
        if floor == None:
            await ctx.send("enter floor number")
        else:
            while user['hp'] > 0:
                while enemy['hp'] > 0:
                    abilities = ability(id)
                    await ctx.send(f"Choose your ability, \n{abilities}")
                    try:
                        msg = await client.wait_for("message", timeout=30, check=lambda message: message.author == ctx.author and
                        message.channel == ctx.channel)
                    except asyncio.TimeoutError:
                        await ctx.send("You took to long")
                    await ctx.send(fight(id, msg))
                    user = openNewDic(id, 'userStats')
                    enemy = openNewDic(id, 'enemy')
                    if enemy['hp'] <= 0:
                        rarity, artifact = lootGain(id, floor)
                        coin = coinGain(id, floor)
                        exp = xpGain(id, floor)
                        insertToArtifactInv(id, rarity, artifact)

                        text = f"{artifact}: \n"
                        for key, value in openArtifactsInv(id, artifact).items():
                            text += f"{key}: {value} \n"
                        await ctx.send(f"You killed enemy, earned {coin} coin, earned {exp} xp")
                        await ctx.send(f"Artifact stats are... \n{text}")
                        await ctx.send(f"Do you want to equip the artifact/weapon? y/n, else it will be sold")
                        try:
                            msg = await client.wait_for("message", timeout=30, check=lambda message: message.author == ctx.author and
                            message.channel == ctx.channel)
                        except asyncio.TimeoutError:
                            await ctx.send("You took to long, item will be sold")
                        if msg.content.lower() == 'y' or msg.content.lower() == 'yes':
                            equip(id, artifact)
                            await ctx.send("equiped")
                        else:
                            await ctx.send(sellArtifact(id, rarity))
                        while levelUp(id, getDataValue(id, 'level'), getDataValue(id, 'exp')):
                            await ctx.send("LevelUp")
                            levelUp(id, getDataValue(id, 'level'), getDataValue(id, 'exp'))
                    elif user['hp'] <= 0:
                        await ctx.send("You died")
                        break
                user = openNewDic(id, 'userStats')
                enemy = openNewDic(id, 'enemy')

                if user['hp'] <= 0:
                    break
                else:
                    break
            else:
                await ctx.send("You need to heal")

@client.command()
async def heal(ctx):
    id = ctx.message.author.id
    await ctx.send("Do you want to heal? y/n")
    try:
        msg = await client.wait_for("message", timeout=30, check=lambda message: message.author == ctx.author and
        message.channel == ctx.channel)
    except asyncio.TimeoutError:
        await ctx.send("You took to long")
    if msg.content.lower() == 'y' or msg.content.lower() == 'yes':
        await ctx.send(healing(id))
    else:
        return "maybe next time then..."

@client.command()
async def location(ctx):
    embed = discord.Embed(title="Locations", description='''
    🙤Forest
    🙤River
    🙤Cave
    🙤Lake
    ''')
    await ctx.send(embed=embed)

@client.command()
async def shop(ctx, item=None):
    id = ctx.message.author.id
    text = shopList()
    embed = discord.Embed(title="Shop Items", description=text)
    if item != None:
        await ctx.send(buy(id, item))

    else:
        await ctx.send(embed=embed)

@client.command()
async def artifacts(ctx):
    id = ctx.message.author.id
    text = userArtifacts(id)
    embed = discord.Embed(title="Profile Artifacts", description=text)
    await ctx.send(embed=embed)

@client.command()
async def upgrade(ctx, artifact):
    id = ctx.message.author.id
    if artifact != None:
        await ctx.send(upgrades(id, artifact))
    else:
        await ctx.send("-upgrade (artifact you want to upgrade) ex. -upgrade weapon")

@client.command()
async def help(ctx):
    text = helps()
    embed = discord.Embed(title="Tutorial for Yuki's DiscordBot", description=text)
    embed.set_footer(text="This is yuki's beta version of the game, there are a lot missed future, it took 3 weeks, I think, I forgot... well have fun ig")
    await ctx.send(embed=embed)
#hiddenCode
def hiddenCode():
    path = "..\\YukiChanToken"
    os.chdir(path)
    with open('token.txt', 'r') as f:
        token = f.read()
        client.run(token)
hiddenCode()


from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from accounts.forms import *
from django.template.context_processors import csrf
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators.csrf import csrf_exempt
from django.urls import reverse
from django.views.generic import View
from django.template.loader import get_template
from . utils import render_to_pdf #created in step 4
from django.utils.encoding import smart_str
import io
import simplejson
from accounts.models import *
from .models import *
import datetime
from django.http import HttpResponse,HttpResponseRedirect
from django.urls import reverse
from .forms import *

def index(request):
    user = request.user
    users = User.objects.all
    contOp = User.objects.filter(tipo='operadora').count()
    contRen = ""
    args = {'title':'Home','user':user,'users':users,'contRen':contRen,'contOp':contOp}
    return render(request,"index.html",args)
#_---------------------------------------------------
def registar_cliente(request):
    form = ClienteForm(request.POST)
    if request.POST:
        print(form.errors)
        form = ClienteForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_cliente'))
            #return HttpResponseRedirect(reverse('main:registar_cliente',args = {id_apolice}))

    args = {'title':'Registar',"form":form}
    return render(request,"registar_cliente.html",args)

def listar_clientes(request):
    clientes = Cliente.objects.all()

    args = {'title':'Listar',"clientes":clientes}
    return render(request,"listar_clientes.html",args)

def editar_cliente(request,id):
    cliente = Cliente.objects.get(id = id)
    form = ClienteForm(instance = cliente)
    if request.POST:
        form = ClienteForm(request.POST,instance = cliente)
        print(form.data["data_nascimento"])
        print(form.errors)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:listar_clientes'))

    args = {'title':'Editar',"form":form}
    return render(request,"registar_cliente.html",args)

def eliminar_cliente(request,id):
    cliente = Cliente.objects.get(id = id)
    cliente.delete()
    return HttpResponseRedirect(reverse('main:listar_clientes'))
#_---------------------------------------------------
def registar_cartao(request):
    form = CartaoForm(request.POST)
    if request.POST:
        form = CartaoForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_cartao'))

    args = {'title':'Registar',"form":form}
    return render(request,"registar_cartao.html",args)

def listar_cartoes(request):
    cartoes = Cartao.objects.all()

    args = {'title':'Listar',"cartoes":cartoes}
    return render(request,"listar_cartoes.html",args)

def gerar_bilhete(request):
    form = BilheteForm(request.POST)
    lista = Bilhete.objects.all()
    if request.POST:
        print(form.errors)
        form = BilheteForm(data = request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:gerar_bilhete'))
    args = {'title':'Gerar',"form":form,'lista':lista}
    return render(request,"gerar_bilhete.html",args)

def editar_cartao(request,id):
    cartao = Cartao.objects.get(id = id)
    form = CartaoForm(instance = cartao)
    if request.POST:
        form = CartaoForm(data = request.POST,files = request.FILES,instance = cartao)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:listar_cartoes'))

    args = {'title':'Editar',"form":form}
    return render(request,"registar_cartao.html",args)

def eliminar_cartao(request,id):
    cartao = Cartao.objects.get(id = id)
    cartao.delete()
    return HttpResponseRedirect(reverse('main:listar_cartoes'))
#-----------------------------------------------------------------
def registar_carreira(request):
    form = CarreiraForm(request.POST)
    if request.POST:
        form = CarreiraForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_carreira'))

    args = {'title':'Registar',"form":form}
    return render(request,"registar_carreira.html",args)

def listar_carreiras(request):
    carreiras = Carreira.objects.all()

    args = {'title':'Listar',"carreiras":carreiras}
    return render(request,"listar_carreiras.html",args)

def editar_carreira(request,id):
    carreira = Carreira.objects.get(id = id)
    form = CarreiraForm(instance = carreira)
    if request.POST:
        form = CarreiraForm(data = request.POST,files = request.FILES,instance = cliente)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:listar_carreiras'))

    args = {'title':'Editar',"form":form}
    return render(request,"registar_carreira.html",args)

def eliminar_carreira(request,id):
    carreira = Carreira.objects.get(id = id)
    carreira.delete()
    return HttpResponseRedirect(reverse('main:listar_carreiras'))
#------------------------------------------------------------------
def registar_autocarro(request):
    form = AutocarroForm(request.POST)
    if request.POST:
        form = AutocarroForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_autocarro'))

    args = {'title':'Registar',"form":form}
    return render(request,"registar_autocarro.html",args)

def listar_autocarros(request):
    autocarros = Autocarro.objects.all()

    args = {'title':'Listar',"autocarros":autocarros}
    return render(request,"listar_autocarros.html",args)

def associar_autocarro_carreira(request,id):
    autocarro = Autocarro.objects.get(id = id)

    if AutocarroCarreira.objects.filter(autocarro = autocarro):
        autocarro_carreira = AutocarroCarreira.objects.get(autocarro = autocarro)
        form = AutocarroCarreiraForm(instance = autocarro_carreira)
    else:
        form = AutocarroCarreiraForm(data = request.POST)

    if request.POST:
        if AutocarroCarreira.objects.filter(autocarro = autocarro):
            autocarro_carreira = AutocarroCarreira.objects.get(autocarro = autocarro)
            form = AutocarroCarreiraForm(data = request.POST,instance = autocarro_carreira)
        else:
            form = AutocarroCarreiraForm(data = request.POST)
        if form.is_valid():
            f = form.save(commit = False)
            f.autocarro = autocarro
            f.save()
            return HttpResponseRedirect(reverse('main:listar_autocarros'))

    args = {'title':'Associar',"form":form}
    return render(request,"associar_autocarro_carreira.html",args)

def editar_autocarro(request,id):
    autocarro = Carreira.objects.get(id = id)
    form = AutocarroForm(instance = autocarro)
    if request.POST:
        form = AutocarroForm(data = request.POST,files = request.FILES,instance = autocarro)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:listar_autocarros'))

    args = {'title':'Editar',"form":form}
    return render(request,"registar_autocarro.html",args)

def eliminar_autocarro(request,id):
    autocarro = Autocarro.objects.get(id = id)
    autocarro.delete()
    return HttpResponseRedirect(reverse('main:listar_autocarros'))

def registar_avaria_autocarro(request):
    form = AvariaForm(request.POST)
    avarias = Avaria.objects.all()
    if request.POST:
        form = AvariaForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_avaria_autocarro'))

    args = {'title':'Registar',"form":form,'avarias':avarias}
    return render(request,"registar_autocarro.html",args)

def listar_avarias(request):
    avarias = Avaria.objects.all()

    args = {'title':'Listar',"avarias":avarias}
    return render(request,"listar_avarias.html",args)

def enviar_autocarro_sub(request,id):
    carreira = Carreira.objects.get(id = id)

    if AutocarroCarreira.objects.filter(carreira = carreira):
        autocarro_carreira = AutocarroCarreira.objects.get(carreira = carreira)
        form = CarreiraAutocarroForm(instance = autocarro_carreira)
    else:
        form = CarreiraAutocarroForm(data = request.POST)

    if request.POST:
        if AutocarroCarreira.objects.filter(carreira = carreira):
            autocarro_carreira = AutocarroCarreira.objects.get(carreira = carreira)
            form = CarreiraAutocarroForm(data = request.POST,instance = autocarro_carreira)
        else:
            form = CarreiraAutocarroForm(data = request.POST)
        if form.is_valid():
            f = form.save(commit = False)
            f.carreira = carreira
            f.save()
            return HttpResponseRedirect(reverse('main:listar_carreiras'))

    args = {'title':'Enviar',"form":form}
    return render(request,"associar_autocarro_carreira.html",args)
#-----------------------------------------------------------------------
def registar_paragem(request):
    form = ParagemForm(request.POST)
    paragens = Paragem.objects.all()
    if request.POST:
        form = ParagemForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_paragem'))

    args = {'title':'Registar',"form":form,"paragens":paragens}
    return render(request,"registar_paragem.html",args)

def editar_paragem(request,id):
    paragem = Paragem.objects.get(id = id)
    paragens = Paragem.objects.all()
    form = ParagemForm(instance = paragem)
    if request.POST:
        form = ParagemForm(data = request.POST,files = request.FILES,instance = paragem)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_paragem'))

    args = {'title':'Editar',"form":form,"paragens":paragens}
    return render(request,"registar_paragem.html",args)

def eliminar_paragem(request,id):
    paragem = Paragem.objects.get(id = id)
    paragem.delete()
    return HttpResponseRedirect(reverse('main:registar_paragem'))
#-----------------------------------------------------------------------
def registar_percurso(request):
    form = PercursoForm(request.POST)
    percursos = Percurso.objects.all()
    if request.POST:
        form = PercursoForm(data = request.POST,files = request.FILES)
        print(form.errors)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_percurso'))

    args = {'title':'Registar',"form":form,"percursos":percursos}
    return render(request,"registar_percurso.html",args)

def editar_percurso(request,id):
    percurso = Percurso.objects.get(id = id)
    percursos = Percurso.objects.all()
    form = PercursoForm(instance = ponto)
    if request.POST:
        form = PercursoForm(data = request.POST,files = request.FILES,instance = percurso)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_percurso'))

    args = {'title':'Editar',"form":form,"percursos":percursos}
    return render(request,"registar_percurso.html",args)

def eliminar_percurso(request,id):
    percurso = Percurso.objects.get(id = id)
    percurso.delete()
    return HttpResponseRedirect(reverse('main:registar_percurso'))
#-----------------------------------------------------------------------
def registar_tipo_carreira(request):
    form = TipoCarreiraForm(request.POST)
    tipo_carreiras = TipoCarreira.objects.all()
    if request.POST:
        form = TipoCarreiraForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_tipo_carreira'))

    args = {'title':'Registar',"form":form,"tipo_carreiras":tipo_carreiras}
    return render(request,"registar_tipo_carreira.html",args)

def editar_tipo_carreira(request,id):
    tipo_carreira = TipoCarreira.objects.get(id = id)
    tipo_carreiras = TipoCarreira.objects.all()
    form = TipoCarreiraForm(instance = ponto)
    if request.POST:
        form = TipoCarreiraForm(data = request.POST,files = request.FILES,instance = tipo_carreira)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_tipo_carreira'))

    args = {'title':'Editar',"form":form,"tipo_carreiras":tipo_carreiras}
    return render(request,"registar_tipo_carreira.html",args)

def eliminar_tipo_carreira(request,id):
    tipo_carreira = TipoCarreira.objects.get(id = id)
    tipo_carreira.delete()
    return HttpResponseRedirect(reverse('main:registar_tipo_carreira'))
#-----------------------------------------------------------------------
def registar_tipo_cartao(request):
    form = TipoCartaoForm(request.POST)
    tipo_cartoes = TipoCartao.objects.all()
    if request.POST:
        form = TipoCartaoForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_tipo_cartao'))

    args = {'title':'Registar',"form":form,"tipo_cartoes":tipo_cartoes}
    return render(request,"registar_tipo_cartao.html",args)

def editar_tipo_cartao(request,id):
    tipo_cartoes = TipoCartao.objects.get(id = id)
    tipo_cartao = TipoCartao.objects.all()
    form = TipoCartaoForm(instance = ponto)
    if request.POST:
        form = TipoCartaoForm(data = request.POST,files = request.FILES,instance = tipo_cartao)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_tipo_cartao'))

    args = {'title':'Editar',"form":form,"tipo_cartoes":tipo_cartoes}
    return render(request,"registar_tipo_cartao.html",args)

def eliminar_tipo_cartao(request,id):
    tipo_cartao = TipoCartao.objects.get(id = id)
    tipo_cartao.delete()
    return HttpResponseRedirect(reverse('main:registar_tipo_cartao'))
#-----------------------------------------------------------------------
def registar_tipo_autocarro(request):
    form = TipoAutocarroForm(request.POST)
    tipo_autocarros = TipoAutocarro.objects.all()
    if request.POST:
        form = TipoAutocarroForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_tipo_autocarro'))

    args = {'title':'Registar',"form":form,"tipo_autocarros":tipo_autocarros}
    return render(request,"registar_tipo_autocarro.html",args)

def editar_tipo_autocarro(request,id):
    tipo_autocarro = TipoAutocarro.objects.get(id = id)
    tipo_autocarros = TipoAutocarro.objects.all()
    form = TipoAutocarroForm(instance = tipo_autocarro)
    if request.POST:
        form = TipoAutocarroForm(data = request.POST,files = request.FILES,instance = tipo_autocarro)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_tipo_autocarro'))

    args = {'title':'Editar',"form":form,"tipo_autocarros":tipo_autocarros}
    return render(request,"registar_tipo_autocarro.html",args)

def eliminar_tipo_autocarro(request,id):
    tipo_autocarro = TipoCartao.objects.get(id = id)
    tipo_autocarro.delete()
    return HttpResponseRedirect(reverse('main:registar_tipo_autocarro'))
#-----------------------------------------------------------------------_____________________________
def registar_ponto(request):
    form = PontoRegistoForm(request.POST)
    pontos = PontoRegisto.objects.all()
    if request.POST:
        form = PontoRegistoForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_ponto'))

    args = {'title':'Registar',"form":form,"pontos":pontos}
    return render(request,"registar_ponto.html",args)

def editar_pontos(request,id):
    ponto = PontoRegisto.objects.get(id = id)
    form = PontoRegistoForm(instance = ponto)
    pontos = PontoRegisto.objects.all()
    if request.POST:
        form = PontoRegistoForm(data = request.POST,files = request.FILES,instance = ponto)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:listar_pontos'))

    args = {'title':'Editar',"form":form,"pontos":pontos}
    return render(request,"registar_ponto.html",args)

def eliminar_ponto(request,id):
    ponto = Ponto.objects.get(id = id)
    ponto.delete()
    return HttpResponseRedirect(reverse('main:registar_ponto'))
#--------------------------------------------------------------------------
def registar_entrada_autocarro(request):
    form = EntradaAutocarroForm(request.POST)

    if request.POST:
        form = EntradaAutocarroForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_entrada_autocarro'))

    args = {'title':'Registar',"form":form,}
    return render(request,"registar_entrada_autocarro.html",args)

def listar_entrada_autocarro(request):
    form = EntradaAutocarroForm(request.POST)
    lista = EntradaAutocarro.objects.all()

    args = {'title':'Listar',"form":form,"lista":lista}
    return render(request,"listar_entrada_autocarro.html",args)

def registar_saida_autocarro(request):
    form = SaidaAutocarroForm(request.POST)
    if request.POST:
        form = SaidaAutocarroForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('main:registar_saida_autocarro'))

    args = {'title':'Registar',"form":form,}
    return render(request,"registar_paragem.html",args)

def listar_saida_autocarro(request):
    form = ParagemForm(request.POST)
    lista = SaidaAutocarro.objects.all()

    args = {'title':'Listar',"form":form,"lista":lista}
    return render(request,"listar_saida_autocarro.html",args)
#-------------------------------------------------------------------------
def ver_estatistica(request):
    lista = []
    carreiras = Carreira.objects.all()
    autocarro = Autocarro.objects.all()
    clientes = Cliente.objects.all()
    entrada = Autocarro.objects.all()
    saida = Cliente.objects.all()
    if request.GET:
        carreira = request.GET.get('carreira',False)
        data = request.GET.get('data',False)
        tipo = request.GET.get('tipo',"entrada")
        if tipo == "entrada":
            lista = EntradaAutocarro.objects.all()
        else:
            lista  = SaidaAutocarro.objects.all()

        print(lista)

        if data:
            print(data.split("-")[1])
            print(data.split("-")[2])
            lista = lista.filter(data__day = data.split("-")[2],data__month = data.split("-")[1])

        print(lista.values_list("autocarro__autocarrocarreira__carreira"))

        if carreira:
            lista = lista.filter(autocarro__autocarrocarreira__carreira__id = carreira)
            print(lista)

    args = {'title':'Ver',"lista":lista,'carreiras':carreiras,"autocarro":autocarro,"entrada":entrada,"saida":saida,"clientes":clientes}
    return render(request,"ver_estatistica.html",args)
"""#-----------------------------------------------------------------------
def registar_tipo_cliente(request):
    form = TipoClienteForm(request.POST)
    tipo_cliente = TipoCliente.objects.all()
    if request.POST:
        form = TipoClienteForm(data = request.POST,files = request.FILES)
        if form.is_valid():
            form.save()

    args = {'title':'title',"form":form,"tipo_clientes":tipo_clientes}
    return render(request,"registar_tipo_cliente.html",args)

def editar_tipo_cliente(request,id):
    tipo_clientes = TipoCliente.objects.get(id = id)
    tipo_cliente = TipoCliente.objects.all()
    form = TipoClienteForm(instance = ponto)
    if request.POST:
        form = TipoClienteForm(data = request.POST,files = request.FILES,instance = tipo_cliente)
        if form.is_valid():
            form.save()

    args = {'title':'title',"form":form,"tipo_clientes":tipo_clientes}
    return render(request,"registar_tipo_cliente.html",args)
"""


# Imports
from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

# Loading Data into Array
with open("training_data.csv") as f:
  train_data=np.loadtxt(f, delimiter=",",dtype=str)

print(train_data.ndim)

# Converting Tenor to Days
def tenorToDays(T)->int:
  identifier=T[-1]
  amt=int(T[:-1])
  return amt*30 if identifier=='M' else amt*12*30

for i in range(1,train_data.shape[0]):
  tenor=tenorToDays(train_data[i][1])
  train_data[i][1]=tenor

# Visualising Surface
fig = plt.figure()
ax = plt.axes(projection='3d')
# tenors=np.array([float(train_data[i][1]) for i in range(1,train_data.shape[0])])
tenors=train_data[1:,1].astype(float)
# print(tenors)
# moneyness=np.array([float(train_data[0][i]) for i in range(2,21)])
moneyness=train_data[0,2:21].astype(float)
# print(moneyness)
# dates=[dt.strptime(train_data[i][0],"%m/%d/%Y") for i in range(1,train_data.shape[0])]
# dates=[x.timestamp() for x in dates]
# dates=np.array([int(round(x)) for x in dates])
iv=train_data[1:, 2:21].astype(float)
# print(iv)
X,Y=np.meshgrid(moneyness,tenors)
print(X.shape,Y.shape,iv.shape)
# ax.plot_wireframe(X,Y,iv,color="red")
ax.plot_surface(X,Y,iv,cmap="viridis",rstride=1,cstride=1,edgecolor="none")
plt.show()