# -*- coding: utf-8 -*-

from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
#from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from ..models.students import Student
from ..models.groups import Group
from endless_pagination.decorators import page_template
from endless_pagination import utils
from datetime import datetime
from django.core.urlresolvers import reverse
from django.contrib import messages

from PIL import Image

from django import forms
from django.forms import ModelForm, ValidationError
from django.views.generic import ListView, UpdateView, DeleteView, CreateView

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Button
from crispy_forms.bootstrap import FormActions

@page_template('students/students_page.html')
def students_list(request,
                  template='students/students_list.html',
                  page_template='students/students_page.html',
                  extra_context=None):
    if request.method == "POST":
        selected = request.POST.getlist('student_select')
        studlist = '/'.join(selected)
        studlist = studlist + "/"
        return HttpResponseRedirect(reverse("students_delete", kwargs={'studlist': studlist}))
    else:
        students = Student.objects.all().order_by('last_name')

        order_by = request.GET.get('order_by', '')
        if order_by in ('last_name', 'first_name', 'card', 'id'):
            students = students.order_by(order_by)
            if request.GET.get('reverse', '') == '1':
                students = students.reverse()

        context = {'students': students,
                   'page_template': page_template,
                   'start_id': (utils.get_page_number_from_request(request) - 1) * 15,
                   'per_page': 15}

        if extra_context is not None:
            context.update(extra_context)
        if request.is_ajax():
            template = page_template

        return render(request, template, context)

def students_add(request):
    if request.method == "POST":
        if request.POST.get('add_button') is not None:
            errors = {}

            data = {'middle_name': request.POST.get('middle_name'),
                    'notes': request.POST.get('notes')}

            # validating user input
            first_name = request.POST.get('first_name', '').strip()
            if not first_name:
                errors['first_name'] = u"Імʼя є обовʼязковим"
            else:
                data['first_name'] = first_name

            last_name = request.POST.get('last_name', '').strip()
            if not last_name:
                errors['last_name'] = u"Прізвище є обовʼязковим"
            else:
                data['last_name'] = last_name

            birth_date = request.POST.get('birth_date', '').strip()
            if not birth_date:
                errors['birth_date'] = u"Дата народження є обовʼязковою"
            else:
                try:
                    datetime.strptime(birth_date, '%Y-%m-%d')
                except Exception:
                    errors[
                        'birth_date'] = u"Введіть коректний формат дати (напр. 1987-12-30)"
                else:
                    data['birth_date'] = birth_date

            card = request.POST.get('card', '').strip()
            if not card:
                errors['card'] = u"Номер білета є обовʼязковим"
            else:
                data['card'] = card

            student_group = request.POST.get('student_group', '').strip()
            if not student_group:
                errors['student_group'] = u"Група є обовʼязковою"
            else:
                groups = Group.objects.filter(pk=student_group)
                if len(groups) != 1:
                    errors['student_group'] = u"Оберіть коректну групу"
                else:
                    data['student_group'] = groups[0]

            photo = request.FILES.get('photo')
            if photo:
                if photo.name.split(".")[-1].lower() not in ('jpg', 'jpeg', 'png', 'gif'):
                    errors[
                        'photo'] = u"Файл має бути одного з наступних типів: jpg, jpeg, png, gif"
                else:
                    try:
                        Image.open(photo)
                    except Exception:
                        errors[
                            'photo'] = u"Завантажений файл не є файлом зображення або пошкоджений"
                    else:
                        if photo.size > 2 * 1024 * 1024:
                            errors[
                                'photo'] = u"Фото занадто велике (розмір файлу має бути менше 2Мб)"
                        else:
                            data['photo'] = photo

            if not errors:
                student = Student(**data)
                student.save()
                messages.success(
                    request, u'Студента "%s" успішно додано!' % student)
                return HttpResponseRedirect(reverse('home'))
            else:
                return render(request, 'students/students_add.html',
                              {'groups': Group.objects.all().order_by('title'),
                               'errors': errors})
        elif request.POST.get('cancel_button') is not None:
            messages.warning(request, u"Додавання студента скасовано!")
            return HttpResponseRedirect(reverse('home'))
    else:
        return render(request, 'students/students_add.html',
                      {'groups': Group.objects.all().order_by('title')})

