import streamlit as st
import xlrd
import openpyxl
import pandas as pd
import plost
import matplotlib.pyplot as plt
import teams_information
import teams_map
from PIL import Image

st.set_page_config(layout="wide")
st.title('NBA資訊面板系統')

st.sidebar.header('請選擇區域及球隊')
area_list={'Atlantic':['Boston Celtics', 'Brooklyn Nets', 'New York Knicks', 'Philadelphia 76ers','Toronto Raptors'],
           'Central':['Chicago Bulls', 'Cleveland Cavaliers', 'Detroit Pistons', 'Indiana Pacers','Milwaukee Bucks'],
           'Southeast':['Atlanta Hawks', 'Charlotte Hornets', 'Miami Heat', 'Orlando Magic','Washington Wizards'],
           'Northwest':['Denver Nuggets', 'Minnesota Timberwolves', 'Oklahoma City Thunder','Portland Trail Blazers','Utah Jazz'],
           'Pacific':['Golden State Warriors', 'Los Angeles Clippers', 'Los Angeles Lakers', 'Phoenix Suns','Sacramento Kings'],
           'Southwest':['Dallas Mavericks', 'Houston Rockets', 'Memphis Grizzlies', 'New Orleans Pelicans','San Antonio Spurs']}
option_area = st.sidebar.selectbox('選擇區域？',area_list)
option = st.sidebar.selectbox('選擇球隊？',area_list[option_area])

legend_list={'Boston Celtics':{'Bill Russell','Larry Bird','Paul Pierce'},'Brooklyn Nets':{'Julius Erving','Jason Kidd','Derrick Coleman'},'New York Knicks':{'Walt Frazier','Patrick Ewing','Willis Reed'},
            'Philadelphia 76ers':{'Charles Barkley','Allen Iverson','Wilt Chamberlain'},'Toronto Raptors':{'Kyle Lowry','Chris Bosh','Vince Carter'},'Chicago Bulls':{'Michael Jordan','Dennis Rodman','Scottie Pippen'},
            'Cleveland Cavaliers':{'LeBron James','Kevin Love','Kyrie Irving'},'Detroit Pistons':{'Isiah Thomas','Ben Wallace','Grant Hill'},'Indiana Pacers':{'Reggie Miller','Metta World Peace','Chuck Person'},
            'Milwaukee Bucks':{'Sidney Moncrief','Giannis Antetokounmpo','Glenn Robinson'},'Golden State Warriors':{'Tim Hardaway','Klay thompson','Stephen Curry'},'Los Angeles Clippers':{'Bob McAdoo','Blake Griffin','Elton Brand'},
            'Los Angeles Lakers':{'Magic Johnson',"Shaquille O'Neal",'Kobe Bryant'},'Phoenix Suns':{"Amar'e Stoudemire",'Steve Nash','Shawn Marion'},'Sacramento Kings':{'Chris Webber','Oscar Robertson','Doug Christie'},
            'Dallas Mavericks':{'Dirk Nowitzki','Derek Harper','Rolando Blackman'},'Houston Rockets':{'Hakeem Olajuwon','Moses Malone','Yao Ming'},'Memphis Grizzlies':{'Zach Randolph','Marc Gasol','Mike Miller'},
            'New Orleans Pelicans':{'Pete Maravich','Chris Paul','Anthony Davis'},'San Antonio Spurs':{'Tim Duncan','David Robinson','Manu Ginóbili'},'Atlanta Hawks':{'Bob Pettit','Dikembe Mutombo','Jamal Crawford'},
            'Charlotte Hornets':{'Kemba Walker','Dell Curry','Larry Johnson'},'Miami Heat':{'Alonzo Mourning','Dwyane Wade','Grant Long'},'Washington Wizards':{'Wes Unseld','Elvin Hayes','Earl Monroe'},
            'Denver Nuggets':{'Fat Lever','Dan Issel','David Thompson'},'Minnesota Timberwolves':{'Kevin Garnett','Sam Mitchell','Sam Cassell'},'Oklahoma City Thunder':{'Russell Westbrook','Gary Payton','Kevin Durant'},
            'Portland Trail Blazers':{'Bill Walton','Buck Williams','Clifford Robinson'},'Utah Jazz':{'Karl Malone','Darrell Griffith','John Stockton'},'Orlando Magic':{'Dwight Howard','Darrell Armstrong',"Nick Anderson"}}

teams_information.teams_information(option)
teams_map.teams_map(option)

col1,col2=st.columns((6,4))
with col1:
  st.markdown('### 球隊戰績')
  teams_data=pd.read_excel("nbateamsdata.xlsx",sheet_name=option)
  st.dataframe(teams_data)
with col2:
  dount_chart_df = pd.read_excel("nbateamsdata(dount_chart).xlsx",sheet_name=option)
  st.markdown('### 年度戰績Donut chart')
  donut_theta = st.selectbox('選擇年度', ('14-15年', '15-16年','16-17年','17-18年','18-19年','19-20年','20-21年','21-22年'))
  plost.donut_chart(
              data=dount_chart_df ,
              theta=donut_theta,
              color='項目',
              legend='bottom',
              use_container_width=True)
data_list={"三分球命中率":"3P%","兩分球命中率":"2P%","罰球命中率":"FT%","投籃命中率":"FG%"}
option1 = st.selectbox('想查看數據？',data_list)
teams_data=pd.read_excel("nbateamsdata.xlsx",sheet_name=option)
area_data=pd.read_excel("nbateamsdata.xlsx",sheet_name=area_list[option_area])
league_data=pd.read_excel("nbateamsdata.xlsx",sheet_name='League Average')
if option1=='三分球命中率':
  col1,col2=st.columns(2)
  with col1:
   st.dataframe(area_data)
  with col2:
   plt.style.use("ggplot")
   plt.plot(teams_data.年度,teams_data.三分球命中率 ,'.-' )
   plt.plot(league_data.年度,league_data.三分球命中率,'.-' )
   plt.xlabel('Season',fontsize="10")
   plt.title(option+data_list[option1]+'vs League AVG')
   st.pyplot(plt)

st.markdown('### 2021-22球員戰績')
players_data=pd.read_excel("21-22playersdata.xlsx",sheet_name=option)
st.dataframe(players_data)

st.markdown('### 三大傳奇球星成績')
col1,col2=st.columns(2)
with col1:
   option_legendplayer = st.selectbox('選擇球員？',legend_list[option])
   legendplayer_data = pd.read_excel("teams_legendplayerdata.xlsx",index_col='球員')
   legendplayer_data=legendplayer_data.loc[option_legendplayer]
   legendplayer_data=legendplayer_data.reset_index(drop=False)
   st.dataframe(legendplayer_data.T)
with col2:
   image = Image.open('legendplayer'+'/'+option_legendplayer+'.jpg')
   st.image(image)


from unittest import TestCase
from n0s3p4ss.report import ReportSchema
from os.path import abspath, dirname
from json import loads
from marshmallow.exceptions import ValidationError

TESTS_PATH = abspath(dirname(__file__))

class ReportTest(TestCase):

    @classmethod
    def setUpClass(cls):
        cls.certificate_informations = dict(
            issuer='RapidSSL RSA CA 2018',
            expiration='2020-10-21'
        )

        cls.report = dict(
            subdomain='account-api.grupozap.com',
            url='https://account-api.grupozap.com/',
            ip='104.17.160.19',
            status=403,
            cert_info=cls.certificate_informations,
            server='cloudflare',
            tor_reachable=False,
            detected_waf=['Cloudflare (Cloudflare Inc.)'],
            open_ports=[80, 443, 8080, 8443],
            alerts=[
                '"Access-control-allow-origin" not present!',
                '"Content-security-policy" not present!',
                '"Path" defined as "/"!'
            ]
        )

        cls.bad_report = dict(
            subdomain='account-api.grupozap.com',
            url='https://account-api.grupozap.com/',
            ipipuhaa='104.17.160.19',
            status=403,
            cert_info=cls.certificate_informations,
            serverus='cloudflare',
            tor_reachable=False,
            wafestruz=['Cloudflare (Cloudflare Inc.)'],
            open_ports=[80, 443, 8080, 8443],
            alerts=[
                '"Access-control-allow-origin" not present!',
                '"Content-security-policy" not present!',
                '"Path" defined as "/"!'
            ]
        )

        cls.report_schema = ReportSchema()

        with open(f'{TESTS_PATH}/resources/report.json') as json_file:
            cls.json = json_file.read()

        with open(f'{TESTS_PATH}/resources/bad_report.json') as bad_json_file:
            cls.bad_json = bad_json_file.read()

    def test_that_should_serialize_report_to_json(self):
        json = self.report_schema.dumps(self.report)

        self.assertEqual(loads(self.json), loads(json))

    def test_that_should_not_serialize_missing_fields_to_json(self):
        json = self.report_schema.dumps(self.bad_report)

        self.assertNotEqual(loads(self.json), loads(json))
        self.assertNotIn('waf', json)
        self.assertNotIn('server', json)
        self.assertNotIn('ip', json)

    def test_that_should_deserialize_json_to_report(self):
        new_report = self.report_schema.loads(self.json)

        self.assertEqual(self.report, new_report)

    def test_that_should_not_deserialize_json_to_report(self):
        with self.assertRaises(ValidationError):
            self.report_schema.loads(self.bad_json)