class StudentAddForm(ModelForm):
    class Meta:
        model = Student
        fields = ['first_name',
                  'last_name',
                  'middle_name',
                  'birth_date',
                  'photo',
                  'card',
                  'student_group',
                  'notes']

    def __init__(self, *args, **kwargs):
        super(StudentAddForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper(self)

        # set form tag attributes
        self.helper.form_action = reverse('students_add')
        self.helper.form_method = 'POST'
        self.helper.form_class = 'form-horizontal'

        # set form field properties
        self.helper.help_text_inline = True
        self.helper.html5_required = True
        self.helper.label_class = 'col-sm-2 control-label'
        self.helper.field_class = 'col-sm-10'

        # add buttons
        self.helper.add_input(Submit('save_button', u'Надіслати'))
        self.helper.add_input(
            Button('cancel_button', u'Скасувати', onclick='window.location.href="{}"'.format(reverse('home'))))

class StudentAddView(CreateView):
    model = Student
    template_name = 'students/students_add_edit.html'
    form_class = StudentAddForm

    def get_success_url(self):
        messages.success(self.request, u"Студента успішно додано!")
        return reverse('home')

    # def post(self, request, *args, **kwargs):
    #     if request.POST.get('cancel_button'):
    #         messages.warning(request, u"Додавання студента відмінено!")
    #         return HttpResponseRedirect(reverse('home'))
    #     else:
    #         return super(StudentAddView, self).post(request, *args, **kwargs)

class StudentList(ListView):
    model = Student
    context_object_name = 'students'
    template = 'students/student_class_based_view_template'

    def get_context_data(self, **kwargs):
        """ This method adds extra variables to template"""
        # get original context data from parent class
        context = super(StudentList, self).get_context_data(**kwargs)

        # tell template not to show logo on a page
        context['show_logo'] = False

        # return context mapping
        return context

    def get_queryset(self):
        """ Order students by last_name"""
        # get original query set
        qs = super(StudentList, self).get_queryset()

        # order by last name
        return qs.order_by('last_name')

class StudentUpdateForm(ModelForm):

    class Meta:
        model = Student
        fields = ['first_name',
                  'last_name',
                  'middle_name',
                  'birth_date',
                  'photo',
                  'card',
                  'student_group',
                  'notes']

    def __init__(self, *args, **kwargs):
        super(StudentUpdateForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper(self)

        # set form tag attributes
        self.helper.form_action = reverse(
            'students_edit', kwargs={'pk': kwargs['instance'].id})
        self.helper.form_method = 'POST'
        self.helper.form_class = 'form-horizontal'

        # set form field properties
        self.helper.help_text_inline = True
        self.helper.html5_required = True
        self.helper.label_class = 'col-sm-2 control-label'
        self.helper.field_class = 'col-sm-10'

        # add buttons
        self.helper.add_input(Submit('save_button', u'Надіслати'))
        self.helper.add_input(
            Button('cancel_button', u'Скасувати', onclick='window.location.href="{}"'.format(reverse('home'))))

    def clean_student_group(self):
        groups = Group.objects.filter(leader=self.instance)
        if len(groups) > 0 and self.cleaned_data['student_group'] != groups[0]:
            raise ValidationError(
                u"Студент є старостою іншої групи", code='invalid')

        return self.cleaned_data['student_group']

class StudentUpdateView(UpdateView):
    model = Student
    template_name = 'students/students_add_edit.html'
    form_class = StudentUpdateForm

    def get_success_url(self):
        messages.success(self.request, u"Студента успішно збережено!")
        return reverse('home')

    def post(self, request, *args, **kwargs):
        if request.POST.get('cancel_button'):
            messages.warning(request, u"Редагування студента відмінено!")
            return HttpResponseRedirect(reverse('home'))
        else:
            return super(StudentUpdateView, self).post(request, *args, **kwargs)

def student_edit_manual(request, pk):
    students = Student.objects.filter(pk=pk)
    groups = Group.objects.all()

    if len(students) != 1:
        messages.error(request, 'Обраного студента не існує')
        return HttpResponseRedirect(reverse('home'))
    elif request.method == "POST":
        st = Student.objects.get(pk=pk)
        if request.POST.get('save_button') is not None:
            st.middle_name = request.POST.get('middle_name', '').strip()
            st.notes = request.POST.get('notes', '').strip()
            errors = {}

            first_name = request.POST.get('first_name', '').strip()
            if not first_name:
                errors['first_name'] = u"Імʼя є обовʼязковим."
            else:
                st.first_name = first_name

            last_name = request.POST.get('last_name', '').strip()
            if not last_name:
                errors['last_name'] = u"Прізвище є обовʼязковим."
            else:
                st.last_name = last_name

            birth_date = request.POST.get('birth_date', '').strip()
            if not birth_date:
                errors['birth_date'] = u"Дата народження є обовʼязковою."
            else:
                try:
                    bd = datetime.strptime(birth_date, '%Y-%m-%d')
                except Exception:
                    errors['birth_date'] = u"Введіть коректний формат дати (напр. 1987-12-30)"
                else:
                    st.birth_date = bd

            if request.POST.get('photo-clear') is not None:
                st.photo = None
            else:
                photo = request.FILES.get('photo')
                if photo:
                    if photo.name.split(".")[-1].lower() not in ('jpg', 'jpeg', 'png', 'gif'):
                        errors[
                            'photo'] = u"Файл має бути одного з наступних типів: jpg, jpeg, png, gif"
                    else:
                        try:
                            Image.open(photo)
                        except Exception:
                            errors[
                                'photo'] = u"Завантажений файл не є файлом зображення або пошкоджений"
                        else:
                            if photo.size > 2 * 1024 * 1024:
                                errors[
                                    'photo'] = u"Фото занадто велике (розмір файлу має бути менше 2Мб)"
                            else:
                                st.photo = request.FILES.get('photo')

            card = request.POST.get('card', '').strip()
            if not card:
                errors['card'] = u"Номер білета є обовʼязковим."
            else:
                st.card = card

            student_group = request.POST.get('student_group', '').strip()
            if not student_group:
                errors['student_group'] = u"Група є обовʼязковою"
            else:
                gr = Group.objects.filter(pk=student_group)
                if len(gr) != 1:
                    errors['student_group'] = u"Оберіть коректну групу"
                else:
                    grps = Group.objects.filter(leader=Student.objects.get(pk=pk))
                    if len(grps) > 0 and int(student_group) != grps[0].pk:
                        errors['student_group'] = u"Студент є старостою іншої групи"
                    else:
                        st.student_group = gr[0]

            if errors:
                messages.error(request, "Виправте, будь-ласка, наступні помилки:")
                return render(request, 'students/students_edit.html', {'pk': pk, 'student': st, 'errors': errors, 'groups': groups})
            else:
                st.save()
                messages.success(
                    request, 'Інформацію по студенту "%s" успішно збережено.' % students[0])
                return HttpResponseRedirect(reverse('home'))
        elif request.POST.get('cancel_button') is not None:
            messages.warning(request, 'Редагування студента скасовано.')
            return HttpResponseRedirect(reverse('home'))
        else:
            messages.error(request, 'Упс! Щось пішло не так. Повторіть спробу пізніше.')
            return HttpResponseRedirect(reverse('home'))
    else:
        return render(request,
                      'students/students_edit.html',
                      {'pk': pk, 'student': students[0], 'groups': groups})

class StudentDeleteView(DeleteView):
    model = Student
    template_name = 'students/students_confirm_delete.html'

    def get_success_url(self):
        messages.success(self.request, "Студента успішно видалено!")
        return reverse('home')

def students_delete(request, studlist):
    selected = studlist[0:-1].split('/')
    selected = map(int, selected)
    students = Student.objects.filter(pk__in=selected)
    if (len(students) != len(selected)) or len(selected) == 0:
        messages.error(request, 'Одного або декількох з обраних студентів не існує.')
        return HttpResponseRedirect(reverse('home'))
    else:
        if request.method == "POST":
            if request.POST.get('confirm_button') is not None:
                name = ""
                for pk in selected:
                    student = Student.objects.get(pk=pk)
                    name = name + "'" + student.__str__() + "', "
                    student.delete()
                messages.success(request, "Успішно видалено: %s." % name[0:-2])
                return HttpResponseRedirect(reverse('home'))
            elif request.POST.get('cancel_button') is not None:
                messages.warning(request, "Видалення студентів скасовано.")
                return HttpResponseRedirect(reverse('home'))
            else:
                messages.error(request, "Упс! Щось пішло не так. Повторіть спробу пізніше.")
                return HttpResponseRedirect(reverse('home'))
        else:
            return render(request,
                          'students/students_delete.html',
                          {'studlist': studlist, 'students': students})


# you could do the same or similar with dictionaries
# entry - puts a list of lists [[1,2],
#                               [3,4]] - a square area of data
# into an excel sheet.
def list_of_lists_to_cell_range(list_of_lists, work_sheet, top_left='A1', bottom_right='unknown'):
    r = 0
    c = 0
    if bottom_right == "unknown":
        bottom_right = number_to_column_letter(len(list_of_lists[0]) + 1) + str(len(list_of_lists) - 1 + int(row_from_coordinate(top_left)))
    for row in work_sheet[top_left:bottom_right]:
        for cell in row:
            print(r)
            print(c)
            print(list_of_lists[r][c])
            cell.value = list_of_lists[r][c]
            c = c + 1
        r = r + 1
        c = 0

def number_to_column_letter(number):
    div = number
    string = ""
    temp = 0
    while div > 0:
        module = (div - 1) % 26
        string = chr(65 + module) + string
        div = int ((div - module) / 26)
    return string

def row_from_coordinate(coordinate):
    number_string = ""
    for character in list(coordinate):
        if represents_integer(character):
            number_string = number_string + character
    return number_string

def represents_integer(integer):
    try:
        int(integer)
        return True
    except ValueError:
        return False


from typing import List, Optional
from dao.db_connection import DBConnection

from business.scenario.scenario import Scenario
from business.role.game_master import GameMaster

class GameMasterDao:

    """Dao of GameMaster
    """

    def add_scenario(self, scenario:Scenario) -> bool:
        """add a Scenario to the database

        Args:
            scenario (Scenario): Scenario to add

        Returns:
            bool: True if the Scenario has been added, else False
        """
        created = False
        request = "INSERT INTO scenario(username, name, description) VALUES "\
                  "(%(username)s,%(name)s,%(description)s)"\
                  "RETURNING id_scenario;"

        with DBConnection().connection as connection:
            with connection.cursor() as cursor :
                cursor.execute(
                    request
                , {"username" : scenario.username
                  ,"name" : scenario.name
                  ,"description" : scenario.description })
                res = cursor.fetchone()
        if res:
            scenario.id = res['id_scenario']
            created = True

        return created

    def rm_scenario(self, id:int ) -> bool:
        """remove a Scenario from database

        Args:
            id (int): id of the Scenario to delete

        Returns:
            bool: True if the Scenario has been deleted, else False
        """
        removed = False
        #delete a scenario implies to delete all the player registered at the table(s) where was the scenario
        request = "DELETE FROM char_reg_game WHERE id_char in (select id_char from game as g JOIN char_reg_game c on g.id_game=c.id_game WHERE g.id_scenario = %(id)s) and id_game in (select c.id_game from game as g JOIN char_reg_game c on g.id_game=c.id_game WHERE g.id_scenario = %(id)s);"\
                  'UPDATE game SET id_scenario=NULL '\
                  'WHERE id_scenario = %(id)s;'\
                  "DELETE FROM scenario WHERE id_scenario = %(id)s;"\
                  "SELECT COUNT(*) FROM scenario WHERE id_scenario = %(id)s;"

        with DBConnection().connection as connection:
            with connection.cursor() as cursor :
                cursor.execute(
                    request
                , {"id" : id})
                res = cursor.fetchone()
        if not res['count']:
            removed = True

        return removed

    def load(self, username:str) -> GameMaster:
        """load GameMaster profile

        Args:
            username (str): username of the GameMaster profile to load

        Returns:
            GameMaster: loaded GameMaster
        """
        game_master = None

        requests = "SELECT * FROM player "\
                    "LEFT JOIN scenario on player.username = scenario.username "\
                    "WHERE player.username = %(username)s;"

        with DBConnection().connection as connection:
            with connection.cursor() as cursor :
                cursor.execute(
                    requests
                    , {"username" : username})
                res = cursor.fetchall()

        if res:
            game_master = GameMaster(username=username)
            for rows in res:
                if rows['id_scenario']:
                    scenario = Scenario(name = rows['name']
                                        , description=rows['description']
                                        , id = rows['id_scenario']
                                        , username=rows['username'])
                    game_master.scenarios.append(scenario)

        return game_master


import sqlite3
import queries

def connect(path):
    conn = sqlite3.connect(path)
    cursor = conn.cursor()
    return conn, cursor

def close(conn):
    conn.close()

def create():
    try:
        conn, cursor = connect('ocr.db')
        cursor.execute("""CREATE TABLE Dict (
                    word text,
                    translation text
                    )""")
        close(conn)
    except Exception as e:
        print("Error while creating table, ", e)

if __name__ == '__main__':
    create()
# ####LISTARE TABEL
# conn, cursor = connect('ocr.db')
# # cursor.execute("SELECT word, translation FROM DICT")
# # print(cursor.fetchall())
# ####CREARE TABEL - e creat deja, daca dai run din nou o sa-ti dea eroare
# cursor.execute("""CREATE TABLE Dict (
#             word text,
#             translation text
#             )""")
# close(conn)
# #####deci lasa partea asta comentata^^^^


from string import capwords
from telegram_credentials import client
from tts import kozak_speak
from requests import get
from bs4 import BeautifulSoup as bs
from re import sub
from random import choice
from os import system, startfile
from datetime import datetime
from starting import jokes_db, apps
from num2words import num2words
from webbrowser import open

############################################ all curent assistent functions ###########################################

def wiki(endpoint):
    kozak_speak("Почекай будь ласка, я перевіряю інформацію, якщо я не відповім то інформацію я не знайшов")
    url = "".join(["https://uk.wikipedia.org/wiki/" + capwords(endpoint)])    # creates final endpoint
    req = get(url)
    soup = bs(req.text, "html.parser")
    results = soup.find("div", id="mw-content-text").find_all("p", limit=3)   # getting info from wikipedia
    for i in results:
        text = sub("\(МФА.+\)|́", "", i.get_text())                            # replaces unwanted elements
        if text.startswith(f'{endpoint.split()[0].capitalize()} '):
            kozak_speak(text)

async def send_message(whom, what):
    await client.send_message(whom, what)  # sends a message to assigned user or group

def jokes():
    kozak_speak("Добре, тоді слухай..")
    kozak_speak(choice(jokes_db))                                            # takes a random joke to be represented

def musics():
    kozak_speak("Насолоджуйся друже...")
    system("C:\\Users\\danpl\\Music\\Playlists\\Kozak_playlist.m3u8")                # turns on music if there are some installed

def current_time():
    hour = num2words(datetime.now().hour, lang="uk")
    minutes = num2words(datetime.now().minute, lang="uk")         # defines current time and translates numbers to text
    kozak_speak(f"Зараз {hour} годин, {minutes} ")

def open_smt(what):
    if what in apps["app"].keys():
        kozak_speak("Гаразд, зараз все буде...")
        startfile(apps["app"][what])
    elif what in apps["website"].keys():                          # opens wanted app or tool
        kozak_speak("Гаразд, зараз все буде...")
        open(apps["website"][what])
    else:
        kozak_speak("Є два варіанти, або я не можу це зробити або ти не правильно сказав команду, хахахахаха.....")

def weather_now():
    kozak_speak("Секундочку, дай гляну...")
    url = "https://www.gismeteo.ua/ua/weather-ludwigshafen-am-rhein-2669/now/"
    req = get(url, headers={
                            "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) "
                            "Chrome/51.0.2704.103 Safari/537.36"
                            })   # uses random client to avoid connection abort
    soup = bs(req.text, "html.parser")
    temp = soup.find("span", class_="unit_temperature_c").get_text()     # getting current weather
    final_temp = num2words(temp, lang="uk")
    if "+" in temp:
        kozak_speak(f"У твоєму місті зараз плюс {final_temp}...")
    if "-" in temp:
        kozak_speak(f"У твоєму місті зараз мінус {final_temp}...")


import numpy as np
import time
import torch
import datetime
import argparse
import torch.nn.functional as F
from graphviz import Digraph
from graph_nn_physics import Graph
from .dataset import get_hdf5

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('dir')
    parser.add_argument('path')
    parser.add_argument('rollout')
    parser.add_argument('radius')
    parser.add_argument('particles')
    args = parser.parse_args()

    data = torch.tensor(get_hdf5(args.dir, args.path, args.rollout))
    init_nodes = data[50]

    graph = Graph(init_nodes)
    start = time.time()
    graph.gen_edges(float(args.radius))
    tstr = str(datetime.timedelta(seconds=time.time() - start) / datetime.timedelta(milliseconds=1))
    # print('K-D Tree time: {}ms'.format(tstr))

    edges = torch.cat([graph.senders.unsqueeze(1), graph.receivers.unsqueeze(1)], dim=1)
    edge_label_colors = np.random.rand(graph.n_edges, 3)

    norm = []

    edge_labels = {(*edges[i].tolist(),): norm[i] for i in range(edges.size(0))}

    pos = {}
    for i, p in enumerate(graph.nodes.numpy()):
        pos[i] = p

    # edge_props = torch.arange(0, edges.size(0), dtype=torch.float32).unsqueeze(1).repeat(1, 5)
    edge_props = torch.arange(0, edges.size(0), dtype=torch.float32)
    receivers = graph.receivers

    if edges.size(0) < graph.n_nodes:
        edge_props = F.pad(edge_props, (0, graph.n_nodes - edge_props.size(0)))
        receivers = F.pad(graph.receivers, (0, graph.n_nodes - edge_props.size(0)))

    edge_props = edge_props.unsqueeze(1)
    receivers = receivers.unsqueeze(1)
    zeros = torch.zeros_like(edge_props)
    scattered_edge_states = zeros.scatter_add(0, receivers, edge_props).squeeze().numpy()

    G = Digraph(engine='neato')

    min_x = min([p[0].item() for p in graph.nodes])
    max_x = max([p[0].item() for p in graph.nodes])
    min_y = min([p[1].item() for p in graph.nodes])
    max_y = max([p[1].item() for p in graph.nodes])
    coord_scale = 100

    for i, n in enumerate(graph.nodes):
        G.node(
            str(i),
            label='{}: {}'.format(i, scattered_edge_states[i]),
            # label='{}'.format(i),
            fontcolor='white',
            style='filled',
            color='white',
            fillcolor='sandybrown',
            shape='circle',
            pos='{},{}!'.format(
                coord_scale * (n[0] - min_x) / (max_x - min_x),
                coord_scale * (n[1] - min_y) / (max_y - min_y),
            ),
            width='1.25',
            fixedsize='true',
            pin='true',
        )

    for i, n in enumerate(edges):
        G.edge(
            str(n[0].item()),
            str(n[1].item()),
            label=str(edge_props[i].item()),
            penwidth='2'
        )

    G.save()


from base.logger import Logger
import time
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import *
from selenium.webdriver.support import expected_conditions as ec
from conftest import IMG_DIR

#logger实例
logger = Logger(logger="BasePage").getlog()

class BasePage(object):

    def __init__(self,login):
        """
        :param login:conftest.py的login
        """
        self.driver = login

    #后退操作
    def back(self):
        self.driver.back()
        logger.info("Click back on current page.")

    def forward(self):
        self.driver.forward()
        logger.info('Click forward on current page.')

    def open(self,url):
        self.driver.get(url)
        logger.info("Open page with url:%s"%url)

    def get_url(self):
        current_url = None
        try:
            current_url = self.driver.current_url
            logger.info('Current UFL is ::'+ current_url)
        except:
            logger.error('Failed get current url ::'+current_url)
        return current_url

    def get_title(self):
        title = None
        try:
            title = self.driver.title
            logger.info('Current title is ::'+ title)
        except:
            logger.error('Failed get current title ::'+title)
        return title

    def open_new_tab(self,locator='' , locator_type='id', timeout=10):

        handles_before = self.driver.window_handles
        self.element_click(locator=locator,locator_type=locator_type)
        handles_after = None
        try:
            WebDriverWait(self.driver,timeout).until(lambda windows:len(handles_before) != len(self.driver.window_handles))
            handles_after = self.driver.window_handles
            logger.info('New window is opened ::' + self.get_title())
            return handles_after
        except:
            logger.error('NO new window opened')
        return handles_after

    def switch_window(self,window_number):
        try:
            self.driver.switch_window(self.driver.window_handles[window_number])
            logger.info('Switched on new window::' + self.get_title())
            return True
        except:
            logger.error('Failed to switch on new window::'+self.get_title())
            return False

    def get_by_type(self,locator_type):

        locator_type = locator_type.lower()
        if locator_type == 'id':
            return By.ID
        elif locator_type == 'class':
            return By.CLASS_NAME
        elif locator_type == 'name':
            return By.NAME
        elif locator_type == 'xpath':
            return By.XPATH
        elif locator_type == 'css':
            return By.CSS_SELECTOR
        elif locator_type == 'link':
            return By.LINK_TEXT
        elif locator_type == 'tag':
            return By.TAG_NAME
        else:
            logger.info("Locator_type：" + locator_type + " not correct")
        return False
    #定位元素
    def element_get(self,locator,locator_type = 'id',web_element=None):
    #locator相当于‘su’
        element = web_element
        try:
            locator_type = locator_type.lower()
            by_type = self.get_by_type(locator_type)
            if element:
                element = web_element.find_element(by_type,locator)
                logger.info('Element descendant Found with locator：' + locator + "，locator_type：" + locator_type)
            else:
                element = self.driver.find_element(by_type,locator)
                logger.info('Element Found with locator：'+locator+'，locator_type：'+locator_type)
        except:
            logger.error('element not found')
        return element

    def elements_get(self,locator , locator_type='id'):
        elements = None
        try:
            locator_type = locator_type.lower()
            by_type = self.get_by_type(locator_type)
            elements = self.driver.find_elements(by_type,locator)
            logger.info('Elements found')
        except:
            logger.error('Elements not found')
        return elements

    def element_click(self,locator='',locator_type='id',web_element=None):
        try:
            if web_element:
                web_element.click()
                logger.info('Clicked on element')

            else:
                element = self.element_get(locator,locator_type)
                element.click()
                logger.info('Clicked on element with locator：'+locator+'，locator_type：'+locator_type)
        except:
            logger.error('Cannot click on the element with locator：'+locator+'，locator_type：'+locator_type)

    def element_send_keys(self,locator,data,locator_type='id',web_element=None):
        try:
            if web_element:
                web_element.send_keys(data)
                logger.info('输入值成功！')
            else:
                element = self.element_get(locator,locator_type)
                element.send_keys(data)
            logger.info('send data：“'+data+'”on element with locator：'+locator+'，locator_type：'+locator_type)
        except Exception as e:
            logger.error('Cannot send content：“'+data+'” on element with locator：'+locator+'，locator_type：'+locator_type)
            print(e)

    def element_attribute(self,attr_name,locator='',locator_type='id',element=None):
        name = None
        if element:
            try:
                name = element.get_attribute(attr_name)
                logger.info('Element found with attribute %s'%attr_name)
            except:
                logger.error('Element not found with attribute %s'%attr_name)
        else:
            try:
                locator_type = locator_type.lower()
                by_type = self.get_by_type(locator_type)
                name = self.driver.find_element(by_type,locator).get_attribute(attr_name)
                logger.info('Element found with attribute %s'%attr_name)
            except:
                logger.error('Element not found with attribute %s' % attr_name)
        return name

    def element_is_parsent(self,locator,locator_type='id'):
        try:
            element = self.elements_get(locator,locator_type)
            if element:
                logger.info('Element found')
                return True
            else:
                logger.error('Element not found')
                return False
        except:
            logger.error('Element not found')
            return False

    def element_parsence_check(self,locator,locator_type='id'):
        try:
            elementList = self.elements_get(logger,locator_type)
            if (len(elementList)) > 0:
                logger.info('Element found')
                return True
            else:
                logger.error('Element not found')
                return False
        except:
            logger.error('Element not found')
            return False

    def element_wait_for(self,locator,locator_type='id',timeout=10,poll_frequency=0.5):
        element = None
        try:
            by_type = self.get_by_type(locator_type)
            logger.info("Waiting for maximum :: " + str(timeout) + " :: seconds for element to be clickable")
            wait = WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll_frequency,ignored_exceptions=[NoSuchElementException,
                                                                                ElementNotVisibleException,
                                                                                ElementNotSelectableException])
            element = wait.until(ec.visibility_of_element_located((by_type,logger)))
            logger.info('Element appeared on the web page')
        except:
            logger.error('Element not appeared on the web page')
        return element

    def element_is_displayed(self,locator ='' ,locator_type='id',element=None):
        is_displayed = False
        try:
            if locator:
                element = self.elements_get(locator,locator_type)
            if element:
                is_displayed = element.is_displayed()
                logger.info('Element is displayed')
            else:
                logger.error('Element is not displayed')
            return is_displayed
        except:
            logger.error('Element is not displayed')
            return False

    def element_is_clickable(self,locator , locator_type='id',timeout=10,poll_frequency=0.5):
        element = None
        try:
            by_type = self.get_by_type(locator_type)
            logger.info('Waiting for maximum::'+ str(timeout)+ '::seconds for element to be clickable')
            wait = WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll_frequency,
                                 ignored_exceptions=[NoSuchElementException,
                                                     ElementNotSelectableException,
                                                     ElementNotVisibleException,
                                                     ElementClickInterceptedException])
            element = wait.until(ec.element_to_be_clickable((by_type,locator)))
            logger.info('Element is ready for click')
        except:
            logger.error('Element is clickable')
        return element

    def element_get_text(self , locator='',locator_type='',element = None , info=""):
        try:
            if locator:
                element = self.element_get(locator,locator_type)
            text = element.text
            if (len(text)) == 0:
                text = element.get_attribute('innerText')
            else:
                logger.info('Getting text on element::'+info)
                logger.info('The text is ::“'+text+'”')
                text = text.strip()
        except:
            logger.error('Failed to get text on element '+ info)
            text = None
        return text

    def element_clear(self,locator,locator_type='id'):
        try:
            element = self.element_get(locator,locator_type)
            element.clear()
            logger.info('Cleared on element with locator: '+locator+',locator_type: '+locator_type)
        except:
            logger.error('Cannot cleared on element with locator: '+locator+',locator_type: '+locator_type)

    def element_clear_by_keys(self,locator,locator_type='id',attribute='value'):
        try:
            element = self.element_get(locator,locator_type)
            value = element.get_attribute(attribute)
            for i in range(len(value)):
                element.send_keys(Keys.BACKSPACE)
            logger.info('Cleared on element with locator: '+locator+',locator_type: '+locator_type)
        except:
            logger.error("Cannot clear on the element with locator: " + locator + " locator_type: " + locator_type)

    def get_windows_img(self):

        creat_time = time.strftime('%Y%m%d%H%M',time.localtime(time.time()))
        screen_name = IMG_DIR+creat_time+'.png'
        try:
            self.driver.get_screenshot_as_file(screen_name)
            logger.info("Had take screenshots and save to folder : /screenshots")
        except Exception as e:
            logger.error("Failed to take screenshots! %s"%e)