import logging
import os
import subprocess
import threading

from common import SubprocessCallWithTimeout

_SSH = ['ssh']
_SCP = ['scp', '-C']  # Use gzip compression.
_SSH_LOGGER = logging.getLogger('ssh')

COPY_TO_TARGET = 0
COPY_FROM_TARGET = 1

def _IsLinkLocalIPv6(hostname):
  return hostname.startswith('fe80::')

def _EscapeIfIPv6Address(address):
  if ':' in address:
    return '[' + address + ']'
  else:
    return address

class CommandRunner(object):
  """Helper class used to execute commands on a remote host over SSH."""

  def __init__(self, config_path, host, port):
    """Creates a CommandRunner that connects to the specified |host| and |port|
    using the ssh config at the specified |config_path|.

    config_path: Full path to SSH configuration.
    host: The hostname or IP address of the remote host.
    port: The port to connect to."""

    self._config_path = config_path
    self._host = host
    self._port = port

  def _GetSshCommandLinePrefix(self):
    cmd_prefix = _SSH + ['-F', self._config_path, self._host]
    if self._port:
      cmd_prefix += ['-p', str(self._port)]
    return cmd_prefix

  def RunCommand(self, command, silent, timeout_secs=None):
    """Executes an SSH command on the remote host and blocks until completion.

    command: A list of strings containing the command and its arguments.
    silent: If true, suppresses all output from 'ssh'.
    timeout_secs: If set, limits the amount of time that |command| may run.
                  Commands which exceed the timeout are killed.

    Returns the exit code from the remote command."""

    ssh_command = self._GetSshCommandLinePrefix() + command
    logging.warning(ssh_command)
    _SSH_LOGGER.debug('ssh exec: ' + ' '.join(ssh_command))
    retval, _, _ = SubprocessCallWithTimeout(ssh_command, silent, timeout_secs)
    return retval

  def RunCommandPiped(self, command, stdout, stderr, ssh_args = None, **kwargs):
    """Executes an SSH command on the remote host and returns a process object
    with access to the command's stdio streams. Does not block.

    command: A list of strings containing the command and its arguments.
    stdout: subprocess stdout.  Must not be None.
    stderr: subprocess stderr.  Must not be None.
    ssh_args: Arguments that will be passed to SSH.
    kwargs: A dictionary of parameters to be passed to subprocess.Popen().
            The parameters can be used to override stdin and stdout, for
            example.

    Returns a Popen object for the command."""

    if not stdout or not stderr:
      raise Exception('Stdout/stderr must be specified explicitly')

    if not ssh_args:
      ssh_args = []

    ssh_command = self._GetSshCommandLinePrefix() + ssh_args + ['--'] + command
    logging.warning(ssh_command)
    _SSH_LOGGER.debug(' '.join(ssh_command))
    return subprocess.Popen(ssh_command, stdout=stdout, stderr=stderr, **kwargs)

  def RunScp(self, sources, dest, direction, recursive=False):
    """Copies a file to or from a remote host using SCP and blocks until
    completion.

    sources: Paths of the files to be copied.
    dest: The path that |source| will be copied to.
    direction: Indicates whether the file should be copied to
               or from the remote side.
               Valid values are COPY_TO_TARGET or COPY_FROM_TARGET.
    recursive: If true, performs a recursive copy.

    Function will raise an assertion if a failure occurred."""

    scp_command = _SCP[:]
    if _SSH_LOGGER.getEffectiveLevel() == logging.DEBUG:
      scp_command.append('-v')
    if recursive:
      scp_command.append('-r')

    host = _EscapeIfIPv6Address(self._host)

    if direction == COPY_TO_TARGET:
      dest = "%s:%s" % (host, dest)
    else:
      sources = ["%s:%s" % (host, source) for source in sources]

    scp_command += ['-F', self._config_path]
    if self._port:
      scp_command += ['-P', str(self._port)]
    scp_command += sources
    scp_command += [dest]

    _SSH_LOGGER.debug(' '.join(scp_command))
    try:
      scp_output = subprocess.check_output(scp_command,
                                           stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as error:
      _SSH_LOGGER.info(error.output)
      raise


#!/usr/bin/python3
# encoding: utf-8
from typing import List, Optional

import cv2
import numpy as np
import quaternion

import rospy
from geometry_msgs.msg import Pose
from apriltag_toolbox.msg import AprilTagDetection
from utils import rodrigues_to_quat, set_corners

class TagMap:
    _tags_w : List[AprilTagDetection] = []

    def add_or_update(self, tag_w : AprilTagDetection, pose : Pose):
        tag = self._find_by_id(tag_w.id[0], self._tags_w)
        if tag is None:
            # Not in map, add to map
            self._add_tag(tag_w, pose)
        else:
            # Already in map update
            self.update_tag(tag, pose)

    def update_tag(self, tag_w : AprilTagDetection, pose : Pose):
        tag_w.pose.pose.pose = pose
        tag_w.corners3 = set_corners(tag_w.corners, tag_w.pose.pose.pose, tag_w.size[0])

    def add_first_tag(self, tag_c : AprilTagDetection):
        # Create tag in world frame and set to origin
        # Set the first tag to origin
        pose = Pose()
        pose.position.x = 0
        pose.position.y = 0
        pose.position.z = 0
        pose.orientation.x = 0
        pose.orientation.y = 0
        pose.orientation.z = 0
        pose.orientation.w = 1
        # pose = Pose()
        # pose.position = tag_c.pose.pose.pose.position
        # pose.orientation = tag_c.pose.pose.pose.orientation
        self._add_tag(tag_c, pose)

    def init(self) -> bool:
        return len(self.tags_w()) > 0

    def first_tag(self) -> Optional[AprilTagDetection]:
        tags = self.tags_w()
        return tags[0] if len(tags) > 0 else None

    def tags_w(self) -> List[AprilTagDetection]:
        return self._tags_w

    def estimate_pose(self, tags_c : List[AprilTagDetection], K, D):
        img_pts = np.empty((1, 2), dtype=np.float64)
        obj_pts = np.empty((1, 3), dtype=np.float64)

        for tag_c in tags_c:
            # Find 2D-3D correspondences
            tag_w = self._find_by_id(tag_c.id[0], self.tags_w())
            if tag_w is not None:
                for corners in tag_w.corners3:
                    obj_pt = np.array([[corners.x, corners.y, corners.z]])
                    obj_pts = np.append(obj_pts, obj_pt, axis=0)
                img_pts = np.append(img_pts, np.array(tag_c.corners, dtype=np.float64).reshape((4, 2)), axis=0)
        obj_pts = obj_pts[1:, :]
        img_pts = img_pts[1:, :]

        assert len(img_pts) == len(obj_pts), "size mismatch!"

        if len(img_pts) == 0:
            return

        # Actual pose estimation work here
        success, c_r_w, c_t_w = cv2.solvePnP(obj_pts, img_pts, K, D, flags=0)

        if not success:
            rospy.logwarn("solvePnP failed")
            return

        c_R_w, _ = cv2.Rodrigues(c_r_w.reshape(3))

        w_T_c = -c_R_w.T * c_t_w

        pose = Pose()
        pose.position.x = w_T_c[0]
        pose.position.y = w_T_c[1]
        pose.position.z = w_T_c[2]

        # w_T_c = -c_R_w.T @ c_t_w

        # pose = Pose()
        # pose.position.x = w_T_c[0][0]
        # pose.position.y = w_T_c[1][0]
        # pose.position.z = w_T_c[2][0]

        quat = rodrigues_to_quat(c_R_w)
        quat = np.quaternion(quat[0], quat[1], quat[2], quat[3])
        w_Q_c = np.quaternion.inverse(quat)
        pose.orientation.x = w_Q_c.x
        pose.orientation.y = w_Q_c.y
        pose.orientation.z = w_Q_c.z
        pose.orientation.w = w_Q_c.w

        return pose

    ##########
    # private
    ##########
    def _add_tag(self, tag : AprilTagDetection, pose : Pose):
        self.update_tag(tag, pose)
        self._tags_w.append(tag)
        rospy.loginfo(f"tag {tag.id[0]} added to map")

    def _find_by_id(self, id : int, tags : List[AprilTagDetection]) -> Optional[AprilTagDetection]:
        for tag in tags:
            if tag.id[0] == id:
                return tag
        return None


from itertools import count
from pyneat.genome import Genome
from pyneat.partitions import Partitions

class Population(object):
    """
    Class to handle all the population of genomes.
    """

    global_count = count(1)

    def __init__(self):
        self.gid_to_genome = dict()
        """dict[int, Genome]: id to genome mapping"""

        self.gid_to_ancestors = dict()
        """dict[int, Genome]: id to genome ancestors mapping"""

    @classmethod
    def initial_population(cls, args):
        """
        Instantiate initial population.

        Args:
            args: Arguments to initialize the population. `args` has the following attributes:
                - population_size (int): initial size of population
                - input_size (int): input size of the policy to be evolved
                - output_size (int): output size of the policy to be evolved

        Returns:
            Population: Population created using the parameters passed in as `args`
        """
        pop = cls()                                                     # create population object

        for _ in range(args.population_size):                                                 # for each individual in population_size
            gid = next(Population.global_count)                                               # create new genome_id for each individual

            pop.gid_to_genome[gid] = Genome(gid, args.input_size, args.output_size)           # create genome/individual/neural-network
            pop.gid_to_ancestors[gid] = tuple()                                               # gid to ancestors mapping, initialize as empty

        return pop

    def partition(self, initial_partitions):
        """
        Partition population by similarity.

        Args:
            initial_partitions (Partitions): Set of Partitions under consideration

        Returns:
            Partitions: New partitions/species for next generation.

        Notes:
            Partition represents a species in populatoin.
        """

        unpartitioned = set(self.gid_to_genome.keys())                # set of unpartitioned/unspeciated genome
        new_partitions = Partitions()                                 # instantiate empty species/partitions

        # Find new representatives (retain the old partitions ids).
        for pid, p in initial_partitions.pid_to_partition.items():    # for each partition in initial_partitions

            new_rep = p.find_representative(unpartitioned, self)      # find representative of partition - genome

            new_partitions.new_partition(pid, members=[new_rep.key], representative=new_rep)      # find representative population

            unpartitioned.remove(new_rep.key)                         # remove the new representative genome

        # Add remaining members to partitions by finding the partition with the
        # most similar representative; if none exist then create a new partition.
        while unpartitioned:                                         # while all population not speciated
            gid = unpartitioned.pop()                                # genome_id of unspeciated genome from population
            g = self.gid_to_genome[gid]                              # get genome with genome_id
            pid = new_partitions.closest_representative(g)           # eval partition_id of species closest to genome
            if pid is None:                                          # if partition_id does not exist
                new_partitions.new_partition(pid, members=[gid], representative=g)       # create new partition for genome
            else:                                                    # if closest partition_id exists
                new_partitions.pid_to_partition[pid].members.append(gid)   # put genome in the closest partition_id

        return new_partitions

    def new_child(self, p1, p2, f1, f2):
        """
        Enables populating the new population object with a new child created using two input parents.

        Args:
            p1 (Genome): parent 1 genome
            p2 (Genome): parent 2 genome
            f1 (float): fitness of parent 1
            f2 (float): fitness of parent 2

        Returns:
            Genome: new child genome
        """
        child = Genome(next(Population.global_count), len(p1.input_keys), len(p1.output_keys))

        if f1 < f2:
            p1, p2 = p2, p1

        child = p1.crossover_edges(p2, child)
        child = p1.crossover_nodes(p2, child)

        child.mutate_()
        return child


from functools import reduce

from django.db import models
from decimal import Decimal as D
from accounts.models import (
                    Account,
                    JournalEntry
                )

from django.shortcuts import reverse

class DebitNote(models.Model):
    """
        A document sent by a business to a supplier notifying them
        that inventory has been returned for some reason.
        Linked to Orders. Stores a list of products returned.

        properties
        -----------
        returned_items - returns a queryset of all returned products for an invoice
        returned_total - returns the numerical value of the products returned.

        methods
        -----------
        create_entry - creates a journal entry in the accounting system.
    """

    date = models.DateField()
    order = models.ForeignKey('inventory.Order', on_delete=models.SET_NULL,
        null=True)
    comments = models.TextField()#never allow blank comments
    entry = models.ForeignKey('accounts.JournalEntry', null=True,
        on_delete=models.SET_NULL)
    reference_number = models.CharField(max_length=255, null=True, default=None)

    def save(self, *args, **kwargs):
        if not self.reference_number:
           prefix = 'DNOTE-{}'.format(timezone.now().strftime('%y%m%d'))
           prev_instances = self.__class__.objects.filter(reference_number__contains=prefix)
           if prev_instances.exists():
              last_instance_id = prev_instances.last().reference_number[-4:]
              self.reference_number = prefix+'{0:04d}'.format(int(last_instance_id)+1)
           else:
               self.reference_number = prefix+'{0:04d}'.format(1)
        if self.entry is None:
            self.create_entry()
        super(DebitNote, self).save(*args, **kwargs)

    @property
    def returned_items(self):
        return self.lines.all()

    @property
    def returned_total(self):
        return self.returned_subtotal + self.returned_tax

    @property
    def returned_tax(self):
        if self.returned_items.count() == 0:
            return 0
        order = self.returned_items.first().item.order
        if order.tax:
            return self.returned_subtotal * (D(self.order.tax.rate) / D(100.0))
        return 0

    @property
    def returned_subtotal(self):
        return sum([i.returned_value for i in self.returned_items ])

    # we have a pending business buddie
    def create_entry(self):
        j = JournalEntry.objects.create(
            memo="Auto generated journal entry from debit note",
            date=self.date,
            creator = self.order.issuing_inventory_controller.employee,
            is_approved = True
        )

        j.debit(self.returned_total, self.order.supplier.account)
        #Purchase returns
        j.credit(self.returned_subtotal, Account.objects.get(name='PURCHASE-RETURNS-ACCOUNT-NUMBER-ONE'))
        #Vat account
        j.credit(self.returned_tax, Account.objects.get(name='VAT-ACCOUNT-NUMBER-ONE'))

        self.entry = j
        # self.save()

class DebitNoteLine(models.Model):
    item = models.ForeignKey('inventory.OrderItem', null=True,
        on_delete=models.SET_NULL)
    note = models.ForeignKey(
                        'inventory.DebitNote',
                        null=True,
                        on_delete = models.SET_NULL,
                        related_name = 'lines'
                    )
    quantity = models.FloatField()

    def __str__(self):
        return str(self.item)

    @property
    def returned_value(self):
        return self.item.order_price * D(self.quantity)


from django.conf.urls.defaults import include, patterns, url
from django.shortcuts import redirect
from .views import product_detail, product_list, shop

urlpatterns = patterns('',
    url(r'^shop/', include(shop.urls)),
    url(r'^products/$', product_list, name='plata_product_list'),
    url(r'^products/(?P<object_id>\d+)/$', product_detail,
                                        name='plata_product_detail'),
    url(r'^$', lambda request: redirect('products/')),
    url(r'^reporting/', include('plata.reporting.urls')),
)


import pygame as pg
from word_scraping import Words
from definitions_scraping import scrape_definitions
import hourglass
import random
import string
import threading
import time

pg.init()
BACKGROUND = pg.image.load('assets/images/paper.jpg')
WINDOW_WIDTH = 1800
WINDOW_HEIGHT = 900
SCREEN = pg.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
GREY = pg.Color(220, 220, 220)
WHITE = pg.Color(255, 255, 255)
BLACK = pg.Color(0, 0, 0)
BLUE = pg.Color(0, 191, 255)
PINK = pg.Color(242, 233, 238)
DARK_GREY = pg.Color(90, 90, 90)
DARK_GREY_2 = pg.Color(170, 170, 170)
GOLD = pg.Color(235, 198, 52)
GREEN = pg.Color(0, 128, 0)
RED = pg.Color(255, 0, 0)
block_size = 40
SCREEN.blit(BACKGROUND, (0, 0))
FONT = pg.font.Font('assets/fonts/arial_bold.ttf', 27)
BUTTON_FONT = pg.font.Font('assets/fonts/arial_bold.ttf', 20)
NUMBER_FONT = pg.font.Font('assets/fonts/arial.ttf', 12)
ARROW_FONT = pg.font.Font('assets/fonts/Symbola.ttf', 10)
DEF_FONT = pg.font.Font('assets/fonts/arial.ttf', 15)
LOADING_FONT = pg.font.Font('assets/fonts/arial_bold.ttf', 40)
horizontal_number = 1
vertical_number = 1
special_chars = ['Ą', 'Ę', 'Ć', 'Ó', 'Ł', 'Ś', 'Ń', 'Ź', 'Ż', 'Y', 'X', 'V']
buttons = []
definitions = []
crossword = 0
show_definitions = False
words_used = {}
words_used_vertical = {}
loaded = True
debug_mode = False
moving_sprites = pg.sprite.Group()
loading_icon = hourglass.Hourglass(1300, 400)
moving_sprites.add(loading_icon)
img = pg.image.load('assets/images/load.png')
img = pg.transform.smoothscale(img, (23, 23)).convert_alpha()

class Button:
    def __init__(self, x, y, width, height, elevation, text, button_type):
        self.rect = pg.Rect(x, y, width, height)
        self.bottom_rect = pg.Rect(x, y, width, height)
        self.elevation = elevation
        self.text = text
        self.text_surface = BUTTON_FONT.render(text, True, BLACK)
        self.text_rect = self.text_surface.get_rect(center=self.rect.center)
        self.button_type = button_type
        self.color = GREY
        self.bottom_color = DARK_GREY
        self.border_color = BLACK
        self.original = y
        self.pressed = False
        if button_type == 4:
            definitions.append(self)
        else:
            buttons.append(self)

    def update_text(self):
        self.text_rect = self.text_surface.get_rect(center=self.rect.center)

    def button_event(self):
        mouse_pos = pg.mouse.get_pos()
        if self.rect.collidepoint(mouse_pos):
            self.color = DARK_GREY_2
            if pg.mouse.get_pressed()[0]:
                self.rect.y = self.bottom_rect.y
                self.update_text()
                update_game_state()
                self.button_action()
            else:
                self.rect.y = self.original
                self.update_text()
        else:
            self.rect.y = self.original
            self.update_text()
            self.color = GREY

    def draw(self):
        self.bottom_rect.y = self.original + self.elevation
        pg.draw.rect(SCREEN, self.bottom_color, self.bottom_rect)
        pg.draw.rect(SCREEN, self.color, self.rect)
        pg.draw.rect(SCREEN, self.border_color, self.rect, 2)
        SCREEN.blit(self.text_surface, self.text_rect)

    def button_action(self):
        if self.button_type == 0:
            t = threading.Thread(target=loading(True))
            d = threading.Thread(target=crossword_1)
            t.start()
            d.start()
        elif self.button_type == 1:
            t = threading.Thread(target=loading(True))
            d = threading.Thread(target=crossword_2)
            t.start()
            d.start()
        elif self.button_type == 2:
            debug()

class Definition(Button):
    def __init__(self, x, y, width, height, elevation, number, word_used, words_dict, text='', button_type=4):
        # button
        super().__init__(x, y, width, height, elevation, text, button_type)
        self.btn_img = img

        # definition
        self.number = str(number) + '. '
        self.number_surface = DEF_FONT.render(self.number, True, BLACK)
        self.word_used = word_used
        self.words_dict = words_dict
        self.definitions = words_dict.get(self.word_used)
        self.current_def = 0
        self.max_def = len(self.definitions) - 1
        self.definition = self.definitions[self.current_def]
        self.part1 = ''
        self.part2 = ''
        self.part3 = ''
        self.def_surface = DEF_FONT.render(self.definition, True, BLACK)
        self.height = 50
        self.width = 400
        self.pos_y = self.rect.topright[1]
        self.pos_x = self.rect.x + 35
        self.def_rect = pg.Rect(self.pos_x, self.pos_y, self.width, self.height)

    def draw(self):
        super().draw()
        SCREEN.blit(self.btn_img, (self.rect.x + 4, self.rect.y + 4))

    def draw_def(self):
        self.def_surface = DEF_FONT.render(self.part1, True, BLACK)
        SCREEN.blit(self.def_surface, (self.pos_x + 2, self.pos_y + 2))
        self.def_surface = DEF_FONT.render(self.part2, True, BLACK)
        SCREEN.blit(self.def_surface, (self.pos_x + 2, self.pos_y + 15))
        self.def_surface = DEF_FONT.render(self.part3, True, BLACK)
        SCREEN.blit(self.def_surface, (self.pos_x + 2, self.pos_y + 27))

    def wrap_def(self):
        i = 0
        text_width = self.def_rect.left
        if DEF_FONT.size(f'{self.definition}')[0] < self.width:
            return self.definition
        else:
            for letter in self.definition:
                font_width = DEF_FONT.size(f'{letter}')[0]
                text_width += font_width
                if text_width >= self.def_rect.right:
                    space = self.definition.rfind(" ", 0, i)
                    part = self.definition[:space]
                    self.definition = self.definition[space + 1:]
                    return part
                i += 1

    def calc_def(self):
        time.sleep(0.1)
        if DEF_FONT.size(f'{self.definition}')[0] >= self.width*3:
            self.next_definition()
            self.calc_def()
        elif DEF_FONT.size(f'{self.definition}')[0] > self.width*2:
            self.part1 = self.wrap_def()
            self.part1 = self.number + self.part1
            self.part2 = self.wrap_def()
            self.part3 = self.wrap_def()
        elif DEF_FONT.size(f'{self.definition}')[0] > self.width:
            self.part1 = self.wrap_def()
            self.part1 = self.number + self.part1
            self.part2 = self.wrap_def()
            self.part3 = ''
        else:
            self.part1 = self.wrap_def()
            self.part1 = self.number + self.part1
            self.part2 = ''
            self.part3 = ''

    def next_definition(self):
        if self.current_def == self.max_def:
            self.current_def = 0
            self.definition = self.definitions[self.current_def]
        else:
            self.current_def += 1
            self.definition = self.definitions[self.current_def]

    def button_action(self):
        super().button_action()
        if self.button_type == 4:
            self.next_definition()
            self.calc_def()
            update_game_state()

class Box:
    def __init__(self, x, y, size, row, column, text='', is_dead=False):
        self.rect = pg.Rect(x, y, size, size)
        self.text = text
        self.secret_text = ''
        self.color = WHITE
        self.border_color = BLACK
        self.txt_surface = FONT.render(self.text, True, BLACK)
        self.number = ''
        self.arrow_vertical = ''
        self.arrow_horizontal = ''
        self.arrow_surface_vertical = ARROW_FONT.render(self.arrow_vertical, True, BLACK)
        self.arrow_surface_horizontal = ARROW_FONT.render(self.arrow_horizontal, True, BLACK)
        self.number_surface = NUMBER_FONT.render(self.number, True, BLACK)
        self.active = False
        self.final = False
        self.is_dead = is_dead
        self.row = row
        self.column = column

    def handle_event(self, event):
        if event.type == pg.MOUSEBUTTONDOWN and event.button == 3:
            if self.rect.collidepoint(event.pos):
                if self.is_dead is False:
                    self.is_dead = True
                else:
                    self.is_dead = False
        if self.is_dead is not True:
            if event.type == pg.MOUSEBUTTONDOWN and event.button == 1:
                if self.rect.collidepoint(event.pos):
                    self.active = not self.active
                else:
                    self.active = False
                if self.final:
                    self.color = GOLD
                if not self.active and not self.final:
                    self.color = WHITE
                if self.active:
                    self.color = BLUE

            if event.type == pg.KEYDOWN:
                not_active = [pg.K_RALT, pg.K_RIGHT, pg.K_LEFT, pg.K_DOWN, pg.K_BACKSPACE, pg.K_RETURN,
                              pg.K_UP, pg.K_LALT, pg.K_LCTRL, pg.K_RCTRL, pg.K_RSHIFT, pg.K_LSHIFT, pg.K_SPACE]
                if self.active:
                    # commented code below is for debugging purposes only
                    # if event.key == pg.K_RIGHT:
                    #     length = random.randint(3, 10)
                    #     word = get_word_from_letter(self.row, self.column, length)
                    #     if is_empty(input_boxes, self.row, self.column, word, False):
                    #         place_word(input_boxes, self.row, self.column, word, False)
                    # elif event.key == pg.K_DOWN:
                    #     length = random.randint(3, 10)
                    #     word = get_word_from_letter(self.row, self.column, length)
                    #     if is_empty(input_boxes, self.row, self.column, word, True):
                    #         place_word(input_boxes, self.row, self.column, word, True)
                    # elif event.key == pg.K_UP:
                    #     print(is_empty_backwards(input_boxes, self.row, self.column, True))
                    # elif event.key == pg.K_LEFT:
                    #     print(is_empty_backwards(input_boxes, self.row, self.column, False))
                    if event.key not in not_active and len(self.text) <= 1:
                        self.text = event.unicode
                        self.active = False
                        self.text = self.text.upper()
                        self.color = GOLD if self.final else WHITE
                    elif event.key == pg.K_BACKSPACE:
                        self.text = self.text[:-1]

                if self.secret_text == self.text:
                    self.txt_surface = FONT.render(self.text, True, GREEN)
                else:
                    self.txt_surface = FONT.render(self.text, True, RED)

    def draw(self):
        if not self.is_dead:
            pg.draw.rect(SCREEN, self.color, self.rect)
            pg.draw.rect(SCREEN, self.border_color, self.rect, 2)
            SCREEN.blit(self.txt_surface, (self.rect.x + 11, self.rect.y + 10))
            SCREEN.blit(self.number_surface, (self.rect.x + 2, self.rect.y + 2))
            SCREEN.blit(self.arrow_surface_vertical, (self.rect.x + 4, self.rect.y + 14))
            SCREEN.blit(self.arrow_surface_horizontal, (self.rect.x + 16, self.rect.y + 2))
        else:
            pg.draw.rect(SCREEN, BLACK, self.rect)

    def add_text(self, text):
        self.secret_text = text

    def reveal_text(self):
        self.text = self.secret_text
        self.txt_surface = FONT.render(self.text, True, BLACK)
        self.draw()

    def add_number(self, number, is_vertical):
        self.number = number
        self.number_surface = NUMBER_FONT.render(self.number, True, BLACK)
        if is_vertical:
            self.arrow_surface_vertical = ARROW_FONT.render('\u25BC', True, BLACK)
        else:
            self.arrow_surface_horizontal = ARROW_FONT.render('\u27A4', True, BLACK)

input_boxes = []
def draw_grid(rows, cols):
    x = 15
    y = 15
    for row in range(rows):
        column = []
        for col in range(cols):
            column.append(Box(x, y, block_size, row, col))
            x += 39
        input_boxes.append(column)
        x = 15
        y += 39

def place_word(array, row, col, word, is_vertical):
    global horizontal_number
    global vertical_number
    if word is not None:
        word = word.upper()
        i_count = 0
        if is_vertical is False:
            array[row][col].add_number(str(horizontal_number), False)
            horizontal_number += 1
            for i in range(len(word)):
                array[row][col + i].add_text(word[i])
                i_count += 1
            array[row][col + i_count].is_dead = True

        else:
            array[row][col].add_number(str(vertical_number), True)
            vertical_number += 1
            for i in range(len(word)):
                array[row + i][col].add_text(word[i])
                i_count += 1
            array[row + i_count][col].is_dead = True
    if word is None:
        print('NoneObject passed')

def is_empty_simple(array, row, col, word, is_vertical: bool):
    if word is not None:
        length = len(word) + 1
        if not is_vertical and col + length < len(array[row]):
            return True

        if is_vertical and row + length < len(array):
            return True

        else:
            return False

def is_empty(array, row, col, word, is_vertical: bool):
    if word is not None:
        length = len(word)
        empty_boxes = 0
        if not is_vertical and col + length + 1 > len(array[row]):
            return False

        if is_vertical and row + length + 1 > len(array):
            return False

        else:
            if is_vertical:
                for i in range(length):
                    x = True if array[row + 1][col].secret_text == '' else False
                    y = True if array[row + 1][col].is_dead is False else False
                    z = True if array[row + 1][col + 1].secret_text == '' else False
                    v = True if array[row + 1][col - 1].secret_text == '' else False
                    temp = [x, y, z, v]
                    if all(temp):
                        empty_boxes += 1
                        row += 1
                        if empty_boxes == length:
                            return True
                    else:
                        return False
            if not is_vertical:
                for i in range(length):
                    x = True if array[row][col + 1].secret_text == '' else False
                    y = True if array[row][col + 1].is_dead is False else False
                    z = True if array[row + 1][col + 1].secret_text == '' else False
                    v = True if array[row - 1][col + 1].secret_text == '' else False
                    temp = [x, y, z, v]
                    if all(temp):
                        empty_boxes += 1
                        col += 1
                        if empty_boxes == length:
                            return True
                    else:
                        return False

def is_empty_backwards(array, row, col, is_vertical: bool):
    length = 0
    counted = False
    if is_vertical:
        while not counted:
            if row == 0:
                return length
            try:
                x = True if array[row - 1][col].secret_text == '' else False
                y = True if array[row - 1][col].is_dead is False else False
                z = True if array[row - 1][col + 1].secret_text == '' else False
                v = True if array[row - 1][col - 1].secret_text == '' else False
                temp = [x, y, z, v]
                if all(temp):
                    length += 1
                    row -= 1
                else:
                    break
            except IndexError:
                break
        return length
    if not is_vertical:
        while not counted:
            if col == 0:
                return length
            try:
                x = True if array[row][col - 1].secret_text == '' else False
                y = True if array[row][col - 1].is_dead is False else False
                z = True if array[row + 1][col - 1].secret_text == '' else False
                v = True if array[row - 1][col - 1].secret_text == '' else False
                temp = [x, y, z, v]
                if all(temp):
                    length += 1
                    col -= 1
                else:
                    break
            except IndexError:
                break
        return length

def get_word(array, length):
    array_sorted = sorted(array, key=len)
    found = False
    while found is not True:
        word = random.choice(array_sorted)
        if len(word) == length:
            return word

def get_word_special_chars(letter):
    if letter == 'ą':
        return random.choice(Words.words_a_pl)
    if letter == 'ę':
        return random.choice(Words.words_e_pl)
    if letter == 'ń':
        return random.choice(Words.words_n_pl)
    if letter == 'ć':
        return random.choice(Words.words_c_pl)
    if letter == 'ó':
        return random.choice(Words.words_o_pl)
    if letter == 'ł':
        return random.choice(Words.words_l_pl)
    if letter == 'ś':
        return random.choice(Words.words_s_pl)
    if letter == 'ź':
        return random.choice(Words.words_x_pl)
    if letter == 'ż':
        return random.choice(Words.words_z_pl)

def get_word_from_letter(row, column, length):
    letter = input_boxes[row][column].secret_text
    global special_chars
    if letter in special_chars:
        return False
    elif letter == '':
        return None
    else:
        letter = letter.lower()
        return get_word(eval(f'Words.words_{letter}'), length)

def get_random_word(length):
    word = None
    while word is None:
        letter = random.choice(string.ascii_lowercase)
        if letter not in ['q', 'v', 'x', 'y']:
            word = get_word(eval(f'Words.words_{letter}'), length)
    return word

# function that generates the first type of crossword, it is activated while pressing the first button
def crossword_1():
    global crossword
    clear()
    final_word = get_random_word(18)
    place_word(input_boxes, 1, 10, final_word, True)
    input_boxes[1][10].add_number('', True)
    input_boxes[1][10].arrow_surface_vertical = NUMBER_FONT.render('', True, BLACK)
    for i in range(1, 19):
        input_boxes[i][10].color = GOLD
        input_boxes[i][10].final = True
    row = 1
    col = 10
    for letter_final in final_word:
        word_placed = False
        while word_placed is not True:
            if letter_final not in special_chars:
                word = get_random_word(random.randint(5, 10))
            else:
                word = get_word_special_chars(letter_final)
            for letter in word:
                if letter == letter_final:
                    column = col - int(word.index(letter_final))
                    if is_empty_simple(input_boxes, row, column, word, False) is True and add_definitions(word, False) is True:
                        place_word(input_boxes, row, column, word, False)
                        row += 1
                        word_placed = True
                        break
                    else:
                        continue
                else:
                    continue

    for i in range(len(input_boxes)):
        for box in input_boxes[i]:
            if box.secret_text == '':
                box.is_dead = True
    draw_definitions()
    loading(False)
    crossword = 1
    update_game_state()

# function that generates the second type of crossword, it is activated while pressing the second button
def crossword_2():
    global crossword
    global special_chars
    clear()
    first_placed = False
    word_placed = False
    occupied_boxes = []
    words_horizontal = 0
    words_vertical = 0
    missed_letters = 0
    backwards_words = 0
    backwards_placed = False
    while not first_placed:
        row = random.randint(0, 1)
        col = random.randint(0, 1)
        z = bool(random.getrandbits(1))
        first_word = get_random_word(random.randint(6, 15))
        if add_definitions(first_word, z) is True:
            place_word(input_boxes, row, col, first_word, z)
            occupied_boxes = get_occupied_boxes(row, col, len(first_word), z)
            first_placed = True
            if z is True:
                words_vertical += 1
            else:
                words_horizontal += 1
    start_time = time.time()
    while not word_placed:
        if time.time() - start_time > 120:
            word_placed = True
            backwards_placed = True
        if words_horizontal == 15 and words_vertical == 15:
            word_placed = True
        if missed_letters > 8:
            backwards_placed = not backwards_placed
            while not backwards_placed:
                occupied_boxes_backwards = occupied_boxes
                if backwards_words == 1:
                    backwards_placed = True
                    break

                for box in occupied_boxes_backwards:
                    vert_empty_space = is_empty_backwards(input_boxes, box[0], box[1], True)
                    hor_empty_space = is_empty_backwards(input_boxes, box[0], box[1], False)
                    if vert_empty_space >= 4 or hor_empty_space >= 4:
                        if vert_empty_space > hor_empty_space:
                            if is_empty(input_boxes, box[0], box[1], 'A', True):
                                length = vert_empty_space
                                add_def = True
                            else:
                                continue
                        if hor_empty_space > vert_empty_space:
                            if is_empty(input_boxes, box[0], box[1], 'A', False):
                                length = hor_empty_space
                                add_def = False
                            else:
                                continue

                        word = get_random_word(random.randint(4, length)).upper()
                        if word[-1] == input_boxes[box[0]][box[1]].secret_text and add_definitions(word, add_def):
                            if vert_empty_space > hor_empty_space:
                                place_word(input_boxes, box[0] - len(word) + 1, box[1], word, True)
                                backwards_words += 1

                            else:
                                place_word(input_boxes, box[0], box[1] - len(word) + 1, word, False)
                                backwards_words += 1
                break
            missed_letters = 0
            backwards_words = 0

        else:
            box = random.choice(occupied_boxes)
            if input_boxes[box[0]][box[1]].secret_text in special_chars:
                continue
            else:
                word = get_word_from_letter(box[0], box[1], random.randint(5, 12))
                if is_empty(input_boxes, box[0], box[1], word, False) is True:
                    if add_definitions(word, False) is True:
                        place_word(input_boxes, box[0], box[1], word, False)
                        missed_letters = 0
                        words_horizontal += 1
                        temp = get_occupied_boxes(box[0], box[1], len(word), False)
                        for i in temp:
                            occupied_boxes.append(i)

                elif is_empty(input_boxes, box[0], box[1], word, True) is True:
                    if add_definitions(word, True) is True:
                        place_word(input_boxes, box[0], box[1], word, True)
                        missed_letters = 0
                        words_vertical += 1
                        temp = get_occupied_boxes(box[0], box[1], len(word), True)
                        for i in temp:
                            occupied_boxes.append(i)

                else:
                    missed_letters += 1

    for i in range(len(input_boxes)):
        for box in input_boxes[i]:
            if box.secret_text == '':
                box.is_dead = True
    draw_definitions()
    loading(False)
    crossword = 2
    update_game_state()

def get_occupied_boxes(row, col, length, is_vertical):
    coords = []
    if is_vertical:
        for i in range(1, length):
            coords.append([row + i, col])
        return coords
    if not is_vertical:
        for i in range(1, length):
            coords.append([row, col + i])
        return coords

def clear():
    global input_boxes
    global vertical_number
    global horizontal_number
    global words_used
    global words_used_vertical
    global definitions
    global crossword
    SCREEN.blit(BACKGROUND, (0, 0))
    input_boxes = []
    draw_grid(20, 20)
    vertical_number = 1
    horizontal_number = 1
    words_used = {}
    words_used_vertical = {}
    definitions = []
    crossword = 0

def add_definitions(word, is_vertical):
    value = scrape_definitions(word)
    if not value:
        return False
    else:
        if not is_vertical:
            words_used.update({word: value})
            return True
        else:
            words_used_vertical.update({word: value})
            return True

def draw_headers():
    if crossword == 1:
        horizontal_header = FONT.render('Poziomo:', True, BLACK)
        SCREEN.blit(horizontal_header, (900, 30))
    if crossword == 2:
        horizontal_header = FONT.render('Poziomo:', True, BLACK)
        vertical_header = FONT.render('Pionowo:', True, BLACK)
        SCREEN.blit(horizontal_header, (900, 30))
        SCREEN.blit(vertical_header, (1500, 30))

def draw_definitions():
    x = 900
    y = 70
    vertical_y = 70
    vertical_x = 1350
    spacing = 55
    button_size = 30
    elevation = 2
    number = 1
    number_vertical = 1
    for word in words_used:
        if number > 15:
            Definition(vertical_x, vertical_y, button_size, button_size, elevation, number, word, words_used)
            vertical_y += spacing
            number += 1
        else:
            Definition(x, y, button_size, button_size, elevation, number, word, words_used)
            y += spacing
            number += 1
    for word in words_used_vertical:
        Definition(vertical_x, vertical_y, button_size, button_size, elevation, number_vertical, word, words_used_vertical)
        vertical_y += spacing
        number_vertical += 1
    for d in definitions:
        d.calc_def()
    loading(False)
    update_game_state()
    global show_definitions
    show_definitions = True

def update_game_state():
    SCREEN.blit(BACKGROUND, (0, 0))
    draw_buttons()
    for d in definitions:
        d.draw_def()
        d.draw()
    draw_headers()

button0 = Button(125, 810, 150, 75, 4, 'Crossword #1', 0)
button1 = Button(325, 810, 150, 75, 4, 'Crossword #2', 1)
button2 = Button(525, 810, 150, 75, 4, 'Show answers', 2)
def draw_buttons():
    for b in buttons:
        b.draw()

def loading(play_animation):
    global loaded
    if play_animation:
        loaded = False
    if not play_animation:
        loaded = True

def debug():
    for i in range(len(input_boxes)):
        for box in input_boxes[i]:
            box.reveal_text()

def welcome():
    line_1 = 'Welcome to Crosswords Game!'
    line_2 = 'If you click first or second button, a crossword in polish language '
    line_3 = 'will be generated for you!'
    line_4 = 'As text on each button indicate, there are two types of crosswords:'
    line_5 = 'In the first one, the final word (gold boxes) will be randomly '
    line_6 = 'chosen and your job will be to guess all the horizontal words.'
    line_7 = 'In the second one, there is no final word, just words that well...'
    line_8 = 'cross with each other.'
    line_9 = 'After you generate a crossword, you can click the \'Show answers\''
    line_10 = 'button if you feel like cheating :)'
    line_11 = 'Good luck!'
    lines = []
    line_spacing = 50
    for line_number in range(1, 11):
        lines.append(eval(f'line_{line_number}'))
    for line in lines:
        line_surface = FONT.render(line, True, BLACK)
        SCREEN.blit(line_surface, (850, line_spacing))
        line_spacing += 30

def main():
    clock = pg.time.Clock()
    draw_grid(20, 20)
    done = False
    welcome()

    while not done:
        if loaded is False:
            update_game_state()
            moving_sprites.draw(SCREEN)
            moving_sprites.update(0.5)
            loading_text = LOADING_FONT.render(loading_icon.text, True, BLACK)
            SCREEN.blit(loading_text, loading_icon.text_pos)

        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            for i in range(len(input_boxes)):
                for box in input_boxes[i]:
                    box.handle_event(event)
            for b in buttons:
                b.button_event()
                b.draw()

        if show_definitions:
            for d in definitions:
                d.draw()
                d.button_event()

        for i in range(len(input_boxes)):
            for box in input_boxes[i]:
                box.draw()

        pg.display.flip()
        clock.tick(30)

if __name__ == '__main__':
    main()
    pg.quit()


import re
import webob

from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova import compute
from nova import exception
from nova.openstack.common import log as logging

LOG = logging.getLogger(__name__)
authorize = extensions.extension_authorizer('compute', 'console_output')

class ConsoleOutputController(wsgi.Controller):
    def __init__(self, *args, **kwargs):
        super(ConsoleOutputController, self).__init__(*args, **kwargs)
        self.compute_api = compute.API()

    @wsgi.action('os-getConsoleOutput')
    def get_console_output(self, req, id, body):
        """Get text console output."""
        context = req.environ['nova.context']
        authorize(context)

        try:
            instance = self.compute_api.get(context, id)
        except exception.NotFound:
            raise webob.exc.HTTPNotFound(_('Instance not found'))

        try:
            length = body['os-getConsoleOutput'].get('length')
        except (TypeError, KeyError):
            raise webob.exc.HTTPBadRequest(_('os-getConsoleOutput malformed '
                                             'or missing from request body'))

        if length is not None:
            try:
                int(length)
            except ValueError:
                raise webob.exc.HTTPBadRequest(_('Length in request body must '
                                                 'be an integer value'))

        try:
            output = self.compute_api.get_console_output(context,
                                                         instance,
                                                         length)
        except exception.NotFound:
            raise webob.exc.HTTPNotFound(_('Unable to get console'))
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(explanation=e.format_message())

        # XML output is not correctly escaped, so remove invalid characters
        remove_re = re.compile('[\x00-\x08\x0B-\x0C\x0E-\x1F-\x0D]')
        output = remove_re.sub('', output)

        return {'output': output}

class Console_output(extensions.ExtensionDescriptor):
    """Console log output support, with tailing ability."""

    name = "ConsoleOutput"
    alias = "os-console-output"
    namespace = ("http://docs.openstack.org/compute/ext/"
                 "os-console-output/api/v2")
    updated = "2011-12-08T00:00:00+00:00"

    def get_controller_extensions(self):
        controller = ConsoleOutputController()
        extension = extensions.ControllerExtension(self, 'servers', controller)
        return [extension]


#!/usr/bin/python

import os
import unittest

from testutils import setup_test_env
setup_test_env()
from softwarecenter.db.database import StoreDatabase
from softwarecenter.db.pkginfo import get_pkg_info
from softwarecenter.db.update import rebuild_database

class TestMime(unittest.TestCase):
    """ tests the mime releated stuff """

    def setUp(self):
        self.cache = get_pkg_info()
        self.cache.open()

    def test_most_popular_applications_for_mimetype(self):
        pathname = "../data/xapian"
        if not os.listdir(pathname):
            rebuild_database(pathname)
        db = StoreDatabase(pathname, self.cache)
        db.open()
        # all
        result = db.get_most_popular_applications_for_mimetype("text/html", only_uninstalled=False, num=5)
        self.assertEqual(len(result), 5)
        # only_uninstaleld
        result = db.get_most_popular_applications_for_mimetype("text/html", only_uninstalled=True, num=2)
        self.assertEqual(len(result), 2)

if __name__ == "__main__":
    import logging
    logging.basicConfig(level=logging.DEBUG)
    unittest.main()


import matplotlib.pyplot as plt
import torch

from data import *
from optim import *

def make_results_folder(optim):
    os.makedirs(f'results_{optim}', exist_ok=True)
# plt.rcParams.update({
#     "text.usetex": True},
#     "font.family": "serif",
#     "font.serif": ["ComputerModern"])

plt.rcParams['figure.figsize'] = (12,9)

plt.rc('axes', facecolor='whitesmoke', edgecolor='none',
    axisbelow=True, grid=True)
plt.rc('grid', color='w', linestyle='solid')
plt.rc('lines', linewidth=2)

plt.rcParams.update({'font.size': 20})

""" Plot losses during traning """
def train_plot_total_losses(total_losses, dloss, pdeloss, pde_w, optim):
    plt.rcParams.update({'figure.max_open_warning': 0})
    plt.figure(dpi = 200)
    total_losses = torch.tensor(total_losses)
    total_losses = total_losses.cpu()
    plt.semilogy(total_losses, label=f'Total loss = data_loss + {str(pde_w)} * pde_loss', linestyle='dashed', zorder=100)

    dloss = torch.tensor(dloss)
    dloss = dloss.cpu()
    plt.semilogy(dloss, label='Data loss')

    if len(pdeloss) >= 1:
        pdeloss = torch.tensor(pdeloss)
        pdeloss = pdeloss.cpu()
        plt.semilogy(pdeloss, label='PDE loss')

    plt.title('Train losses')
    plt.ylabel("Loss", fontsize=20 , labelpad=10)
    plt.xlabel("Iteration", fontsize=20 , labelpad=10)
    plt.legend(framealpha=0.9, facecolor=(1, 1, 1, 1))
    plt.tight_layout()
    plt.savefig(f'results_{optim}/train_loss_plot_{int(pde_w * 100)}.png')
    plt.clf()

def test_plot_total_losses(total_losses, pde_w, optim):
    plt.rcParams.update({'figure.max_open_warning': 0})
    plt.figure(dpi = 200)
    total_losses = torch.tensor(total_losses)
    total_losses = total_losses.cpu()
    plt.semilogy(total_losses, label='total loss')
    plt.title('Total loss on the test data', pad=15)
    plt.ylabel("Loss", fontsize=20 , labelpad=10)
    plt.xlabel("Iteration", fontsize=20 , labelpad=10)
    plt.legend(framealpha=0.9, facecolor=(1, 1, 1, 1))
    plt.tight_layout()
    plt.savefig(f'results_{optim}/test_loss_plot_{int(pde_w * 100)}.png')
    plt.clf()

def train_test_total_losses(train_total_losses, test_total_losses, pde_w, optim):
    plt.rcParams.update({'figure.max_open_warning': 0})
    plt.figure(dpi = 200)
    train_total_losses = torch.tensor(train_total_losses)
    test_total_losses = torch.tensor(test_total_losses)

    plt.semilogy(test_total_losses, label='test')
    plt.semilogy(train_total_losses, label='train')
    plt.title('Test/train loss', pad=15)
    plt.ylabel("Loss", fontsize=20 , labelpad=10)
    plt.xlabel("Iteration", fontsize=20 , labelpad=10)
    plt.legend(framealpha=0.9, facecolor=(1, 1, 1, 1))
    plt.savefig(f'results_{optim}/test_train_losses_{int(pde_w * 100)}.png')
    plt.tight_layout()
    plt.clf()

'''Plot D during training'''
def D_plot(D_during_train, pde_w, optim):
    plt.figure(dpi=200)
    plt.title("PINN's diffusion coefficient estimate against iterations", pad=15)
    plt.semilogy(D_during_train, label='The diffusion coefficient')
    plt.ylabel("Estimated diffusion coefficient", fontsize=20 , labelpad=10)
    plt.xlabel("Iterations", fontsize=20 , labelpad=10)
    plt.legend(framealpha=0.9, facecolor=(1, 1, 1, 1))
    plt.tight_layout()
    plt.savefig(f'results_{optim}/D_plot_{int(pde_w * 100)}.png')
    plt.clf()

""" Plot of the traning images """
def train_images():
    os.makedirs(f'train_images', exist_ok=True)
    dataset = "brain2dsmooth10"
    path_to_data, roi = import_data(dataset, mask=True)
    images = load_images(path_to_data, dataset)
    coordinate_grid = make_coordinate_grid(images)
    datadict, true_time_keys = get_input_output_pairs(coordinate_grid, mask=roi, images=images)
    train_time_keys = get_train_time_keys()

    for i,t in enumerate(train_time_keys):
        xyt = torch.tensor(datadict[t][0]).float()
        xyt_cpu = xyt.cpu()
        plt.figure(dpi=200)
        plt.plot(xyt_cpu[..., 0], xyt_cpu[..., 1], marker=".", linewidth=0, markersize=0.2, color="k")
        plt.scatter(xyt_cpu[..., 0], xyt_cpu[..., 1], c=datadict[t][1], vmin=-1., vmax=1., linewidths=2.5)
        plt.xlabel("x", fontsize=20, labelpad=10)
        plt.ylabel("y", fontsize=20, labelpad=10)
        plt.title(f'Synthetic data at {true_time_keys[i]} hours', pad=15)
        plt.colorbar()
        plt.tight_layout()
        plt.savefig(f'train_images/{str(int(true_time_keys[i]))}_true.png')
        plt.clf()

""" Comparison plot of the test prediction and the test data """
def test_data_NN_prediction(NN, pde_w, optim):
    os.makedirs(f'results_{optim}/test_data_NN_prediction', exist_ok=True)

    dataset = "brain2dsmooth10"
    path_to_data, roi = import_data(dataset, mask=True)
    images = load_images(path_to_data, dataset)
    coordinate_grid = make_coordinate_grid(images)
    datadict, true_time_keys = get_input_output_pairs(coordinate_grid, mask=roi, images=images)

    test_time_keys = get_test_time_keys()
    fig, axs = plt.subplots(2, 2, figsize=[12,9], sharex=True)

    xyt1  = torch.tensor(datadict[test_time_keys[0]][0]).float()
    xyt2  = torch.tensor(datadict[test_time_keys[1]][0]).float()

    xyt1[:, -1] = float(test_time_keys[0])
    xyt2[:, -1] = float(test_time_keys[1])

    prediction1 = NN(xyt1)
    prediction2 = NN(xyt2)

    xyt1 = xyt1.cpu()
    xyt2 = xyt2.cpu()

    prediction1 = prediction1.cpu()
    prediction2 = prediction2.cpu()

    img1 = axs[0, 0].plot(xyt1[:, 0], xyt1[:, 1], marker=".", linewidth=0, markersize=0.1, color="k")
    img1 = axs[0, 0].scatter(xyt1[:, 0], xyt1[:, 1], c=np.squeeze(prediction1.detach().numpy(),1), vmin=-1., vmax=1.)
    axs[0, 0].set_title(f"PINN prediction at time = {true_time_keys[7]} hours", fontsize=14, pad=7)

    img2 = axs[1, 0].plot(xyt2[:, 0], xyt2[:, 1], marker=".", linewidth=0, markersize=0.1, color="k")
    img2 = axs[1, 0].scatter(xyt2[:, 0], xyt2[:, 1], c=np.squeeze(prediction2.detach().numpy(),1), vmin=-1., vmax=1.)
    axs[1, 0].set_title(f"PINN prediction at time = {true_time_keys[14]} hours", fontsize=14, pad=7)

    img3 = axs[0, 1].plot(xyt1[:, 0], xyt1[:, 1], marker=".", linewidth=0, markersize=0.1, color="k")
    img3 = axs[0, 1].scatter(xyt1[:, 0], xyt1[:, 1], c=datadict[test_time_keys[0]][1], vmin=-1., vmax=1.)
    axs[0, 1].set_title(f"Data at time = {true_time_keys[7]} hours", fontsize=14, pad=7)

    img4 = axs[1, 1].plot(xyt2[:, 0], xyt2[:, 1], marker=".", linewidth=0, markersize=0.1, color="k")
    img4 = axs[1, 1].scatter(xyt2[:, 0], xyt2[:, 1], c=datadict[test_time_keys[1]][1], vmin=-1., vmax=1.)
    axs[1, 1].set_title(f"Data at time = {true_time_keys[14]} hours", fontsize=14, pad=7)

    fig.suptitle('Test and data images', y=0.98)

    cbar = fig.colorbar(img4, ax=axs, orientation='vertical', fraction=0.046, pad=0.1)
    plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)
    plt.savefig(f'results_{optim}/test_data_NN_prediction/test_data_NN_prediction_{int(pde_w * 100)}.png')
    plt.clf()

def bvto(losses_train_ANN, losses_test_ANN, losses_train_PINN, losses_test_PINN, pde_w, optim):

    losses_train_ANN = torch.tensor(losses_train_ANN)
    losses_test_ANN = torch.tensor(losses_test_ANN)
    losses_train_ANN = torch.tensor(losses_train_PINN)
    losses_test_ANN = torch.tensor(losses_test_PINN)

    fig, ax = plt.subplots(2, 1, figsize=[12,9], sharex=True, sharey=True)
    fig.suptitle('Train/test loss - ANN vs PINN', y=0.98)

    # Plot something in the first subplot
    ax[0].plot(losses_train_ANN, label='ANN train loss')
    ax[0].plot(losses_test_ANN, label='ANN test loss')
    ax[0].set_yscale('log')
    ax[0].set_ylabel('Loss', fontsize=20 ,labelpad=10)
    ax[0].set_title('ANN', pad=5)
    ax[0].legend(framealpha=0.9, facecolor=(1, 1, 1, 1))

    # Plot something in the first subplot
    ax[1].plot(losses_train_PINN, label='PINN train loss')
    ax[1].plot(losses_test_PINN, label='PINN test loss')
    ax[1].set_yscale('log')
    ax[1].set_ylabel('Loss', fontsize=20 , labelpad=10)
    ax[1].set_title('PINN', pad=5)
    ax[1].set_xlabel('Iterations', fontsize=20 , labelpad=10)
    ax[1].legend(framealpha=0.9, facecolor=(1, 1, 1, 1))

    plt.savefig(f'results_{optim}/bvto_{int(pde_w * 100)}.png')
    plt.clf()