#!/usr/bin/env python

lexicon = open("data/local/tmp/lexicon.1")
lexicon_ext = open("data/local/tmp/lexicon.2", "w")

for line in lexicon:
    line = line.strip()
    if "//" not in line:
        lexicon_ext.write(line + "\n")
        continue
    lineComp = line.split("\t")
    prons = lineComp[1].split("//")
    for item in prons:
        lexicon_ext.write(lineComp[0] + "\t" + item + "\n")

lexicon.close()
lexicon_ext.close()


import pandas as pd

def process_csv(input_file, output_file):
        # Read the CSV file
    df = pd.read_csv(input_file)

    # Convert the first column to the desired format
    df['regex_coordinates'] = df['regex_coordinates'].apply(lambda x: [(float(x.split(",")[0].strip()), float(x.split(",")[1].strip()))])

    # Convert the second column from string to list of tuples
    df['lat_long_pairs'] = df['lat_long_pairs'].apply(eval)

    # Combine the two columns
    df['Combined'] = df['regex_coordinates'] + df['lat_long_pairs']

    # Filter out unwanted latitude and longitude pairs
    def filter_coordinates(coords_list):
        filtered_list = []
        for coord in coords_list:
            lat, lon = coord
            if 40.580 <= lat <= 40.875 and -74.052 <= lon <= -73.741:
                filtered_list.append(coord)
        return filtered_list

    df['Filtered Combined'] = df['Combined'].apply(filter_coordinates)

     # Remove existing double quotes from the Caption column
    df['Caption'] = df['Caption'].str.replace('"', '')

    # Select the required columns for the output
    df_output = df[['Media ID', 'Caption', 'Date', 'Post URL', 'Filtered Combined']]

    # Save the processed data to a new CSV file
    df_output.to_csv(output_file, index=False, )