Project 3 - Inverse Physics Informed Neural Network Problem/src/plot.py


import requests

from bot.keyboards import get_menu_keyboard, get_categories_list_keyboard, get_category_detail_keyboard, \
    get_product_detail_keyboard, get_cart_keyboard
from bot.utils import save_user

def start(update, context):
    user = update.effective_user
    save_user(user)
    update.message.reply_text('Menu', reply_markup=get_menu_keyboard())

def categories_list(update, context):
    query = update.callback_query

    data = requests.get('http://127.0.0.1:8000/categories/').json()

    text = ''
    for category in data:
        text += f'{category["id"]}. {category["title"]}\n'

    query.edit_message_text(text=text, reply_markup=get_categories_list_keyboard(data))

def category_detail(update, context):
    query = update.callback_query
    pk = query.data.split('_')[1]

    data = requests.get(f'http://127.0.0.1:8000/categories/{pk}/').json()

    if not data:
        query.edit_message_text(text='No products yet',
                                reply_markup=get_category_detail_keyboard())
        return

    text = ''
    for product in data:
        text += f'{product["id"]}. {product["title"]}\n'

    query.edit_message_text(text=text, reply_markup=get_category_detail_keyboard(data))

def product_detail(update, context):
    query = update.callback_query
    pk = query.data.split('_')[1]

    product = requests.get(f'http://127.0.0.1:8000/products/{pk}').json()

    text = f'Title: {product["title"]}\n' \
           f'Price: {product["price"]}\n' \
           f'Description: {product["description"]}\n'

    context.bot.send_photo(
        chat_id=query.message.chat.id,
        photo=requests.get(product["image"]).content,
        caption=text,
        reply_markup=get_product_detail_keyboard(product, context)
    )
    context.bot.delete_message(chat_id=query.message.chat.id,
                               message_id=query.message.message_id)