# Example usage
input_file = 'data/curb_alert_list.csv'
output_file = 'data/final_location_parse.csv'
process_csv(input_file, output_file)


# Saves the image files on disk as required by the keras api
import data_loader
from keras.preprocessing.image import save_img
from keras.preprocessing.image import array_to_img
import os
import numpy as np
import pandas as pd

IMAGE_WIDTH = 48
IMAGE_HEIGHT = 48

def extract_and_save_img(df, type_subdir, index, file_prefix='Image_', image_dir='data'):
    type_fp = os.path.join(os.getcwd(), image_dir)
    type_fp = os.path.join(type_fp, type_subdir + str(index))
    if not os.path.exists(type_fp):
        os.mkdir(type_fp)

    # Iterate over data frame
    basetype_fp = type_fp
    for row in df.itertuples():
        pixel_arr = np.array(row.pixels.split())

        emotion = 0
        if row.emotion != index:
            emotion = 1

        if type_subdir != 'Test':
            type_fp = os.path.join(type_fp, str(emotion))
        else:
            type_fp = os.path.join(type_fp, 'Test_folder')
        if not os.path.exists(type_fp):
            os.mkdir(type_fp)

        # Reshape to channel_last_dimensions
        pixel_arr = np.reshape(pixel_arr, (IMAGE_WIDTH, IMAGE_HEIGHT, 1))

        if type_subdir != 'Test':
            type_fp = os.path.join(type_fp, file_prefix + str(row.Index))
        else:
            type_fp = os.path.join(type_fp, str(emotion) + '_' + file_prefix + str(row.Index))

        save_img(type_fp + '.png', pixel_arr)

        #Reset type_fp to basetype
        type_fp = basetype_fp

train_df,test_df,val_df= data_loader.load_all_data()

for i in range(7):
    extract_and_save_img(train_df, 'Train', i)
    extract_and_save_img(val_df, 'Valid', i)
    extract_and_save_img(test_df, 'Test', i)


from tkinter import *

root=Tk()
e1=Entry(root)
e1.pack()

def clickaction():
    textoutput=e1.get()
    t1=Label(root,text=textoutput)
    t1.pack()

b1=Button(root,text="click",command=clickaction)
b1.pack()
root.mainloop()


#!/bin python
# -*- coding: utf-8 -*-
# @Time    : 2021/9/21
# @Author  : zhangl
import logging

import pandas

def read(path, sheet_name):
    return pandas.read_excel(path, sheet_name=sheet_name)

if __name__ == '__main__':
    df = read("户籍(老).xlsx", sheet_name="区域代码表")
    for index, line in df.iterrows():
        try:
            number = str(int(line['number']))
            # if not number.startswith('65'):
            #     continue

            if number.endswith('0000'):
                province = line['area']
                city = ""
                print(number, province)
                df.loc[index, 'province'] = province
                df.loc[index, 'city'] = ''
                df.loc[index, 'county'] = ''
            elif number.endswith('00'):
                if number.startswith("11") or number.startswith("12") \
                        or number.startswith("50") or number.startswith("31"):
                    city = province
                else:
                    city = line['area'].replace(province, "")
                print(number, province, city)
                df.loc[index, 'province'] = province
                df.loc[index, 'city'] = city
                df.loc[index, 'county'] = ''
            else:
                if number.startswith("11") or number.startswith("12") \
                        or number.startswith("50") or number.startswith("31"):
                    county = line['area'].replace(province, "")
                else:
                    county = line['area'].replace(province + city, "")
                print(number, province, city, county)
                df.loc[index, 'province'] = province
                df.loc[index, 'city'] = city
                df.loc[index, 'county'] = county
            pass

        except Exception as e:
            print(line)
            logging.error(e)
            break

with pandas.ExcelWriter("户籍(老)-处理结果.xlsx") as writer:
    df.to_excel(writer, sheet_name='官方', index=False)


"""Module for extracting the plot descriptions from the
scraped Memory Alpha articles and writing them to a simple text file."""
from pathlib import Path
import re
import bs4
from bs4.element import NavigableString

# set the series folder here

# tng folders
#FOLDER_TO_WIKIDATA = Path.cwd() / Path('data') / Path('scraped') / Path('tng')
#FOLDER_FOR_SAVING = Path.cwd() / Path('data') / Path('scraped') / Path('tng') / Path('processed')

# voy folders
#FOLDER_TO_WIKIDATA = Path.cwd() / Path('data') / Path('scraped') / Path('voy')
#FOLDER_FOR_SAVING = Path.cwd() / Path('data') / Path('scraped') / Path('voy') / Path('processed')

# ds9 folders
FOLDER_TO_WIKIDATA = Path.cwd() / Path('data') / Path('scraped') / Path('ds9')
FOLDER_FOR_SAVING = Path.cwd() / Path('data') / Path('scraped') / Path('ds9') / Path('processed')

# loop over all text files, find the plot element and get all para elements
# under that until we hit the next heading
for wikipage in FOLDER_TO_WIKIDATA.glob('*.txt'):
    with open(wikipage, 'r', encoding='utf-8') as episode_document:
        title = wikipage.name

        soup = bs4.BeautifulSoup(episode_document, 'html.parser')
        plot = []
        # lets find the header for plot, but we only want to get the Act wise descriptions, not the teaser
        act_headings = soup.find_all(id=re.compile('^Act'))

        for act in act_headings:  # iterate over all acts
            # this line allows us to iterate over all elements that come next/under:
            for para_element in act.parent.nextSiblingGenerator():
                # ignore h3, h2 because this is either the next act or we are done with the plot description
                if para_element.name in ['h3', 'h2']:
                    break
                if para_element.name == 'figure':  # we dont want the captions
                    continue
                if isinstance(para_element, NavigableString):
                    continue
                if para_element.text:

                    plot.append(para_element.text)

        # process a bit and save to new file.
        if not FOLDER_FOR_SAVING.exists():
            FOLDER_FOR_SAVING.mkdir(parents=True)
        with open(FOLDER_FOR_SAVING / Path(title), 'w', encoding='utf-8') as file_to_write:
            # lets remove the parts that are in brackets - these are usually the names of the actors
            COMPLETE_TEXT = ' '.join(plot)
            # Regex: Take everything between ( and ) with non greedy matching
            text_without_actors = re.sub(r'\(.{1,}?\)', '', COMPLETE_TEXT)
            file_to_write.write(text_without_actors)


import os
import sys
import pygame as pg
from colors import BROWN, GREEN

class World:
	def __init__(self,width=800, height=600, CAPTION = 'Mundo das ovelhas', flat = False):
		self.width = width
		self.height = height
		self. flat = flat
		self.fps = 1 #60
		self.done = False
		os.environ['SDL_VIDEO_CENTERED'] = '1'
		pg.init()
		pg.display.set_caption(CAPTION)
		pg.display.set_mode((self.width,self.height))
		self.screen = pg.display.get_surface()
		self.keys = pg.key.get_pressed()
		self.clock = pg.time.Clock()

	def tick(self):
		pg.display.update()
		#self.clock.tick(self.fps)  # tempo de espera por frame se for muito rápido

	def event_loop(self):
		"""
		One event loop. Never cut your game off from the event loop.
		Your OS may decide your program has hung if the event queue is not
		accessed for a prolonged period of time.
		"""
		for event in pg.event.get():
			if event.type == pg.QUIT or self.keys[pg.K_ESCAPE]:
					self.done = True
			elif event.type in (pg.KEYUP, pg.KEYDOWN):
				self.keys = pg.key.get_pressed()

	def clear(self):
 		""" limpa a tela com cor de terra (planta comida)
 		"""
 		self.screen.fill(BROWN)

	def ellipse(self, x, y, xsize, ysize, color):
		pg.draw.ellipse(self.screen, color, (x,y,xsize,ysize))

	def rect(self, x, y, xsize, ysize, color):
		pg.draw.rect(self.screen, color, (x,y,xsize,ysize))

	def end(self):
		pg.quit()
		sys.exit()


# =============================================================================
# IMPORTS
# =============================================================================
# Python
import shutil
import tempfile
from copy import deepcopy
from datetime import timedelta

# Django
from django.conf import settings
from django.core.files.uploadedfile import UploadedFile
from django.db import connection
from django.test import override_settings
from django.utils import formats
from django.utils.timezone import now

# Third Party Python
from path import Path

# Third Party Django
from rest_framework import status
from rest_framework.parsers import ParseError
from rest_framework.reverse import reverse
from rest_framework.test import APITestCase

# App
from project_manager.api.common.views import ProjectViewSet
from project_manager.sub_plugins.api.filtersets import SubPluginFilterSet
from project_manager.sub_plugins.api.serializers import (
    SubPluginCreateSerializer,
    SubPluginSerializer,
)
from project_manager.sub_plugins.api.views import SubPluginViewSet
from project_manager.sub_plugins.models import (
    SubPlugin,
    SubPluginRelease,
)
from requirements.models import (
    DownloadRequirement,
    PyPiRequirement,
    VersionControlRequirement,
)
from test_utils.factories.games import GameFactory
from test_utils.factories.packages import PackageFactory, PackageReleaseFactory
from test_utils.factories.plugins import PluginFactory, SubPluginPathFactory
from test_utils.factories.sub_plugins import (
    SubPluginContributorFactory,
    SubPluginFactory,
    SubPluginGameFactory,
    SubPluginReleaseFactory,
    SubPluginTagFactory,
)
from test_utils.factories.tags import TagFactory
from test_utils.factories.users import ForumUserFactory
from users.models import ForumUser

# =============================================================================
# TEST CASES
# =============================================================================
class SubPluginViewSetTestCase(APITestCase):

    contributor_1 = contributor_2 = current_release_1 = None
    current_release_2 = detail_api = list_api = owner = plugin = None
    sub_plugin_1 = sub_plugin_2 = None
    MEDIA_ROOT = Path(tempfile.mkdtemp())

    @classmethod
    def setUpTestData(cls):
        cls.owner = ForumUserFactory()
        cls.plugin = PluginFactory()
        cls.sub_plugin_1 = SubPluginFactory(
            owner=cls.owner,
            plugin=cls.plugin,
            logo='logo.jpg',
            created=now() - timedelta(minutes=3),
            updated=now() - timedelta(minutes=2),
        )
        cls.sub_plugin_2 = SubPluginFactory(
            owner=cls.owner,
            plugin=cls.plugin,
            created=now() - timedelta(minutes=1),
            updated=now() - timedelta(minutes=1),
        )
        SubPluginReleaseFactory(
            created=now() - timedelta(minutes=3),
            sub_plugin=cls.sub_plugin_1,
            zip_file='/media/release_v1.0.0.zip',
        )
        cls.current_release_1 = SubPluginReleaseFactory(
            created=now() - timedelta(minutes=2),
            sub_plugin=cls.sub_plugin_1,
            zip_file='/media/release_v1.0.1.zip',
        )
        cls.current_release_2 = SubPluginReleaseFactory(
            sub_plugin=cls.sub_plugin_2,
            zip_file='/media/release_v1.0.0.zip',
        )
        cls.list_api = 'api:sub-plugins:projects-list'
        cls.list_path = reverse(
            viewname=cls.list_api,
            kwargs={'plugin_slug': cls.plugin.slug},
        )
        cls.detail_api = 'api:sub-plugins:projects-detail'
        cls.detail_path = reverse(
            viewname=cls.detail_api,
            kwargs={
                'plugin_slug': cls.plugin.slug,
                'slug': cls.sub_plugin_1.slug,
            }
        )
        cls.contributor_1 = ForumUserFactory()
        cls.contributor_2 = ForumUserFactory()
        SubPluginContributorFactory(
            sub_plugin=cls.sub_plugin_1,
            user=cls.contributor_1,
        )
        SubPluginContributorFactory(
            sub_plugin=cls.sub_plugin_1,
            user=cls.contributor_2,
        )
        cls.regular_user = ForumUserFactory()

        cls.payload_1 = {
            'name': cls.sub_plugin_1.name,
            'slug': cls.sub_plugin_1.slug,
            'total_downloads': cls.sub_plugin_1.total_downloads,
            'current_release': {
                'version': cls.current_release_1.version,
                'notes': cls.current_release_1.notes,
            },
            'created': {
                'actual': cls.sub_plugin_1.created.strftime(
                    '%Y-%m-%dT%H:%M:%S.%fZ',
                ),
                'locale': formats.date_format(
                    cls.sub_plugin_1.created,
                    'DATETIME_FORMAT',
                ),
                'locale_short': formats.date_format(
                    cls.sub_plugin_1.created,
                    'SHORT_DATETIME_FORMAT',
                ),
            },
            'updated': {
                'actual': cls.sub_plugin_1.updated.strftime(
                    '%Y-%m-%dT%H:%M:%S.%fZ',
                ),
                'locale': formats.date_format(
                    cls.sub_plugin_1.updated,
                    'DATETIME_FORMAT',
                ),
                'locale_short': formats.date_format(
                    cls.sub_plugin_1.updated,
                    'SHORT_DATETIME_FORMAT',
                ),
            },
            'synopsis': cls.sub_plugin_1.synopsis,
            'description': cls.sub_plugin_1.description,
            'configuration': cls.sub_plugin_1.configuration,
            'video': cls.sub_plugin_1.video,
            'owner': {
                'forum_id': cls.sub_plugin_1.owner.forum_id,
                'username': cls.sub_plugin_1.owner.user.username,
            },
            'contributors': [
                {
                    'forum_id': cls.contributor_1.forum_id,
                    'username': cls.contributor_1.user.username,
                },
                {
                    'forum_id': cls.contributor_2.forum_id,
                    'username': cls.contributor_2.user.username,
                },
            ],
        }
        cls.payload_2 = {
            'name': cls.sub_plugin_2.name,
            'slug': cls.sub_plugin_2.slug,
            'total_downloads': cls.sub_plugin_2.total_downloads,
            'current_release': {
                'version': cls.current_release_2.version,
                'notes': cls.current_release_2.notes,
            },
            'created': {
                'actual': cls.sub_plugin_2.created.strftime(
                    '%Y-%m-%dT%H:%M:%S.%fZ',
                ),
                'locale': formats.date_format(
                    cls.sub_plugin_2.created,
                    'DATETIME_FORMAT',
                ),
                'locale_short': formats.date_format(
                    cls.sub_plugin_2.created,
                    'SHORT_DATETIME_FORMAT',
                ),
            },
            'updated': {
                'actual': cls.sub_plugin_2.updated.strftime(
                    '%Y-%m-%dT%H:%M:%S.%fZ',
                ),
                'locale': formats.date_format(
                    cls.sub_plugin_2.updated,
                    'DATETIME_FORMAT',
                ),
                'locale_short': formats.date_format(
                    cls.sub_plugin_2.updated,
                    'SHORT_DATETIME_FORMAT',
                ),
            },
            'synopsis': cls.sub_plugin_2.synopsis,
            'description': cls.sub_plugin_2.description,
            'configuration': cls.sub_plugin_2.configuration,
            'logo': None,
            'video': cls.sub_plugin_2.video,
            'owner': {
                'forum_id': cls.sub_plugin_2.owner.forum_id,
                'username': cls.sub_plugin_2.owner.user.username,
            },
            'contributors': [],
        }

    @classmethod
    def tearDownClass(cls):
        shutil.rmtree(cls.MEDIA_ROOT, ignore_errors=True)
        super().tearDownClass()

    def test_inheritance(self):
        self.assertTrue(expr=issubclass(SubPluginViewSet, ProjectViewSet))

    def test_base_attributes(self):
        self.assertEqual(
            first=SubPluginViewSet.filterset_class,
            second=SubPluginFilterSet,
        )
        self.assertEqual(
            first=SubPluginViewSet.serializer_class,
            second=SubPluginSerializer,
        )
        self.assertEqual(
            first=SubPluginViewSet.creation_serializer_class,
            second=SubPluginCreateSerializer,
        )
        self.assertIs(expr1=SubPluginViewSet.queryset.model, expr2=SubPlugin)
        prefetch_lookups = getattr(
            SubPluginViewSet.queryset,
            '_prefetch_related_lookups'
        )
        self.assertEqual(first=len(prefetch_lookups), second=1)
        lookup = prefetch_lookups[0]
        self.assertEqual(first=lookup.prefetch_to, second='releases')
        self.assertEqual(
            first=lookup.queryset.query.order_by,
            second=('-created',),
        )

        self.assertDictEqual(
            d1=SubPluginViewSet.queryset.query.select_related,
            d2={'owner': {'user': {}}, 'plugin': {}},
        )

    def test_get_queryset(self):
        with self.assertRaises(ParseError) as context:
            obj = SubPluginViewSet()
            setattr(obj, 'action', 'retrieve')
            obj.kwargs = {}
            obj.get_queryset()

        self.assertEqual(
            first=context.exception.detail,
            second='Invalid plugin_slug.',
        )

        plugin = PluginFactory()
        plugin2 = PluginFactory()
        sub_plugin_1 = SubPluginFactory(
            plugin=plugin,
        )
        sub_plugin_2 = SubPluginFactory(
            plugin=plugin,
        )
        SubPluginFactory(
            plugin=plugin2,
        )
        SubPluginFactory(
            plugin=plugin2,
        )
        obj.kwargs = {'plugin_slug': plugin.slug}
        obj.get_queryset()
        self.assertSetEqual(
            set1=set(obj.get_queryset()),
            set2={sub_plugin_1, sub_plugin_2},
        )

        obj.kwargs = {}
        obj.plugin = plugin
        obj.get_queryset()
        self.assertSetEqual(
            set1=set(obj.get_queryset()),
            set2={sub_plugin_1, sub_plugin_2},
        )

        obj = SubPluginViewSet()
        obj.kwargs = {'plugin_slug': plugin.slug}
        setattr(obj, 'action', 'retrieve')
        prefetch_lookups = getattr(
            obj.get_queryset(),
            '_prefetch_related_lookups'
        )
        self.assertEqual(first=len(prefetch_lookups), second=1)

        setattr(obj, 'action', 'list')
        prefetch_lookups = getattr(
            obj.get_queryset(),
            '_prefetch_related_lookups'
        )
        self.assertEqual(first=len(prefetch_lookups), second=2)
        lookup = prefetch_lookups[1]
        self.assertEqual(first=lookup.prefetch_to, second='contributors')
        self.assertIs(
            expr1=lookup.queryset.model,
            expr2=ForumUser,
        )
        self.assertEqual(
            first=lookup.queryset.query.select_related,
            second={'user': {}}
        )

    def test_http_method_names(self):
        self.assertTupleEqual(
            tuple1=SubPluginViewSet.http_method_names,
            tuple2=('get', 'post', 'patch', 'options'),
        )

    @override_settings(DEBUG=True)
    def test_get_list(self):
        # Verify that non-logged-in user can see results but not 'id'
        response = self.client.get(path=self.list_path)
        self.assertEqual(first=len(connection.queries), second=5)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        content = response.json()
        self.assertEqual(first=content['count'], second=2)
        request = response.wsgi_request
        domain = f'{request.scheme}://{request.get_host()}'
        zip_file_1 = f'{domain}{self.current_release_1.get_absolute_url()}'
        payload_1 = deepcopy(self.payload_1)
        payload_1['current_release']['zip_file'] = zip_file_1
        payload_1['logo'] = f'{domain}{self.sub_plugin_1.logo.url}'
        zip_file_2 = f'{domain}{self.current_release_2.get_absolute_url()}'
        payload_2 = deepcopy(self.payload_2)
        payload_2['current_release']['zip_file'] = zip_file_2
        self.assertDictEqual(
            d1=content['results'][0],
            d2=payload_2,
        )
        self.assertDictEqual(
            d1=content['results'][1],
            d2=payload_1,
        )

        # Verify that regular user can see results but not 'id'
        self.client.force_login(self.regular_user.user)
        response = self.client.get(path=self.list_path)
        self.assertEqual(first=len(connection.queries), second=7)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        content = response.json()
        self.assertEqual(first=content['count'], second=2)
        self.assertDictEqual(
            d1=content['results'][0],
            d2=payload_2,
        )
        self.assertDictEqual(
            d1=content['results'][1],
            d2=payload_1,
        )

        # Verify that contributors can see results AND 'id'
        self.client.force_login(self.contributor_1.user)
        response = self.client.get(path=self.list_path)
        self.assertEqual(first=len(connection.queries), second=7)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        content = response.json()
        self.assertEqual(first=content['count'], second=2)
        self.assertDictEqual(
            d1=content['results'][0],
            d2=payload_2,
        )
        self.assertDictEqual(
            d1=content['results'][1],
            d2=payload_1,
        )

        # Verify that the owner can see results AND 'id'
        self.client.force_login(self.owner.user)
        response = self.client.get(path=self.list_path)
        self.assertEqual(first=len(connection.queries), second=7)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        content = response.json()
        self.assertEqual(first=content['count'], second=2)
        self.assertDictEqual(
            d1=content['results'][0],
            d2=payload_2,
        )
        self.assertDictEqual(
            d1=content['results'][1],
            d2=payload_1,
        )

    @override_settings(DEBUG=True)
    def test_get_list_filters(self):
        response = self.client.get(path=self.list_path)
        self.assertEqual(first=len(connection.queries), second=5)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        self.assertEqual(
            first=response.json()['count'],
            second=2,
        )

        # Validate tag filtering
        response = self.client.get(
            path=self.list_path,
            data={'tag': 'test_tag'},
        )
        self.assertEqual(first=len(connection.queries), second=2)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        self.assertEqual(
            first=response.json()['count'],
            second=0,
        )
        tag = TagFactory(name='test_tag')
        SubPluginTagFactory(
            sub_plugin=self.sub_plugin_1,
            tag=tag,
        )
        response = self.client.get(
            path=self.list_path,
            data={'tag': 'test_tag'},
        )
        self.assertEqual(first=len(connection.queries), second=5)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        self.assertEqual(
            first=response.json()['count'],
            second=1,
        )

        # Validate game filtering
        response = self.client.get(
            path=self.list_path,
            data={'game': 'game1'},
        )
        self.assertEqual(first=len(connection.queries), second=2)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        self.assertEqual(
            first=response.json()['count'],
            second=0,
        )
        game = GameFactory(
            name='Game1',
            basename='game1',
            icon='icon1.jpg',
        )
        SubPluginGameFactory(
            sub_plugin=self.sub_plugin_1,
            game=game,
        )
        response = self.client.get(
            path=self.list_path,
            data={'game': 'game1'},
        )
        self.assertEqual(first=len(connection.queries), second=5)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        self.assertEqual(
            first=response.json()['count'],
            second=1,
        )

        # Validate user filtering
        response = self.client.get(
            path=self.list_path,
            data={'user': self.regular_user.user.username},
        )
        self.assertEqual(first=len(connection.queries), second=2)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        self.assertEqual(
            first=response.json()['count'],
            second=0,
        )
        response = self.client.get(
            path=self.list_path,
            data={'user': self.contributor_1.user.username},
        )
        self.assertEqual(first=len(connection.queries), second=5)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        self.assertEqual(
            first=response.json()['count'],
            second=1,
        )
        response = self.client.get(
            path=self.list_path,
            data={'user': self.owner.user.username},
        )
        self.assertEqual(first=len(connection.queries), second=5)
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )
        self.assertEqual(
            first=response.json()['count'],
            second=2,
        )

    @override_settings(DEBUG=True)
    def test_get_details(self):
        environ = getattr(self.client, '_base_environ')()
        domain = f'{environ["wsgi.url_scheme"]}://{environ["SERVER_NAME"]}'
        zip_file_1 = f'{domain}{self.current_release_1.get_absolute_url()}'
        payload_1 = deepcopy(self.payload_1)
        payload_1['current_release']['zip_file'] = zip_file_1
        payload_1['current_release']['download_requirements'] = []
        payload_1['current_release']['package_requirements'] = []
        payload_1['current_release']['pypi_requirements'] = []
        payload_1['current_release']['version_control_requirements'] = []
        payload_1['logo'] = f'{domain}{self.sub_plugin_1.logo.url}'
        del payload_1['contributors']
        zip_file_2 = f'{domain}{self.current_release_2.get_absolute_url()}'
        payload_2 = deepcopy(self.payload_2)
        payload_2['current_release']['zip_file'] = zip_file_2
        payload_2['current_release']['download_requirements'] = []
        payload_2['current_release']['package_requirements'] = []
        payload_2['current_release']['pypi_requirements'] = []
        payload_2['current_release']['version_control_requirements'] = []
        del payload_2['contributors']
        detail_path_2 = reverse(
            viewname=self.detail_api,
            kwargs={
                'plugin_slug': self.plugin.slug,
                'slug': self.sub_plugin_2.slug,
            }
        )
        for path, payload in (
            (self.detail_path, payload_1),
            (detail_path_2, payload_2),
        ):
            # Verify that non-logged-in user can see details
            self.client.logout()
            response = self.client.get(path=path)
            self.assertEqual(first=len(connection.queries), second=7)
            self.assertEqual(
                first=response.status_code,
                second=status.HTTP_200_OK,
            )
            self.assertDictEqual(
                d1=response.json(),
                d2=payload,
            )

            # Verify that regular user can see details
            self.client.force_login(self.regular_user.user)
            response = self.client.get(path=path)
            self.assertEqual(first=len(connection.queries), second=9)
            self.assertEqual(
                first=response.status_code,
                second=status.HTTP_200_OK,
            )
            self.assertDictEqual(
                d1=response.json(),
                d2=payload,
            )

            # Verify that contributors can see details
            self.client.force_login(self.contributor_1.user)
            response = self.client.get(path=path)
            self.assertEqual(first=len(connection.queries), second=9)
            self.assertEqual(
                first=response.status_code,
                second=status.HTTP_200_OK,
            )
            self.assertDictEqual(
                d1=response.json(),
                d2=payload,
            )

            # Verify that the owner can see details
            self.client.force_login(self.owner.user)
            response = self.client.get(path=path)
            self.assertEqual(first=len(connection.queries), second=9)
            self.assertEqual(
                first=response.status_code,
                second=status.HTTP_200_OK,
            )
            self.assertDictEqual(
                d1=response.json(),
                d2=payload,
            )

    @override_settings(MEDIA_ROOT=MEDIA_ROOT)
    def test_post(self):
        # Verify non-logged-in user cannot create a sub-plugin
        plugin = PluginFactory(
            basename='test_plugin',
        )
        SubPluginPathFactory(
            plugin=plugin,
            path='sub_plugins',
            allow_package_using_basename=True,
        )
        base_path = settings.BASE_DIR / 'fixtures' / 'releases' / 'sub-plugins'
        file_path = base_path / 'test-plugin' / 'test-sub-plugin' / 'test-sub-plugin-v1.0.0.zip'
        version = '1.0.0'
        api_path = reverse(
            viewname=self.list_api,
            kwargs={'plugin_slug': plugin.slug},
        )
        with file_path.open('rb') as open_file:
            zip_file = UploadedFile(open_file, content_type='application/zip')
            response = self.client.post(
                path=api_path,
                data={
                    'name': 'Test SubPlugin',
                    'releases.notes': '',
                    'releases.version': version,
                    'releases.zip_file': zip_file,
                },
            )

        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_403_FORBIDDEN,
        )

        # Verify that a logged-in user can create a sub-plugin
        self.assertEqual(
            first=SubPlugin.objects.count(),
            second=2,
        )
        with file_path.open('rb') as open_file:
            zip_file = UploadedFile(open_file, content_type='application/zip')
            self.client.force_login(self.regular_user.user)
            response = self.client.post(
                path=api_path,
                data={
                    'name': 'Test SubPlugin',
                    'releases.notes': '',
                    'releases.version': version,
                    'releases.zip_file': zip_file,
                },
            )

        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_201_CREATED,
        )
        self.assertEqual(
            first=SubPlugin.objects.count(),
            second=3,
        )
        content = response.json()
        sub_plugin = SubPlugin.objects.get(slug=content['slug'])
        self.assertEqual(
            first=sub_plugin.releases.count(),
            second=1,
        )
        release = sub_plugin.releases.get()
        self.assertEqual(
            first=release.created_by.forum_id,
            second=self.regular_user.forum_id,
        )
        self.assertEqual(
            first=release.version,
            second=version,
        )

        # Verify cannot create a sub-plugin where the basename already exists
        with file_path.open('rb') as open_file:
            zip_file = UploadedFile(open_file, content_type='application/zip')
            response = self.client.post(
                path=api_path,
                data={
                    'name': 'Test SubPlugin',
                    'releases.notes': '',
                    'releases.version': version,
                    'releases.zip_file': zip_file,
                },
            )

        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_400_BAD_REQUEST,
        )
        self.assertDictEqual(
            d1=response.json(),
            d2={'basename': 'SubPlugin already exists. Cannot create.'}
        )

    @override_settings(MEDIA_ROOT=MEDIA_ROOT)
    def test_post_with_requirements(self):
        plugin = PluginFactory(
            basename='test_plugin',
        )
        SubPluginPathFactory(
            plugin=plugin,
            path='sub_plugins',
            allow_package_using_basename=True,
        )
        base_path = settings.BASE_DIR / 'fixtures' / 'releases' / 'sub-plugins'
        sub_plugin_file_path = base_path / 'test-plugin' / 'test-sub-plugin'
        file_path = sub_plugin_file_path / 'test-sub-plugin-requirements-v1.0.0.zip'
        version = '1.0.0'
        custom_package_1 = PackageFactory(
            basename='custom_package_1',
        )
        PackageReleaseFactory(
            package=custom_package_1,
            version='1.0.0',
        )
        custom_package_2 = PackageFactory(
            basename='custom_package_2',
        )
        PackageReleaseFactory(
            package=custom_package_2,
            version='1.0.0',
        )
        self.assertEqual(
            first=DownloadRequirement.objects.count(),
            second=0,
        )
        self.assertEqual(
            first=PyPiRequirement.objects.count(),
            second=0,
        )
        self.assertEqual(
            first=VersionControlRequirement.objects.count(),
            second=0,
        )
        self.client.force_login(self.owner.user)
        with file_path.open('rb') as open_file:
            zip_file = UploadedFile(open_file, content_type='application/zip')
            response = self.client.post(
                path=reverse(
                    viewname=self.list_api,
                    kwargs={'plugin_slug': plugin.slug},
                ),
                data={
                    'name': 'Test Package',
                    'releases.notes': '',
                    'releases.version': version,
                    'releases.zip_file': zip_file,
                },
            )

        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_201_CREATED,
        )
        contents = response.json()
        sub_plugin = SubPlugin.objects.get(slug=contents['slug'], plugin=plugin)
        release = SubPluginRelease.objects.get(sub_plugin=sub_plugin)
        self.assertEqual(
            first=DownloadRequirement.objects.count(),
            second=2,
        )
        self.assertEqual(
            first=release.download_requirements.count(),
            second=2,
        )
        self.assertEqual(
            first=PyPiRequirement.objects.count(),
            second=2,
        )
        self.assertEqual(
            first=release.pypi_requirements.count(),
            second=2,
        )
        self.assertEqual(
            first=VersionControlRequirement.objects.count(),
            second=2,
        )
        self.assertEqual(
            first=release.vcs_requirements.count(),
            second=2,
        )

    def test_patch(self):
        # Verify that non-logged-in user cannot update a path
        response = self.client.patch(
            path=self.detail_path,
            data={
                'synopsis': 'Test Synopsis',
            }
        )
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_403_FORBIDDEN,
        )

        # Verify that regular user cannot update a path
        self.client.force_login(self.regular_user.user)
        response = self.client.patch(
            path=self.detail_path,
            data={
                'synopsis': 'Test Synopsis',
            }
        )
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_403_FORBIDDEN,
        )

        # Verify that contributor can update a path
        self.client.force_login(self.contributor_1.user)
        response = self.client.patch(
            path=self.detail_path,
            data={
                'synopsis': 'Test Synopsis',
            }
        )
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )

        # Verify that owner can update a path
        self.client.force_login(self.owner.user)
        response = self.client.patch(
            path=self.detail_path,
            data={
                'synopsis': 'New Test Synopsis',
            }
        )
        self.assertEqual(
            first=response.status_code,
            second=status.HTTP_200_OK,
        )

    def test_options(self):
        # Verify that non-logged-in user cannot POST
        response = self.client.options(path=self.list_path)
        self.assertEqual(first=response.status_code, second=status.HTTP_200_OK)
        content = response.json()
        self.assertEqual(
            first=content['name'],
            second='Sub Plugin List',
        )
        self.assertNotIn(member='actions', container=content)

        # Verify that normal user can POST
        self.client.force_login(user=self.regular_user.user)
        response = self.client.options(path=self.list_path)
        self.assertEqual(first=response.status_code, second=status.HTTP_200_OK)
        content = response.json()
        self.assertEqual(
            first=content['name'],
            second='Sub Plugin List',
        )
        self.assertIn(member='actions', container=content)
        self.assertSetEqual(set1=set(content['actions']), set2={'POST'})

    def test_options_object(self):
        # Verify that non-logged-in user cannot PATCH
        response = self.client.options(path=self.detail_path)
        self.assertEqual(first=response.status_code, second=status.HTTP_200_OK)
        content = response.json()
        self.assertEqual(
            first=content['name'],
            second='Sub Plugin Instance',
        )
        self.assertNotIn(member='actions', container=content)

        # Verify that normal user cannot PATCH
        self.client.force_login(user=self.regular_user.user)
        response = self.client.options(path=self.detail_path)
        self.assertEqual(first=response.status_code, second=status.HTTP_200_OK)
        content = response.json()
        self.assertEqual(
            first=content['name'],
            second='Sub Plugin Instance',
        )
        self.assertNotIn(member='actions', container=content)

        # Verify that contributors can PATCH
        self.client.force_login(user=self.contributor_1.user)
        response = self.client.options(path=self.detail_path)
        self.assertEqual(first=response.status_code, second=status.HTTP_200_OK)
        content = response.json()
        self.assertEqual(
            first=content['name'],
            second='Sub Plugin Instance',
        )
        self.assertIn(member='actions', container=content)
        self.assertSetEqual(set1=set(content['actions']), set2={'PATCH'})

        # Verify that the owner can PATCH
        self.client.force_login(user=self.owner.user)
        response = self.client.options(path=self.detail_path)
        self.assertEqual(first=response.status_code, second=status.HTTP_200_OK)
        content = response.json()
        self.assertEqual(
            first=content['name'],
            second='Sub Plugin Instance',
        )
        self.assertIn(member='actions', container=content)
        self.assertSetEqual(set1=set(content['actions']), set2={'PATCH'})