def search(update, context):
    pass

def back(update, context):
    query = update.callback_query
    level = query.data.split('_')[1]

    if level == 'menu':
        query.message.reply_text(text='Menu', reply_markup=get_menu_keyboard())
    elif level == 'categories':
        data = requests.get('http://127.0.0.1:8000/categories/').json()

        text = ''
        for category in data:
            text += f'{category["id"]}. {category["title"]}\n'

        query.message.reply_text(text=text, reply_markup=get_categories_list_keyboard(data))

    if level == 'category':
        pk = query.data.split('_')[2]

        data = requests.get(f'http://127.0.0.1:8000/categories/{pk}/').json()

        if not data:
            query.message.reply_text(text='No products yet',
                                     reply_markup=get_category_detail_keyboard())
            return

        text = ''
        for product in data:
            text += f'{product["id"]}. {product["title"]}\n'

        query.message.reply_text(text=text, reply_markup=get_category_detail_keyboard(data))

    context.bot.delete_message(chat_id=query.message.chat.id,
                               message_id=query.message.message_id)

def update_cart(update, context):
    query = update.callback_query
    pk = query.data.split('_')[1]

    cart = context.user_data.get('cart', [])

    if pk in cart:
        cart.remove(pk)
        text = 'Removed from cart'
    else:
        cart.append(pk)
        text = 'Added to cart'

    context.user_data['cart'] = cart
    query.answer(text=text)

def cart_list(update, context):
    cart = context.user_data.get('cart', [])
    query = update.callback_query

    if not cart:
        query.answer(text='Cart in empty')
    else:
        data = requests.get(f'http://127.0.0.1:8000/cart-data/?products={cart}').json()

        text = ''
        for product in data:
            text += f'{product["id"]}. {product["title"]}\n'

        query.message.reply_text(text=text, reply_markup=get_cart_keyboard())
        context.bot.delete_message(chat_id=query.message.chat.id,
                                   message_id=query.message.message_id)

def checkout(update, context):
    query = update.callback_query
    user_id = update.effective_user.id
    cart = context.user_data['cart']

    requests.post(
        'http://127.0.0.1:8000/orders/create/',
        data={
            'user_id': user_id,
            'products': cart
        }
    )

    query.answer('Order is created')
    context.user_data['cart'] = []

    query.edit_message_text(text='Menu', reply_markup=get_menu_keyboard())


from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

import time

class MyGPS(GridLayout):
    def __init__(self, **kwargs):
        super(MyGPS, self).__init__(**kwargs)
        self.set_values()

    def set_values(self, **kwargs):
        latitude, longitude, location_name, accuracy = self.getLocation()
        #latitude = "49.58311130"
        #longitude = "11.00884270"
        #location_name = "91052, Erlangen, Bavaria, Rathenau, ... , und mehr"
        #accuracy = "15m (accurate)"
        #print(f'There are {len(self.ids.items())} id(s)')
        self.ids.Latitude.text = latitude
        self.ids.Longitude.text = longitude
        self.ids.Location.text = location_name
        self.ids.Accuracy.text = accuracy

    def getLocation(self):
        chrome_options = Options()
        chrome_options.add_argument("--use-fake-ui-for-media-stream")
        timeout = 20
        driver = webdriver.Chrome()
        driver.get("https://mycurrentlocation.net/")
        wait = WebDriverWait(driver, timeout)
        time.sleep(3)
        # Click the "Detect My Location" button
        driver.find_elements(By.XPATH, '/html/body/div[2]/div[4]/div/div[1]/div/div[1]/div/button')[0].click()
        # Click the "Alert Pop-Up" with the text "Yeeay location found!"
        WebDriverWait(driver, 10).until(EC.alert_is_present())
        driver.switch_to.alert.accept()

        longitude = driver.find_elements(By.ID, 'detail-longitude')
        longitude = [x.text for x in longitude]
        longitude = str(longitude[0])

        latitude = driver.find_elements(By.ID, 'detail-latitude')
        latitude = [x.text for x in latitude]
        latitude = str(latitude[0])

        location_name = driver.find_elements(By.ID, 'detail-location-name')
        location_name = [x.text for x in location_name]
        location_name = str(location_name[0])

        accuracy = driver.find_elements(By.ID, 'detail-accuracy')
        accuracy = [x.text for x in accuracy]
        accuracy = str(accuracy[0])

        driver.quit()

        return (latitude, longitude, location_name, accuracy)