# Daily Temperatures
# 스택과 인덱스를 활용하여 현재 기온보다 높을 때까지 며칠 걸리는지 확인

temperatures = [73,74,75,71,69,72,76,73]

class Solution(object):
    def dailyTemperatures(self, temperatures):
        """
        :type temperatures: List[int]
        :rtype: List[int]
        """

        answer = [0] * len(temperatures)
        stack = []

        for i, cur in enumerate(temperatures):

            # 현재 온도가 높을 때만 갱신
            while stack and cur > temperatures[stack[-1]]:
                last = stack.pop()
                answer[last] = i - last # 현재 인덱스 - 스택에 쌓아둔 현재 온도 값

            stack.append(i)

        return answer

Sol = Solution()
print(Sol.dailyTemperatures(temperatures))


from pptx.util import Inches

def py_replace_image(pres, label, new_image, new_height=True):
    """Replace a template image with a new image

    Keyword arguments:
     pres -- pptx Pres object containing the text to be replaced
     label -- The unique label of the object containing the text to be replaced
     new_image -- Path to the new image.
     new_height -- Change the height of the new image to match the old image?
    """
    # Get slide index from label
    slide_idx_list = []
    for slide_idx, slide in enumerate(pres.slides):
        target_shape = [shape for shape in slide.shapes if shape.name == label]
        slide_contains_target_shape = len(target_shape) > 0

        if slide_contains_target_shape:
            slide_idx_list.append(slide_idx)

    if len(slide_idx_list) == 1:
        slide_idx = slide_idx_list[0]
    elif len(slide_idx_list) == 0:
        raise Exception("No object with the specified label was found.")
    elif len(slide_idx_list) > 1:
        raise Exception("More than one object with the specified label was found.")

    # Get shape from label
    target_shape = [
        shape for slide in pres.slides for shape in slide.shapes if shape.name == label
    ]

    if len(target_shape) == 0:
        raise Exception("No object with the specified label was found.")
    elif len(target_shape) > 1:
        raise Exception("More than one shape with that label was found.")

    old_image = target_shape[0]

    slide = pres.slides[slide_idx]

    # Make sure the size and position of the new image are the same as for the
    # old image.
    shape_left = Inches(old_image.left.inches)
    shape_top = Inches(old_image.top.inches)
    shape_width = Inches(old_image.width.inches)

    if new_height:
        shape_height = Inches(old_image.height.inches)
    else:
        shape_height = None

    # Add the new image
    new_shape = slide.shapes.add_picture(
        new_image,
        left=shape_left,
        top=shape_top,
        width=shape_width,
        height=shape_height,
    )

    # Delete the old image
    old_image = old_image._element
    new_pic = new_shape._element
    old_image.addnext(new_pic)
    old_image.getparent().remove(old_image)


import csv, json
from fastkml import kml
from geojson import Feature, FeatureCollection, Point, LineString, Polygon
import xml.etree.ElementTree as ET

input_file_name = 'pedbike_risk_exposure_IE_NM_Superior'

input_file = 'data/'+ input_file_name + '.csv'
output_file = 'data/'+ input_file_name + '_GeoJson.json'
output_file_1 = 'data/'+ input_file_name + '_GeoJson_1.json'
output_file_2 = 'data/'+ input_file_name + '_GeoJson_2.json'
features = []

def remove_tags(text):
    extracted_string = ';'.join(ET.fromstring(text).itertext())
    array = extracted_string.split()
    return array

'''csv line'''
'''
with open(input_file, newline='') as csvlinefile:
    reader = csv.reader(csvlinefile, delimiter=',')
    next(reader)

    for geometry, weight, fips, region, rid, rank in reader:
        extracted_array = remove_tags(geometry)
        line_coords = []
        for coords in extracted_array:
            if len(coords.split(',')) == 2:
                longitude,latitude = coords.split(',')
            elif len(coords.split(',')) == 3:
                longitude,latitude, elevation = coords.split(',')

            longitude, latitude = map(float, (longitude, latitude))
            line_coords.append((longitude, latitude))

        features.append(
            Feature(
                geometry = LineString(line_coords),
                properties = {
                    'weight': weight,
                    'fips'  : fips,
                    'region': region,
                    'rid'   : rid,
                    'rank'  : rank
                }
            )
        )

collection = FeatureCollection(features)
with open(output_file, "w") as f:
    f.write('%s' % collection)
'''

'''csv polygon'''
# {
# "displayFieldName" : "<displayFieldName>",
# "fieldAliases" : {
#   "<fieldName1>" : "<fieldAlias1>",
#   "<fieldName2>" : "<fieldAlias2>"
# },
# "geometryType" : "<geometryType>",
# "hasZ" : <true|false>,  //Added at 10.1
# "hasM" : <true|false>,   //Added at 10.1
# "spatialReference" : <spatialReference>,
# "fields": [
#             {
#                 "name": "<field1>",
#                 "type": "<field1Type>",
#                 "alias": "<field1Alias>"
#             },
#             {
#                 "name": "<field2>",
#                 "type": "<field2Type>",
#                 "alias": "<field2Alias>"
#             }
#         ],
#  "features": [
#             {
#                 "geometry": {
#                     <geometry1>
#                 },
#                 "attributes": {
#                     "<field1>": <value11>,
#                     "<field2>": <value12>
#                 }
#             },
#             {
#                 "geometry": {
#                     <geometry2>
#                 },
#                 "attributes": {
#                     "<field1>": <value21>,
#                     "<field2>": <value22>
#                 }
#             }
#         ]
# }
with open(input_file, newline='') as csvpolygonfile:
    reader = csv.reader(csvpolygonfile, delimiter=',')
    next(reader)

    for spaz_id, fips, region, Rid, PedCrashCt, Ped_Risk, PRrank, BikeCrashCt, \
        Bike_Risk, BRrank, PedExp, PErank, Pie, PIErank, BikeExp, BErank, Bie, \
        BIErank, NMRisk, NMRrank, NMExp, NMErank, geometry in reader:

        extracted_array = remove_tags(geometry)
        polygon_coords = []
        for coords in extracted_array:
            if len(coords.split(',')) == 2:
                longitude,latitude = coords.split(',')
            elif len(coords.split(',')) == 3:
                longitude,latitude, elevation = coords.split(',')

            longitude, latitude = map(float, (longitude, latitude))
            polygon_coords.append((longitude, latitude))

        features.append(
            Feature(
                geometry = Polygon([polygon_coords]),
                properties = {
                    'spaz_id'     : spaz_id,
                    'fips'        : fips,
                    'region'      : region,
                    'Rid'         : Rid,
                    'PedCrashCt'  : PedCrashCt,
                    'Ped_Risk'    : Ped_Risk,
                    'PRrank'      : PRrank,
                    'BikeCrashCt' : BikeCrashCt,
                    'Bike_Risk'   : Bike_Risk,
                    'BRrank'      : BRrank,
                    'PedExp'      : PedExp,
                    'PErank'      : PErank,
                    'Pie'         : Pie,
                    'PIErank'     : PIErank,
                    'BikeExp'     : BikeExp,
                    'BErank'      : BErank,
                    'Bie'         : Bie,
                    'BIErank'     : BIErank,
                    'NMRisk'      : NMRisk,
                    'NMRrank'     : NMRrank,
                    'NMExp'       : NMExp,
                    'NMErank'     : NMErank
                }
            )
        )