class MyLocation(App):
    def build(self):

        return MyGPS()

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


from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit import *

from qiskit import execute, BasicAer, Aer

qubit = QuantumRegister(1, 'qubit')
circuit = QuantumCircuit(qubit)

circuit.x(qubit)
circuit.barrier(qubit)
circuit.id(qubit)
circuit.barrier(qubit)
circuit.rx(3.1416, qubit)

backend = Aer.get_backend('statevector_simulator')
job = execute(circuit, backend)
result = job.result()
outputstate = result.get_statevector(circuit, decimals=3)
print(outputstate)


import torch
import torch.nn as nn

class RNN(nn.Module):
    def __init__(self, input_size, hidden_size):
        """
        Base network class.

        Arguments:
        ----------
        input_size : `int`
            The number of expected features in the input for GRU.
        hidden_size : `int`
            The number of features in the hidden state of GRU (default: 256).
        """
        super(RNN, self).__init__()

        self._hidden_size = hidden_size

        # define GRU
        self.gru = nn.GRU(input_size, hidden_size)

        # initialise parameters
        for name, param in self.gru.named_parameters():
            if 'bias' in name:
                nn.init.constant_(param, 0)
            elif 'weight' in name:
                nn.init.orthogonal_(param)

    def forward(self, x, hxs, masks):
        if x.size(0) == hxs.size(0):
            x, hxs = self.gru(x.unsqueeze(0), (hxs * masks).unsqueeze(0))
            x = x.squeeze(0)
            hxs = hxs.squeeze(0)
        else:
            # x is a (T, N, -1) tensor that has been flattened to (T * N, -1)
            N = hxs.size(0)
            T = int(x.size(0) / N)

            # unflatten
            x = x.view(T, N, x.size(1))

            # Same deal with masks
            masks = masks.view(T, N)

            # Let's figure out which steps in the sequence have a zero for any agent
            # We will always assume t=0 has a zero in it as that makes the logic cleaner
            has_zeros = ((masks[1:] == 0.0)
                         .any(dim=-1)
                         .nonzero()
                         .squeeze()
                         .cpu())

            # +1 to correct the masks[1:]
            if has_zeros.dim() == 0:
                # Deal with scalar
                has_zeros = [has_zeros.item() + 1]
            else:
                has_zeros = (has_zeros + 1).numpy().tolist()

            # add t=0 and t=T to the list
            has_zeros = [0] + has_zeros + [T]

            hxs = hxs.unsqueeze(0)
            outputs = list()
            for i in range(len(has_zeros) - 1):
                # We can now process steps that don't have any zeros in masks together!
                # This is much faster
                start_idx = has_zeros[i]
                end_idx = has_zeros[i + 1]

                rnn_scores, hxs = self.gru(
                    x[start_idx:end_idx],
                    hxs * masks[start_idx].view(1, -1, 1))

                outputs.append(rnn_scores)

            # assert len(outputs) == T
            # x is a (T, N, -1) tensor
            x = torch.cat(outputs, dim=0)
            # flatten
            x = x.view(T * N, -1)
            hxs = hxs.squeeze(0)

        return x, hxs