# features_1 = features[:len(features)//2]
# features_2 = features[len(features)//2:]
# collection_1 = FeatureCollection(features_1)
# collection_2 = FeatureCollection(features_2)
# with open(output_file_1, "w") as f1:
#     f1.write('%s' % collection_1)

# with open(output_file_2, "w") as f2:
#     f2.write('%s' % collection_2)

collection = FeatureCollection(features)

with open(output_file, "w") as f:
    f.write('%s' % collection)

# pedbike_risk_exposure_IE_NM_NorthBay_GeoJson_1

# {
# "displayFieldName" : "<displayFieldName>",
# "fieldAliases" : {
#   "<fieldName1>" : "<fieldAlias1>",
#   "<fieldName2>" : "<fieldAlias2>"
# },
# "geometryType" : "<geometryType>",
# "hasZ" : <true|false>,  //Added at 10.1
# "hasM" : <true|false>,   //Added at 10.1
# "spatialReference" : <spatialReference>,
# "fields": [
#             {
#                 "name": "<field1>",
#                 "type": "<field1Type>",
#                 "alias": "<field1Alias>"
#             },
#             {
#                 "name": "<field2>",
#                 "type": "<field2Type>",
#                 "alias": "<field2Alias>"
#             }
#         ],
#  "features": [
#             {
#                 "geometry": {
#                     <geometry1>
#                 },
#                 "attributes": {
#                     "<field1>": <value11>,
#                     "<field2>": <value12>
#                 }
#             },
#             {
#                 "geometry": {
#                     <geometry2>
#                 },
#                 "attributes": {
#                     "<field1>": <value21>,
#                     "<field2>": <value22>
#                 }
#             }
#         ]
# }

#{   "type": "FeatureCollection",
#     "features": [
#         {   "type": "Feature",
#             "geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
#             "properties": {"prop0": "value0"}
#         },
#         {   "type": "Feature",
#             "geometry": {
#             "type": "LineString",
#             "coordinates": [
#                 [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
#                 ]
#             },
#             "properties": {
#             "prop0": "value0",
#             "prop1": 0.0
#             }
#         },
#         {   "type": "Feature",
#             "geometry": {
#             "type": "Polygon",
#             "coordinates": [
#                 [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
#                 [100.0, 1.0], [100.0, 0.0] ]
#                 ]
#             },
#             "properties": {
#             "prop0": "value0",
#             "prop1": {"this": "that"}
#             }
#         }
#     ]
# }

# Formatting
# { "type": "FeatureCollection",
#   "features": [
#     { "type": "Feature",
#       "geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
#       "properties": {"prop0": "value0"}
#       },
#     { "type": "Feature",
#       "geometry": {
#         "type": "LineString",
#         "coordinates": [
#           [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
#           ]
#         },
#       "properties": {
#         "prop0": "value0",
#         "prop1": 0.0
#         }
#       },
#     { "type": "Feature",
#        "geometry": {
#          "type": "Polygon",
#          "coordinates": [
#            [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
#              [100.0, 1.0], [100.0, 0.0] ]
#            ]
#        },
#        "properties": {
#          "prop0": "value0",
#          "prop1": {"this": "that"}
#          }
#        }
#      ]
#    }


# Main file endpoint of my application
# In this file implemented 1st task
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles

# Import submodule for 2. task
from controllers import go

# Import submodule for 3. task
from controllers import get_short_url, todo_links, todo_users

# Import model that do encode and decode to base64
from models.Converter import Converter

# uncomment this two lines below if you work without migration
# from db.database import engine, Base
# Base.metadata.create_all(engine)

# Create instance of my application
app = FastAPI()

origins = ["*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Now we add each our routers to main FastAPI applocation
app.include_router(go.router)
app.include_router(get_short_url.router)
app.include_router(todo_links.router)
app.include_router(todo_users.router)

app.mount("/todo-links", StaticFiles(directory="./frontend/", html = True), name="static")

# Default page
@app.get("/")
async def root():
    return "Hello World"

# Page for 1. task
# Inside this endpoint use method from BaseModel for encode a URL
@app.post("/base64")
async def base64(url: str):
    coder = Converter()
    result = coder.encode_url(url)
    return {"result": result}


"""
This module contains methods to return numerical solutions for
the Double Pendulum problem.
"""
from typing import Iterable, List, Tuple, Callable, Protocol
from scipy.integrate import odeint, solve_ivp

import numpy as np

vector = np.ndarray

class ODE:
    #[[vector, float, Tuple], vector]
    @staticmethod
    def rk4_solve(deriv: Callable,
                    y0: vector, t_arr: vector, args: Tuple) -> vector:
        # while current_t < t_arr[-1]
        # for each eq in deriv and each init value in y0
        #   k1 = deriv(t_n, y_n)
        #   k2 = deriv(t_n + h/2, y_n + h*k1/2)
        #   k3 = deriv(t_n + h/2, y_n + h*k2/2)
        #   k4 = deriv(t_n + h, y_n + h*k3)
        #   y_{n+1} = y_n + (1/6) * h * (k1 + 2*k2 + 2*k3 + k4)
        #   t_{n+1} = t_n + h

        prev_y = y0
        h = t_arr[1] - t_arr[0]

        solution = np.full((len(t_arr), len(y0)), y0)

        for idx in range(1, len(t_arr)):
            k1 = deriv(prev_y, t_arr[idx], *args)
            k2 = deriv(prev_y + (h / 2) * k1, t_arr[idx] + h / 2, *args)
            k3 = deriv(prev_y + (h / 2) * k2, t_arr[idx] + h / 2, *args)
            k4 = deriv(prev_y + h * k3, t_arr[idx] + h, *args)

            y = prev_y + (1.0 / 6.0) * h * (k1 + 2 * k2 + 2 * k3 + k4)
            solution[idx] = y

            prev_y = y

        return solution

class DoublePendulum:
    def __init__(self, l1: float, l2: float, m1: float, m2: float):
        self.l1 = l1
        self.l2 = l2
        self.m1 = m1
        self.m2 = m2

    @staticmethod
    def derivative(init_conditions: vector, t,
                    l1: float, l2: float, m1: float,
                    m2: float, g: float = 9.81) -> vector:
        """
        Returns the vector [theta_1', theta_2', w1', w2']
        using the equations of motion for a double pendulum
        """
        theta_1, theta_2, w1, w2 = init_conditions

        sine = np.sin(theta_1 - theta_2)
        cosine = np.cos(theta_1 - theta_2)

        denominator1 = l1 * (m1 + m2 * sine * sine)
        denominator2 = l2 * (m1 + m2 * sine * sine)

        numerator1 = (m2 * g * np.sin(theta_2) * cosine
                    - m2 * sine * (l1 * w1 * w1 * cosine + l2 * w2 * w2)
                    - (m1 + m2) * g * np.sin(theta_1))

        numerator2 = ((m1 + m2) * (l1 * w1 * w1 * sine
                    - g * np.sin(theta_2) + g * np.sin(theta_1) * cosine)
                    + m2 * l2 * w2 * w2 * sine * cosine)

        w1_dot = numerator1 / denominator1
        w2_dot = numerator2 / denominator2

        return np.array([w1, w2, w1_dot, w2_dot])

    def numerical_solve(self, dt: float, tmax: float,
                        y0: vector) -> Iterable[vector]:
        """
        Solves the ODE using scipy's odeint(), given the initial
        conditions in y0 and the time variables.
        """

        t = np.arange(0, tmax + dt, dt)

        # y has form [[theta_1(0), theta_2(0), w1(0), w2(0)],
        #             [theta_1(dt), theta_2(dt), w1(dt), w2(dt)], ...]
        y = ODE.rk4_solve(DoublePendulum.derivative, y0, t,
                            args=(self.l1, self.l2, self.m1, self.m2))

        theta_1 = y[:, 0]   # ':, 0' -> from all elements, return idx 0
        theta_2 = y[:, 1]   # ':, 1' -> from all elements, return idx 1

        return t, theta_1, theta_2

    def numerical_solve_scipy(self, dt: float, tmax: float,
                        y0: vector) -> Iterable[vector]:
        """
        Solves the ODE using scipy's odeint(), given the initial
        conditions in y0 and the time variables.
        """

        t = np.arange(0, tmax + dt, dt)

        # y has form [[theta_1(0), theta_2(0), w1(0), w2(0)],
        #             [theta_1(dt), theta_2(dt), w1(dt), w2(dt)], ...]
        y = odeint(DoublePendulum.derivative, y0, t,
                            args=(self.l1, self.l2, self.m1, self.m2))

        theta_1 = y[:, 0]   # ':, 0' -> from all elements, return idx 0
        theta_2 = y[:, 1]   # ':, 1' -> from all elements, return idx 1

        return t, theta_1, theta_2

    def numerical_solve_scipy_ivp(self, dt: float, tmax: float,
                        y0: vector) -> Iterable[vector]:
        """
        Solves the ODE using scipy's odeint(), given the initial
        conditions in y0 and the time variables.
        """

        t = np.arange(0, tmax + dt, dt)

        # y has form [[theta_1(0), theta_2(0), w1(0), w2(0)],
        #             [theta_1(dt), theta_2(dt), w1(dt), w2(dt)], ...]
        y = solve_ivp(DoublePendulum.derivative, (t[0], t[-1]), y0,
                            t_eval=t, method="LSODA",
                            args=(self.l1, self.l2, self.m1, self.m2)).y
        print(y)

        theta_1 = y[:, 0]   # ':, 0' -> from all elements, return idx 0
        theta_2 = y[:, 1]   # ':, 1' -> from all elements, return idx 1

        return t, theta_1, theta_2