from pyramid_sqlalchemy import Session
from sqlalchemy import engine_from_config, event, DDL
from sqlalchemy.orm import configure_mappers

# import or define all models here to ensure they are attached to the
# Base.metadata prior to any initialization routines
from .mymodel import Product, City, User, Price # flake8: noqa

# run configure_mappers after defining all of the models to ensure
# all relationships can be setup
configure_mappers()

def get_engine(settings, prefix='sqlalchemy.'):
    return engine_from_config(settings, prefix)

def includeme(config):
    """
    Initialize the model for a Pyramid app.

    Activate this setup using ``config.include('multitenant_rls.models')``.

    """
    settings = config.get_settings()
    engine = engine_from_config(settings)
    Session.configure(bind=engine)

    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')

enable_rls_str = "alter table %(table)s enable row level security"
"""Activate RLS for the given table"""

tenancy_policy_str = "create policy %(table)s_tenancy_policy on %(table)s for all " \
                     "using (city_id=current_setting('my.city_id')::integer) " \
                     "with check (city_id=current_setting('my.city_id')::integer)"
"""Create the city constraint policy for the given table"""

event.listen(Price.__table__, 'after_create', DDL(enable_rls_str))
event.listen(Price.__table__, 'after_create', DDL(tenancy_policy_str))
"""In case you want to apply the policy to more than one table, the keyword Table can be used instead naming each table
separately."""