#   Copyright (c) 2016, Xilinx, Inc.
#   All rights reserved.
#
#   Redistribution and use in source and binary forms, with or without
#   modification, are permitted provided that the following conditions are met:
#
#   1.  Redistributions of source code must retain the above copyright notice,
#       this list of conditions and the following disclaimer.
#
#   2.  Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#
#   3.  Neither the name of the copyright holder nor the names of its
#       contributors may be used to endorse or promote products derived from
#       this software without specific prior written permission.
#
#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#   OR BUSINESS INTERRUPTION). HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import re
from copy import deepcopy
from collections import OrderedDict
from pyeda.inter import exprvar
from pyeda.inter import expr2truthtable
from pynq import Register
from pynq import MMIO
from .constants import *

__author__ = "Parimal Patel"
__copyright__ = "Copyright 2018, Xilinx"
__email__ = "pynq_support@xilinx.com"

class BooleanGenerator:
    """Class for the Boolean generator.

    This class can implement any combinational function. Since
    each LUT5 takes 5 inputs, the basic function that users can implement is
    5-input, 1-output boolean function. However, by concatenating multiple
    LUT5 together, users can implement complex boolean functions.

    There are 16 5-LUTs, so users can implement at most 16 basic boolean
    functions at a specific time.

    Attributes
    ----------
    expressions : list/dict
        The boolean expressions, each expression being a string.
    input_pins : list
        A list of input pins used by the generator.
    output_pins : list
        A list of output pins used by the generator.

    """

    def __init__(self, intf_spec_name='BG_SPECIFICATION'):
        """Return a new Boolean generator object.

        The available input pins are data pins DIN0 - DIN15,

        The available output pins can be DOUT0-DOUT15.

        The input boolean expression can be of the following format:
        `DOUT4 = DIN0 & DIN1 | DIN2`.

        If no input boolean expression is specified, the default function
        implemented is `DIN0 & DIN1 & DIN2 & DIN3`.

        Parameters
        ----------
        No parameters are required

        """
        if type(intf_spec_name) is str:
            self.intf_spec = eval(intf_spec_name)
        elif type(intf_spec_name) is dict:
            self.intf_spec = intf_spec_name
        else:
            raise ValueError("Interface specification has to be str or dict.")

        self.bg_mmio = MMIO(0x43c00000,(4*64))
        self.bg_sel_mmio = MMIO(0x41200000)
		# Parameters to be cleared at reset
        self.expressions = dict()
        self.output_pins = list()
        self.input_pins = list()

    def setup(self, expressions):
        """Configure CFGLUTs with new boolean expression.

        Parameters
        ----------
        expressions : list/dict
            The boolean expression to be configured.

        """

        if isinstance(expressions, list):
            for i in range(len(expressions)):
                self.expressions['Boolean expression {}'.format(i)] = \
                    deepcopy(expressions[i])
        elif isinstance(expressions, dict):
            self.expressions = deepcopy(expressions)
        else:
            raise ValueError("Expressions must be list or dict.")

        mailbox_addr = self.bg_mmio.base_addr
        mailbox_regs = [Register(addr) for addr in range(
            mailbox_addr, mailbox_addr + 4 * 64, 4)]
        for offset in range(0, 32, 2):
            mailbox_regs[offset][31:0] = 0x1FFFFFF

        for index in range (0,32):
            self.bg_mmio.write((index*4),mailbox_regs[index][31:0])
        self.bg_mmio.write((62*4),0x0000ffff)
        self.bg_mmio.write((63*4),(0x0000ffff | 0x80000000))
        self.bg_mmio.write((63*4), 0) # was 0x0000ffff)

        for expr_label, expression in self.expressions.items():
            if not isinstance(expression, str):
                raise TypeError("Boolean expression has to be a string.")

            if "=" not in expression:
                raise ValueError(
                    "Boolean expression must have form Output = Function.")

            # Parse boolean expression into output & input string
            expr_out, expr_in = expression.split("=")
            expr_out = expr_out.strip()
            if expr_out in self.output_pins:
                raise ValueError("The same output pin should not be driven by "
                                 "multiple expressions.")
            self.output_pins.append(expr_out)
            if expr_out in self.intf_spec['output_pins']:
                output_pin_num = self.intf_spec[
                    'output_pins'][expr_out]
            else:
                raise ValueError("Invalid output pin {}.".format(expr_out))

            # Parse the used pins preserving the order
            non_unique_inputs = re.sub("\W+", " ", expr_in).strip().split(' ')
            unique_input_pins = list(OrderedDict.fromkeys(non_unique_inputs))
            if not 1 <= len(unique_input_pins) <= 5:
                raise ValueError("Expect 1 - 5 inputs for each LUT.")
            input_pins_with_dontcares = unique_input_pins[:]
            self.input_pins += unique_input_pins
            self.input_pins = list(set(self.input_pins))

            # Need 5 inputs - any unspecified inputs will be don't cares
            for i in range(len(input_pins_with_dontcares), 5):
                expr_in = '(({0}) & X{1})|(({0}) & ~X{1})'.format(
                    expr_in, i)
                input_pins_with_dontcares.append('X{}'.format(i))

            # Map to truth table
            p0, p1, p2, p3, p4 = map(exprvar, input_pins_with_dontcares)
            expr_p = expr_in

            # Use regular expression to match and replace whole word only
            for orig_name, p_name in zip(input_pins_with_dontcares,
                                         ['p{}'.format(i) for i in range(5)]):
                expr_p = re.sub(r"\b{}\b".format(orig_name), p_name, expr_p)

            truth_table = expr2truthtable(eval(expr_p))

            # Parse truth table to send
            truth_list = str(truth_table).split("\n")
            truth_num = 0
            for i in range(32, 0, -1):
                truth_num = (truth_num << 1) + int(truth_list[i][-1])

            # Get current boolean generator bit enables
            bit_enables = self.bg_mmio.read(62*4)
            cfg_enables = self.bg_mmio.read(63*4)

            # Generate the input selects based on truth table and bit enables
            truth_table_inputs = [str(inp) for inp in truth_table.inputs]
            for i in range(5):
                lsb = i * 5
                msb = (i + 1) * 5 - 1
                if truth_table_inputs[i] in unique_input_pins:
                    if truth_table_inputs[i] in self.intf_spec[
                        'input_pins'] and truth_table_inputs[i] \
                            in self.intf_spec['input_pins']:
                        input_pin_ix = self.intf_spec[
                            'input_pins'][truth_table_inputs[i]]
                    else:
                        raise ValueError("Invalid input pin "
                                         "{}.".format(truth_table_inputs[i]))
                else:
                    input_pin_ix = 0x1f
                mailbox_regs[output_pin_num * 2][msb:lsb] = input_pin_ix

            mailbox_regs[output_pin_num * 2 + 1][31:0] = truth_num
            mailbox_regs[62][31:0] = bit_enables
            mailbox_regs[62][output_pin_num] = 0

            mailbox_regs[63][31:0] = cfg_enables
            mailbox_regs[63][output_pin_num] = 1

        int_to_write_62=int(mailbox_regs[62][31:0])
        int_to_write_63=int(mailbox_regs[63][31:0])
        for index in range (0,32):
            self.bg_mmio.write((index*4),(mailbox_regs[index][31:0]))
        self.bg_mmio.write((62*4), int_to_write_62)
        self.bg_mmio.write((63*4),(int_to_write_63 | 0x80000000))
        self.bg_mmio.write((63*4), int_to_write_63)

    def read(self, regnum):
        """Read Boolean Generator memory mapped registers.

        Parameters
        ----------
        regnum : integer

        """
        if type(regnum) is int:
            self.reg_num = regnum
        else:
            raise ValueError("Register number must be integer")

        if regnum not in range (0,64):
            raise ValueError("Register number must be in range of 0-63")

        return (self.bg_mmio.read(self.reg_num*4))

    def clear(self, expressions):
        """Clear output pins so new function on same pin can be defined.

        Parameters
        ----------
        expressions : list/dict
            Clear output pins so previosly configured output pins can be used.

        """

        if isinstance(expressions, list):
            for i in range(len(expressions)):
                self.expressions['Boolean expression {}'.format(i)] = \
                    deepcopy(expressions[i])
        elif isinstance(expressions, dict):
            self.expressions = deepcopy(expressions)
        else:
            raise ValueError("Expressions must be list or dict.")

        self.output_pins = list()


from odoo import api, fields, models, _
import odoo.addons.decimal_precision as dp
from odoo.exceptions import UserError

class KGPurchaseRequestLineMakePurchaseOrder(models.TransientModel):
    _inherit = "purchase.request.line.make.purchase.order"

    @api.model
    def _prepare_item(self, line):
        res = super(KGPurchaseRequestLineMakePurchaseOrder, self)._prepare_item(line)
        res['purchase_type'] = line.request_id.purchase_type
        return res

    @api.model
    def _prepare_purchase_order(self, picking_type, group_id, company, origin, purchase_type):
        if not self.supplier_id:
            raise UserError(
                _('Enter a supplier.'))
        supplier = self.supplier_id
        data = {
            'origin': origin,
            'partner_id': self.supplier_id.id,
            'fiscal_position_id': supplier.property_account_position_id and
            supplier.property_account_position_id.id or False,
            'picking_type_id': picking_type.id,
            'company_id': company.id,
            'group_id': group_id.id,
            'purchase_type': purchase_type.id,
            'from_purchase_request': True
            }
        return data

    @api.model
    def _check_valid_request_line(self, request_line_ids):
        picking_type = False
        company_id = False
        purch_type = []
        for line in self.env['purchase.request.line'].browse(request_line_ids):
            purch_type.append(line.request_id.purchase_type)

            if line.request_id.state != 'approved':
                raise UserError(
                    _('Purchase Request %s is not approved') %
                    line.request_id.name)

            if line.purchase_state == 'done':
                raise UserError(
                    _('The purchase has already been completed.'))

            line_company_id = line.company_id \
                and line.company_id.id or False
            if company_id is not False \
                    and line_company_id != company_id:
                raise UserError(
                    _('You have to select lines '
                      'from the same company.'))
            else:
                company_id = line_company_id

            line_picking_type = line.request_id.picking_type_id or False
            if not line_picking_type:
                raise UserError(
                    _('You have to enter a Picking Type.'))
            if picking_type is not False \
                    and line_picking_type != picking_type:
                raise UserError(
                    _('You have to select lines '
                      'from the same Picking Type.'))
            else:
                picking_type = line_picking_type

        if len(list(set(purch_type))) > 1:
            raise UserError(
                _('You cannot create a single Purchase Order from '
                  'purchase requests that have different Purchase Type.'))

    @api.multi
    def make_purchase_order(self):
        res = []
        purchase_obj = self.env['purchase.order']
        po_line_obj = self.env['purchase.order.line']
        pr_line_obj = self.env['purchase.request.line']
        purchase = False

        for item in self.item_ids:
            line = item.line_id
            if item.product_qty <= 0.0:
                raise UserError(
                    _('Enter a positive quantity.'))
            if self.purchase_order_id:
                purchase = self.purchase_order_id
            if not purchase:
                po_data = self._prepare_purchase_order(
                    line.request_id.picking_type_id,
                    line.request_id.group_id,
                    line.company_id,
                    line.origin,
                    line.request_id.purchase_type)
                purchase = purchase_obj.create(po_data)

            # Look for any other PO line in the selected PO with same
            # product and UoM to sum quantities instead of creating a new
            # po line
            domain = self._get_order_line_search_domain(purchase, item)
            available_po_lines = po_line_obj.search(domain)
            new_pr_line = True
            if available_po_lines and not item.keep_description:
                new_pr_line = False
                po_line = available_po_lines[0]
                po_line.purchase_request_lines = [(4, line.id)]
                po_line.move_dest_ids |= line.move_dest_ids
            else:
                po_line_data = self._prepare_purchase_order_line(purchase,
                                                                 item)
                if item.keep_description:
                    po_line_data['name'] = item.name
                po_line = po_line_obj.create(po_line_data)
            new_qty = pr_line_obj._calc_new_qty(
                line, po_line=po_line,
                new_pr_line=new_pr_line)
            po_line.product_qty = new_qty
            po_line._onchange_quantity()
            # The onchange quantity is altering the scheduled date of the PO
            # lines. We do not want that:
            po_line.date_planned = item.line_id.date_required
            res.append(purchase.id)

        return {
            'domain': [('id', 'in', res)],
            'name': _('RFQ'),
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'purchase.order',
            'view_id': False,
            'context': False,
            'type': 'ir.actions.act_window'
        }


# -*- coding: utf-8 -*-
from json import dumps
from unittest import TestCase

from projects.api.main import app
from projects.controllers.utils import uuid_alpha
from projects.database import engine
from projects.object_storage import BUCKET_NAME

EXPERIMENT_ID = str(uuid_alpha())
NAME = "foo"
POSITION = 0
EXPERIMENT_ID_2 = str(uuid_alpha())
NAME_2 = "foo 2"
POSITION_2 = 1
PROJECT_ID = str(uuid_alpha())
TEMPLATE_ID = str(uuid_alpha())
TASK_ID = str(uuid_alpha())
OPERATOR_ID = str(uuid_alpha())
OPERATOR_ID_2 = str(uuid_alpha())
OPERATOR_ID_3 = str(uuid_alpha())
OPERATOR_ID_4 = str(uuid_alpha())
DEPENDENCY_ID = str(uuid_alpha())
IS_ACTIVE = True
PARAMETERS = {"coef": 0.1}
PARAMETERS_JSON = dumps(PARAMETERS)
DESCRIPTION = "long foo"
IMAGE = "platiagro/platiagro-notebook-image-test:0.2.0"
COMMANDS = ["CMD"]
COMMANDS_JSON = dumps(COMMANDS)
ARGUMENTS = ["ARG"]
ARGUMENTS_JSON = dumps(ARGUMENTS)
TAGS = ["PREDICTOR"]
TAGS_JSON = dumps(TAGS)
TASKS_JSON = dumps([TASK_ID])
EXPERIMENT_NOTEBOOK_PATH = f"minio://{BUCKET_NAME}/tasks/{TASK_ID}/Experiment.ipynb"
DEPLOYMENT_NOTEBOOK_PATH = f"minio://{BUCKET_NAME}/tasks/{TASK_ID}/Deployment.ipynb"
CREATED_AT = "2000-01-01 00:00:00"
CREATED_AT_ISO = "2000-01-01T00:00:00"
UPDATED_AT = "2000-01-01 00:00:00"
UPDATED_AT_ISO = "2000-01-01T00:00:00"
NAME_COPYFROM = "TEST_COPY"

DEPENDENCIES_EMPTY = []
DEPENDENCIES_EMPTY_JSON = dumps(DEPENDENCIES_EMPTY)
DEPENDENCIES_OP_ID = [OPERATOR_ID]
DEPENDENCIES_OP_ID_JSON = dumps(DEPENDENCIES_OP_ID)

class TestExperiments(TestCase):
    def setUp(self):
        self.maxDiff = None
        conn = engine.connect()
        text = (
            f"INSERT INTO tasks (uuid, name, description, image, commands, arguments, tags, experiment_notebook_path, deployment_notebook_path, is_default, created_at, updated_at) "
            f"VALUES ('{TASK_ID}', '{NAME}', '{DESCRIPTION}', '{IMAGE}', '{COMMANDS_JSON}', '{ARGUMENTS_JSON}', '{TAGS_JSON}', '{EXPERIMENT_NOTEBOOK_PATH}', '{DEPLOYMENT_NOTEBOOK_PATH}', 0, '{CREATED_AT}', '{UPDATED_AT}')"
        )
        conn.execute(text)
        text = (
            f"INSERT INTO projects (uuid, name, created_at, updated_at) "
            f"VALUES ('{PROJECT_ID}', '{NAME}', '{CREATED_AT}', '{UPDATED_AT}')"
        )
        conn.execute(text)

        text = (
            f"INSERT INTO experiments (uuid, name, project_id, position, is_active, created_at, updated_at) "
            f"VALUES ('{EXPERIMENT_ID}', '{NAME}', '{PROJECT_ID}', '{POSITION}', 1, '{CREATED_AT}', '{UPDATED_AT}')"
        )
        conn.execute(text)

        text = (
            f"INSERT INTO experiments (uuid, name, project_id, position, is_active, created_at, updated_at) "
            f"VALUES ('{EXPERIMENT_ID_2}', '{NAME_2}', '{PROJECT_ID}', '{POSITION_2}', 1, '{CREATED_AT}', '{UPDATED_AT}')"
        )
        conn.execute(text)

        text = (
            f"INSERT INTO operators (uuid, experiment_id, task_id, parameters, created_at, updated_at, dependencies) "
            f"VALUES ('{OPERATOR_ID}', '{EXPERIMENT_ID}', '{TASK_ID}', '{PARAMETERS_JSON}', '{CREATED_AT}', '{UPDATED_AT}', '{DEPENDENCIES_EMPTY_JSON}')"
        )
        conn.execute(text)

        text = (
            f"INSERT INTO operators (uuid, experiment_id, task_id, parameters, created_at, updated_at, dependencies) "
            f"VALUES ('{OPERATOR_ID_2}', '{EXPERIMENT_ID}', '{TASK_ID}', '{PARAMETERS_JSON}', '{CREATED_AT}', '{UPDATED_AT}', '{DEPENDENCIES_OP_ID_JSON}')"
        )
        conn.execute(text)

        text = (
            f"INSERT INTO templates (uuid, name, tasks, created_at, updated_at) "
            f"VALUES ('{TEMPLATE_ID}', '{NAME}', '{TASKS_JSON}', '{CREATED_AT}', '{UPDATED_AT}')"
        )
        conn.execute(text)
        conn.close()

    def tearDown(self):
        conn = engine.connect()

        text = f"DELETE FROM templates WHERE uuid = '{TEMPLATE_ID}'"
        conn.execute(text)

        text = f"DELETE FROM operators WHERE experiment_id = '{EXPERIMENT_ID}'"
        conn.execute(text)

        text = f"DELETE FROM operators WHERE experiment_id =" \
               f" (SELECT uuid FROM experiments where name = '{NAME_COPYFROM}')"
        conn.execute(text)

        text = f"DELETE FROM experiments WHERE project_id in ('{PROJECT_ID}')"
        conn.execute(text)

        text = f"DELETE FROM projects WHERE uuid = '{PROJECT_ID}'"
        conn.execute(text)

        text = f"DELETE FROM tasks WHERE uuid = '{TASK_ID}'"
        conn.execute(text)

        conn.close()

    def test_list_experiments(self):
        with app.test_client() as c:
            rv = c.get("/projects/unk/experiments")
            result = rv.get_json()
            expected = {"message": "The specified project does not exist"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 404)

            rv = c.get(f"/projects/{PROJECT_ID}/experiments")
            result = rv.get_json()
            self.assertIsInstance(result, list)

    def test_create_experiment(self):
        with app.test_client() as c:
            rv = c.post("/projects/unk/experiments", json={})
            result = rv.get_json()
            expected = {"message": "The specified project does not exist"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 404)

            rv = c.post(f"/projects/{PROJECT_ID}/experiments", json={})
            result = rv.get_json()
            expected = {"message": "name is required"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 400)

            rv = c.post(f"/projects/{PROJECT_ID}/experiments", json={
                "name": NAME,
            })
            result = rv.get_json()
            expected = {"message": "an experiment with that name already exists"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 400)

            rv = c.post(f"/projects/{PROJECT_ID}/experiments", json={
                "name": "test",
            })
            result = rv.get_json()
            expected = {
                "name": "test",
                "projectId": PROJECT_ID,
                "position": 2,
                "isActive": IS_ACTIVE,
                "operators": [],
            }
            # uuid, created_at, updated_at are machine-generated
            # we assert they exist, but we don't assert their values
            machine_generated = ["uuid", "createdAt", "updatedAt"]
            for attr in machine_generated:
                self.assertIn(attr, result)
                del result[attr]
            self.assertDictEqual(expected, result)

        """Copy operators for a given experiment"""
        with app.test_client() as c:
            rv = c.post(f"/projects/{PROJECT_ID}/experiments", json={
                "name": f"{NAME_COPYFROM}",
                "copy_from": f"{EXPERIMENT_ID}"
            })
            self.assertEqual(rv.status_code, 200)

            rv = c.post(f"/projects/{PROJECT_ID}/experiments", json={
                "name": f"TESCOPY",
                "copy_from": f"4555"
            })
            self.assertEqual(rv.status_code, 400)

    def test_get_experiment(self):
        with app.test_client() as c:
            rv = c.get(f"/projects/foo/experiments/{EXPERIMENT_ID}")
            result = rv.get_json()
            expected = {"message": "The specified project does not exist"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 404)

            rv = c.get(f"/projects/{PROJECT_ID}/experiments/foo")
            result = rv.get_json()
            expected = {"message": "The specified experiment does not exist"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 404)

            rv = c.get(f"/projects/{PROJECT_ID}/experiments/{EXPERIMENT_ID}")
            result = rv.get_json()
            expected = {
                "uuid": EXPERIMENT_ID,
                "name": NAME,
                "projectId": PROJECT_ID,
                "position": POSITION,
                "isActive": IS_ACTIVE,
                "operators": result['operators'],
                "createdAt": CREATED_AT_ISO,
                "updatedAt": UPDATED_AT_ISO,
            }
            self.assertDictEqual(expected, result)

    def test_update_experiment(self):
        with app.test_client() as c:
            rv = c.patch(f"/projects/foo/experiments/{EXPERIMENT_ID}", json={})
            result = rv.get_json()
            expected = {"message": "The specified project does not exist"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 404)

            rv = c.patch(f"/projects/{PROJECT_ID}/experiments/foo", json={})
            result = rv.get_json()
            expected = {"message": "The specified experiment does not exist"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 404)

            rv = c.patch(f"/projects/{PROJECT_ID}/experiments/{EXPERIMENT_ID}", json={
                "name": NAME_2,
            })
            result = rv.get_json()
            expected = {"message": "an experiment with that name already exists"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 400)

            rv = c.patch(f"/projects/{PROJECT_ID}/experiments/{EXPERIMENT_ID}", json={
                "templateId": "unk",
            })
            result = rv.get_json()
            expected = {"message": "The specified template does not exist"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 400)

            rv = c.patch(f"/projects/{PROJECT_ID}/experiments/{EXPERIMENT_ID}", json={
                "unk": "bar",
            })
            self.assertEqual(rv.status_code, 400)

            # update experiment using the same name
            rv = c.patch(f"/projects/{PROJECT_ID}/experiments/{EXPERIMENT_ID}", json={
                "name": NAME,
            })
            self.assertEqual(rv.status_code, 200)

            rv = c.patch(f"/projects/{PROJECT_ID}/experiments/{EXPERIMENT_ID}", json={
                "name": "bar",
            })
            result = rv.get_json()
            expected = {
                "uuid": EXPERIMENT_ID,
                "name": "bar",
                "projectId": PROJECT_ID,
                "position": POSITION,
                "isActive": IS_ACTIVE,
                "operators": result['operators'],
                "createdAt": CREATED_AT_ISO,
            }
            machine_generated = ["updatedAt"]
            for attr in machine_generated:
                self.assertIn(attr, result)
                del result[attr]
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 200)

            rv = c.patch(f"/projects/{PROJECT_ID}/experiments/{EXPERIMENT_ID}", json={
                "templateId": TEMPLATE_ID,
            })
            result = rv.get_json()
            expected = {
                "uuid": EXPERIMENT_ID,
                "name": "bar",
                "projectId": PROJECT_ID,
                "position": POSITION,
                "isActive": IS_ACTIVE,
                "createdAt": CREATED_AT_ISO,
            }
            result_operators = result["operators"]
            machine_generated = ["updatedAt", "operators"]
            for attr in machine_generated:
                self.assertIn(attr, result)
                del result[attr]
            self.assertDictEqual(expected, result)
            expected = [{
                "taskId": TASK_ID,
                "experimentId": EXPERIMENT_ID,
                "parameters": {},
                "dependencies": [],
                "positionX": None,
                "positionY": None,
                "deploymentId": None
            }]
            machine_generated = ["uuid", "createdAt", "updatedAt"]
            for attr in machine_generated:
                for operator in result_operators:
                    self.assertIn(attr, operator)
                    del operator[attr]
            self.assertListEqual(expected, result_operators)

    def test_delete_experiment(self):
        with app.test_client() as c:
            rv = c.delete(f"/projects/foo/experiments/{EXPERIMENT_ID}")
            result = rv.get_json()
            expected = {"message": "The specified project does not exist"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 404)

            rv = c.delete(f"/projects/{PROJECT_ID}/experiments/unk")
            result = rv.get_json()
            expected = {"message": "The specified experiment does not exist"}
            self.assertDictEqual(expected, result)
            self.assertEqual(rv.status_code, 404)

            rv = c.delete(f"/projects/{PROJECT_ID}/experiments/{EXPERIMENT_ID}")
            result = rv.get_json()
            expected = {"message": "Experiment deleted"}
            self.assertDictEqual(expected, result)


from os import getcwd, listdir, rename, chdir

current_directory = str(getcwd())
current_file_path = ''
file_path = ''
file_name = 'noname'
counter = 1

if __name__ == '__main__':
    print('!!!!Hello, welcome to the file renamer!!!!')
    question_for_path = input('Full path or from the current directory(1 - full, 2 - current): ')
    file_path = input('Enter file path: ')
    if question_for_path == '2':
        current_file_path = current_directory + file_path
    else:
        current_file_path = file_path
    try:
        chdir(file_path)
        file_name = input('Enter file name: ')
        array_file = listdir(file_path)
        if len(array_file) > 0:
            for file in array_file:
                rename(file, str(file_name + str(counter) + '.jpg'), src_dir_fd=None, dst_dir_fd=None)
                counter += 1
    except FileNotFoundError:
        print('Incorrect path')


# -*- coding: utf-8 -*-
"""
Created on Thu August 10 23:52:55 2022

@author: jmmauricio
"""

import numpy as np
import sympy as sym

def i_vsg_ll(grid,name,bus_name,data_dict):
    """
    # auxiliar equations
    Omega_b = 2*np.pi*F_n
    omega_s = omega_coi
    v_D = V*sin(theta)  # e^(-j)
    v_Q = V*cos(theta)
    v_d = v_D * cos(delta) - v_Q * sin(delta)
    v_q = v_D * sin(delta) + v_Q * cos(delta)

    Domega = x_v + K_p * (p_ref - p)
    e_dv = 0.0
    epsilon_v = v_ref - V
    i_d = i_d_ref
    i_q = i_q_ref
    omega_v = Domega + 1.0
    q_ref_0 = K_p_v * epsilon_v + K_i_v * xi_v

    # dynamical equations
    ddelta   = Omega_b*(omega_v - omega_s) - K_delta*delta
    dx_v = K_i*(p_ref - p) - K_g*(omega_v - 1.0)
    de_qm = 1.0/T_q * (q - q_ref_0 - q_ref - e_qm)
    dxi_v = epsilon_v # PI agregado

    # algebraic equations
    g_i_d_ref  = e_dv - R_v * i_d_ref - X_v * i_q_ref - v_d
    g_i_q_ref  = e_qv - R_v * i_q_ref + X_v * i_d_ref - v_q
    g_p  = v_d*i_d + v_q*i_q - p
    g_q  = v_d*i_q - v_q*i_d - q
    g_e_qv = 1.0 - e_qv - K_q*e_qm

    {"bus":"1","type":"vsg_ll",'S_n':10e6,'F_n':50,'K_delta':0.0,
    'R_v':0.01,'X_v':0.1,'K_p':1.0,'K_i':0.1,'K_g':0.0,'K_q':20.0,
    'T_q':0.1,'K_p_v':1e-6,'K_i_v':1e-6}

    """

    sin = sym.sin
    cos = sym.cos

    ctrl_data = data_dict['ctrl']

    buses = grid.data['buses']
    buses_list = [bus['name'] for bus in buses]

    idx_bus = buses_list.index(bus_name) # get the number of the bus where the syn is connected
    if not 'idx_powers' in buses[idx_bus]: buses[idx_bus].update({'idx_powers':0})
    buses[idx_bus]['idx_powers'] += 1

    # inputs:
    q_l,q_r,v_ref = sym.symbols(f'q_l_{name},q_r_{name},v_ref_{name}', real=True)
    p_l,p_r = sym.symbols(f'p_l_{name},p_r_{name}', real=True)
    v_dc = sym.Symbol(f"v_dc_{name}", real=True)
    Ddelta_ff,Domega_ff = sym.symbols(f'Ddelta_ff_{name},Domega_ff_{name}', real=True)

    # dynamical states:
    delta,x_p1,x_p2,e_qm,xi_v = sym.symbols(f'delta_{name},x_p1_{name},x_p2_{name},e_qm_{name},xi_v_{name}', real=True)

    # algebraic states:
    Domega = sym.Symbol(f'Domega_{name}', real=True)
    p_s = sym.Symbol(f'p_s_{name}', real=True)
    q_s = sym.Symbol(f'q_s_{name}', real=True)
    e_vq = sym.Symbol(f"e_vq_{name}", real=True)
    v_td_ref = sym.Symbol(f"v_td_ref_{name}", real=True)
    v_tq_ref = sym.Symbol(f"v_tq_ref_{name}", real=True)

    # params:
    S_base = sym.Symbol('S_base', real = True) # S_base = global power base, S_n = machine power base
    S_n,F_n,K_delta = sym.symbols(f'S_n_{name},F_n_{name},K_delta_{name}', real=True)
    K_p,K_i,K_g,K_i_q = sym.symbols(f'K_p_{name},K_i_{name},K_g_{name},K_i_q_{name}', real=True)
    R_v,X_v = sym.symbols(f'R_v_{name},X_v_{name}', real=True)
    K_q,T_q = sym.symbols(f'K_q_{name},T_q_{name}', real=True)
    K_p_v,K_i_v = sym.symbols(f'K_p_v_{name},K_i_v_{name}', real=True)
    params_list = ['F_n','K_delta','K_p','K_i','K_g','R_v','X_v','K_q','T_q','K_p_v','K_i_v']

    # auxiliar variables and constants
    omega_coi = sym.Symbol("omega_coi", real=True) # from global system
    V_s = sym.Symbol(f"V_{bus_name}", real=True) # from global system
    theta_s = sym.Symbol(f"theta_{bus_name}", real=True) # from global system
    i_si = sym.Symbol(f"i_si_{name}", real=True)
    i_sr = sym.Symbol(f"i_sr_{name}", real=True)
    m = sym.Symbol(f"m_{name}", real=True)
    theta_t = sym.Symbol(f"theta_t_{name}", real=True)

    # auxiliar equations
    Omega_b = 2*np.pi*F_n
    omega_s = omega_coi

    i_sD = i_si  # e^(-j)
    i_sQ = i_sr

    delta_ff =  delta + Ddelta_ff
    i_sd = i_sD * cos(delta_ff) - i_sQ * sin(delta_ff)
    i_sq = i_sD * sin(delta_ff) + i_sQ * cos(delta_ff)

    p_ref = p_l + p_r
    q_ref = q_l + q_r
    e_vd = 0.0
    epsilon_v = v_ref - V_s
    omega_v = Domega + 1.0
    q_ref_0 = K_p_v * epsilon_v + K_i_v * xi_v

    v_tD_ref =  v_td_ref * cos(delta_ff) + v_tq_ref * sin(delta_ff)
    v_tQ_ref = -v_td_ref * sin(delta_ff) + v_tq_ref * cos(delta_ff)

    v_ti_ref = v_tD_ref
    v_tr_ref = v_tQ_ref
    m_ref = sym.sqrt(v_tr_ref**2 + v_ti_ref**2)/v_dc
    theta_t_ref = sym.atan2(v_ti_ref,v_tr_ref)
    p_meas = p_s

    # dynamical equations
    ddelta   = Omega_b*(omega_v - omega_s) - K_delta*delta
    dx_p1 = K_i*(p_ref - p_meas) - K_g*x_p1
    dx_p2 = K_p*(p_ref - p_meas) - K_g*x_p2
    de_qm = 1.0/T_q * (q_s - q_ref_0 - q_ref - e_qm)
    dxi_v = epsilon_v # PI agregado

    # algebraic equations
    g_Domega = -Domega +  dx_p2 + x_p1
    g_v_td_ref  = e_vd - R_v * i_sd - X_v * i_sq - v_td_ref
    g_v_tq_ref  = e_vq - R_v * i_sq + X_v * i_sd - v_tq_ref

    g_e_vq = 1.0 - e_vq - K_q*e_qm
    g_m  = m-m_ref
    g_theta_t  = theta_t-theta_t_ref

    # DAE system update
    grid.dae['f'] += [ddelta,dx_p1,dx_p2,de_qm,dxi_v]
    grid.dae['x'] += [ delta, x_p1, x_p2, e_qm, xi_v]
    grid.dae['g'] +=     [g_Domega,g_v_td_ref,g_v_tq_ref,g_e_vq,g_m,g_theta_t]
    grid.dae['y_ini'] += [  Domega,v_td_ref,  v_tq_ref,  e_vq,  m,  theta_t]
    grid.dae['y_run'] += [  Domega,v_td_ref,  v_tq_ref,  e_vq,  m,  theta_t]

    # default inputs
    grid.dae['u_ini_dict'].update({f'p_l_{name}':0.0})
    grid.dae['u_ini_dict'].update({f'q_l_{name}':0.0})
    grid.dae['u_ini_dict'].update({f'p_r_{name}':0.0})
    grid.dae['u_ini_dict'].update({f'q_r_{name}':0.0})
    grid.dae['u_ini_dict'].update({f'v_ref_{name}':1.0})
    grid.dae['u_ini_dict'].update({f'Ddelta_ff_{name}':0.0})
    grid.dae['u_ini_dict'].update({f'Domega_ff_{name}':0.0})

    grid.dae['u_run_dict'].update({f'p_l_{name}':0.0})
    grid.dae['u_run_dict'].update({f'q_l_{name}':0.0})
    grid.dae['u_run_dict'].update({f'p_r_{name}':0.0})
    grid.dae['u_run_dict'].update({f'q_r_{name}':0.0})
    grid.dae['u_run_dict'].update({f'v_ref_{name}':1.0})
    grid.dae['u_run_dict'].update({f'Ddelta_ff_{name}':0.0})
    grid.dae['u_run_dict'].update({f'Domega_ff_{name}':0.0})

    # default parameters
    for item in params_list:
        grid.dae['params_dict'].update({item + f'_{name}':ctrl_data[item]})

    # add speed*H term to global for COI speed computing
    H = 4.0
    grid.H_total += H
    grid.omega_coi_numerator += omega_v*H*S_n
    grid.omega_coi_denominator += H*S_n

    # DAE outputs update
    grid.dae['h_dict'].update({f"omega_v_{name}":omega_v})
    grid.dae['h_dict'].update({f"p_ref_{name}":p_ref})
    grid.dae['h_dict'].update({f"q_ref_{name}":q_ref})
    grid.dae['h_dict'].update({f"v_ref_{name}":v_ref})
    grid.dae['h_dict'].update({f"i_sd_{name}":i_sd})
    grid.dae['h_dict'].update({f"i_sq_{name}":i_sq})
    grid.dae['h_dict'].update({f"delta_ff_{name}":delta_ff})

    grid.dae['xy_0_dict'].update({str(e_vq):1.0})
    grid.dae['xy_0_dict'].update({str(v_tq_ref):1.0})

    p_W   = p_s * S_n
    q_var = q_s * S_n

    return p_W,q_var

if __name__ == "__main__":
    pass


from typing import List, Tuple

import labop
import uml

def protocol_make_decision_node(
    self: labop.Protocol,
    primary_incoming_node: uml.ActivityNode,
    decision_input_behavior: uml.Behavior = None,
    decision_input_source: uml.ActivityNode = None,
    outgoing_targets: List[Tuple[uml.ValueSpecification, uml.ActivityNode]] = None,
):
    """
    Make a uml:DecisionNode using optionally specified incoming and outgoing nodes.
    Returns a uml:DecisionNode and a set of edges connecting incoming and outgoing nodes.

    Args:
        primary_incoming_source_node (uml:ActivityNode): primary incoming edge type (control or object) determines output edge types
        decision_input_source_node (uml:ActivityNode, optional): Used to evaluate guards. Defaults to None.
        outgoing_targets (List[Tuple[uml.ValueSpecification, uml.ActivityNode]], optional): List of pairs of guards and nodes for outgoing edges. Defaults to None.
    """

    assert primary_incoming_node
    primary_incoming_flow = (
        uml.ControlFlow(source=primary_incoming_node)
        if isinstance(primary_incoming_node, uml.ControlNode)
        else uml.ObjectFlow(source=primary_incoming_node)
    )
    self.edges.append(primary_incoming_flow)

    decision_input = None

    if decision_input_behavior:
        input_pin_map = {}
        decision_input_control = None
        if decision_input_source:
            input_pin_map["decision_input"] = decision_input_source
        if primary_incoming_node:
            if isinstance(primary_incoming_node, uml.ObjectNode):
                input_pin_map["primary_input"] = primary_incoming_node
            else:
                # Make a ControlFlow so that decision_input executes first
                decision_input_control = uml.ControlFlow(source=primary_incoming_node)

        decision_input = self.execute_primitive(
            decision_input_behavior, **input_pin_map
        )
        if decision_input_control:
            decision_input_control.target = decision_input
            self.edges.append(decision_input_control)

    decision_input_flow = None
    if decision_input_source:
        decision_input_flow = uml.ObjectFlow(source=decision_input_source)
        self.edges.append(decision_input_flow)

    decision = uml.DecisionNode(
        decision_input=decision_input_behavior, decision_input_flow=decision_input_flow
    )
    self.nodes.append(decision)

    if decision_input:
        # Flow that communicates the return value of the decision_input behavior execution to the decision
        decision_input_to_decision_flow = uml.ObjectFlow(
            source=decision_input.output_pin("return"), target=decision
        )
        self.edges.append(decision_input_to_decision_flow)

    primary_incoming_flow.target = decision
    if decision_input_flow:
        decision_input_flow.target = decision

    # Make edges for outgoing_targets
    if outgoing_targets:
        for (guard, target) in outgoing_targets:
            decision.add_decision_output(self, guard, target)

    return decision

labop.Protocol.make_decision_node = (
    protocol_make_decision_node  # Add to class via monkey patch
)

def decision_node_add_decision_output(self, protocol, guard, target):
    """Attach a guarded edge between DecisionNode and target.

    Args:
        protocol (labop.Protocol): The protocol with the self DecisionNode.
        guard (primitive type): edge guard
        target (uml.ActivityNode): edge target
    """

    kwargs = {"source": self, "target": target}
    kwargs["guard"] = uml.literal(guard)
    outgoing_edge = (
        uml.ObjectFlow(**kwargs)
        if isinstance(self.get_primary_incoming_flow(protocol).source, uml.ObjectNode)
        else uml.ControlFlow(**kwargs)
    )
    protocol.edges.append(outgoing_edge)

uml.DecisionNode.add_decision_output = (
    decision_node_add_decision_output  # Add to class via monkey patch
)

def decision_node_get_primary_incoming_flow(self, protocol):
    try:
        primary_incoming_flow = next(
            e
            for e in protocol.edges
            if e.target is not None
            and e.target.lookup() == self
            and e != self.decision_input_flow
            and not (
                isinstance(e.source.lookup(), uml.OutputPin)
                and e.source.lookup().get_parent().behavior == self.decision_input
            )
        )
        return primary_incoming_flow
    except StopIteration as e:
        raise Exception(
            f"Could not find primary_incoming edge for DecisionNode: {self.identity}"
        )

uml.DecisionNode.get_primary_incoming_flow = (
    decision_node_get_primary_incoming_flow  # Add to class via monkey patch
)

def decision_node_get_decision_input_node(self):
    if hasattr(self, "decision_input") and self.decision_input:
        return self.decision_input
    else:
        # primary input flow leads to decision
        primary_incoming_flow = self.get_primary_incoming_flow(self.protocol())
        return primary_incoming_flow.source.lookup().get_decision_input_node()

uml.DecisionNode.get_decision_input_node = (
    decision_node_get_decision_input_node  # Add to class via monkey patch
)

def fork_node_get_decision_input_node(self):
    [fork_input_edge] = [e for e in self.protocol().edges if e.target.lookup() == self]
    decision_input_node = fork_input_edge.source.lookup().get_decision_input_node()
    return decision_input_node

uml.ForkNode.get_decision_input_node = (
    fork_node_get_decision_input_node  # Add to class via monkey patch
)

def output_pin_get_decision_input_node(self):
    return self.get_parent()

uml.OutputPin.get_decision_input_node = (
    output_pin_get_decision_input_node  # Add to class via monkey patch
)


"""
:mod:`tsne`

Returns t-SNE plot given a set of features.
"""

import numpy as np
from sklearn.manifold import TSNE

from . import plot

def reduce_features_in_two_dimensions_using_tsne(density_contrasts_with_label,
                                                 n_components=2, perplexity=50.0,
                                                 early_exaggeration=4.0, learning_rate=1000.0, n_iter=1000,
                                                 metric="euclidean", init="random",
                                                 random_state=None):
    """
    Tune t-SNE hyperparameters and reduce feature space to two dimensions using t-SNE.
    We use the t-SNE algorithm inbuilt in the scikit-learn package.

    Args:
        density_contrasts_with_label (ndarray): labeled density contrasts for in and out particles.
        n_components (int): Dimensions of reduced feature space. Default is 2.
        perplexity (float): Related to number of nearest neighbours used in other "manifold" algorithms.
           t-SNE not very sensitive to this. Usually in the range 5-50. Default is 50.
        early_exaggeration (float): Controls how tight clusters in original space will be in embedded space.
           t-SNE not very sensitive to this. Default is 4.0.
        learning_rate (float): This can be critical. Should be between 100 and 1000. Default is 1000.
        n_iter (int): Max number of iteration for optimization. Default is 1000.
        metric (str): Metric of similarity in feature space. Default is "euclidean", which is
             squared euclidean distance.
        init (str):"random" or "pca". Default is "random".
        random_state: Psuedo Random Number generator seed control.

    Returns:
        labeled_features_two_dimensions (2Darray): Two-dimensional features array which features as columns.
    """
    if len(density_contrasts_with_label[0]) > 52:
        raise ValueError("t-SNE dimensionality reduction doesn't work well with more than 50 features. Perform "
                         "further dimensionality reduction (e.g.PCA) before t-SNE plot.")

    tsne_algo = TSNE(n_components=n_components, perplexity=perplexity,
                                early_exaggeration=early_exaggeration, learning_rate=learning_rate, n_iter=n_iter,
                                metric=metric, init=init,
                                random_state=random_state)

    y = tsne_algo.fit_transform(density_contrasts_with_label[:, :-1])
    labeled_features_two_dimensions = np.column_stack((y, density_contrasts_with_label[:, -1]))
    return labeled_features_two_dimensions

def split_features_in_and_out(features_with_label):
    """Split labeled features ndarray in two ndarrays, features of 'in' particles and features of 'out' particles."""

    features_in = features_with_label[features_with_label[:, -1] == 1]
    features_out = features_with_label[features_with_label[:, -1] == -1]
    return features_in, features_out

def get_tsne_plot(features_with_label, n_components=2, perplexity=50.0,
                  early_exaggeration=4.0, learning_rate=1000.0, n_iter=1000,
                  metric="euclidean", init="random",
                  random_state=None, title=False):
    """
    Returns t-sne plot given a set of labeled features and t-SNE hyperparameters.
    It reduces the feature space to two-dim (see :func:`reduce_features_in_two_dimensions_using_tsne`),
    it splits the features in the two classes (see :func:`split_features_in_and_out`)
    and it gives the t-SNE plot using :func:`plot_tsne_features` in :mod:`plot`.
    """
    features_tsne = reduce_features_in_two_dimensions_using_tsne(features_with_label,
                                                                 n_components=n_components, perplexity=perplexity,
                                                                 early_exaggeration=early_exaggeration,
                                                                 learning_rate=learning_rate, n_iter=n_iter,
                                                                 metric=metric, init=init,
                                                                 random_state=random_state)
    features_in, features_out = split_features_in_and_out(features_tsne)

    fig = plot.plot_tsne_features(features_in, features_out)
    number_of_particles = len(features_tsne)
    number_of_filters = features_with_label.shape[1]-1

    if title is True:
        fig.suptitle("t-SNE of " + str(number_of_filters) +
                     " features for " + str(number_of_particles) + " particles")
    return fig


import  xlrd
class read:
    def get_msg(self):
        book=xlrd.open_workbook(r'D:\shuju.xlsx')
        sheet=book.sheets()[0]
        return sheet
if __name__=='__main__':
    s=read().get_msg()
    # print(s)
    # print(s.nrows)
    # print(s.cell(3,1).value)

    for i in range(s.nrows):
        # for j in range(s.ncols):
            # print(s.cell(i,j).value,'\t',end='')
        # print('')
        li=s.row_values(i)
        print(li)


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

import os
import tkinter

if __name__ == "__main__":
    from Lobby.PongLobbyClient import LobbyClient
    from Lobby.Gui.join_game_dialog import JoinGameDialog
    from Lobby.Gui.create_match_dialog import CreateMatchDialog
else:
    from ..PongLobbyClient import LobbyClient
    from .join_game_dialog import JoinGameDialog
    from .create_match_dialog import CreateMatchDialog
    from Settings.utility import create_system_message

class ClientMainWindow(tkinter.Toplevel):
    """
    This class defines the client's most relevant window containing multiple buttons
    to interact with a lobby as well as a chat window to communicate with others
    """
    def __init__(self, menu=None):
        """
        Initializes a ClientMainWindow object
        :param menu: EntryWindow specifying the reference to the parent window
        """
        super().__init__()

        self.exists = True
        self.menu = menu
        self.selectedLobby = None
        self.supported_features = []

        #sets window title
        self.title('Pong Client')
        #sets background color
        self.configure(background = 'black')
        #sets little windowicon
        image = tkinter.PhotoImage(file=os.sep.join([os.path.dirname(__file__), 'pong_icon.png']), master=self)
        self.tk.call('wm', 'iconphoto', self._w, image)

        self.protocol('WM_DELETE_WINDOW', self.exit_window)

        """"HEADER FRAME"""
        self.headerFrame = tkinter.Frame(self, bg = 'black')

        #Welcome to the Pong Game Title Label
        self.titleLabel = tkinter.Label(self.headerFrame,
                                        bg = 'black',
                                        fg = 'white',
                                        font = ('Comic Sans MS', 15),
                                        text = "Welcome to the Pong Game-Client!")
        self.titleLabel.grid(row = 1, column = 1, columnspan = 3)

        #placeholder between Title Label and Name insertion
        self.placeholder1 = tkinter.Frame(self.headerFrame, bg = 'black', height = 10, width = 60)
        self.placeholder1.grid(row = 2, column = 1)

        #Name insertion descrition Label TODO: CURSOR BLINKING
        self.insertNameLabel = tkinter.Label(self.headerFrame,
                                             bg = 'black',
                                             fg = 'white',
                                             width = 20,
                                             font = ('Comic Sans MS', 15),
                                             text = "Chose your name: ",
                                             anchor = 'w')
        self.insertNameLabel.grid(row = 3, column = 1)

        #placeholder between Name insertion descriptor and entry Widget
        self.placeholder2 = tkinter.Frame(self.headerFrame, bg = 'black', height = 10, width = 60)
        self.placeholder2.grid(row = 3, column = 2)

        self.nameEntry = tkinter.Entry(self.headerFrame,
                                       font = ('Comic Sans MS', 15),
                                       fg = 'white',
                                       bg = 'gray12',
                                       width = 22,
                                       justify = 'center')

        self.nameEntry.grid(row = 3, column = 3)
        self.headerFrame.grid(row = 1, column = 1)

        """ SERVER FRAME """
        self.serverFrame = tkinter.Frame(self, bg = 'black')

        #placeholder between Header and Server Frame
        self.placeholder3 = tkinter.Frame(self.serverFrame, bg = 'black', height = 10, width = 10)
        self.placeholder3.grid(row = 1, column = 1)

        #placeholder between left border and search Server Button
        self.placeholder4 = tkinter.Frame(self.serverFrame, bg = 'black', width = 5, height = 2)
        self.placeholder4.grid(row = 2, column = 1)

        self.demo_var = tkinter.IntVar()
        self.demo_checkbox = tkinter.Checkbutton(self.serverFrame,
                                                            text = "Remote",
                                                            font = ('Comic Sans MS', 12),
                                                            bg = 'black',
                                                            fg = 'white',
                                                            selectcolor="black",
                                                            variable = self.demo_var,
                                                            onvalue = 1,
                                                            offvalue = 0)
        self.demo_checkbox.grid(row=2, column=2)

        #placeholder between checkbutton and search Server
        self.placeholder20 = tkinter.Frame(self.serverFrame, bg = 'black', width = 10, height = 2)
        self.placeholder20.grid(row = 2, column = 3)

        #search Server Button
        self.button_find_lobby = tkinter.Button(self.serverFrame,
                                                bg = 'gray10',
                                                fg = 'white',
                                                bd = 0,
                                                font = ('Comic Sans MS', 12),
                                                text = 'Find Lobby',
                                                activeforeground = 'thistle3',
                                                activebackground = 'black',
                                                command = self.find_lobbies)
        self.button_find_lobby.grid(row = 2, column = 4)

        #placeholder between search Server Button and connection Status Label
        self.placeholder5 = tkinter.Frame(self.serverFrame, bg = 'black', height = 12, width = 10)
        self.placeholder5.grid(row = 2, column = 5)

        #connection Status Label
        self.connectionStatLabel = tkinter.Label(self.serverFrame,
                                                 bg = 'black',
                                                 fg = 'red',
                                                 font = ('Comic Sans MS', 15),
                                                 text = 'Connection status:')
        self.connectionStatLabel.grid(row = 2, column = 6)

        #Label to show the actual connection Status
        self.vconnectionStatLabel = tkinter.Label(self.serverFrame,
                                              bg = 'black',
                                              fg = 'red',
                                              font = ('Comic Sans MS', 15),
                                              width = 15,
                                              text = 'no connection')
        self.vconnectionStatLabel.grid(row = 2, column = 7)

        """ LOBBYTABLE """

        self.lobbyTableFrame = tkinter.Frame(self.serverFrame, bg = 'black')

        #placeholder between Server Frame and Table Frame
        self.placeholder6 = tkinter.Frame(self.serverFrame, bg = 'black', height = 30, bd = 10)
        self.placeholder6.grid(row = 3, column = 1, columnspan = 3)

        self.lobbyTableFrame = tkinter.Frame(self.serverFrame, bg = 'black')

        headlineColor = 'gray25'

        #available Games Headrow
        self.lobbyHeadRowLabel1 = tkinter.Label(self.lobbyTableFrame,
                                           bg = headlineColor,
                                           fg = 'white',
                                           width = 15,
                                           font = ('Comic Sans MS', 12),
                                           text = 'Lobby IP')
        self.lobbyHeadRowLabel1.grid(row = 1, column = 1)

        #Features Headrow
        self.lobbyHeadRowLabel2 = tkinter.Label(self.lobbyTableFrame,
                                           bg = headlineColor,
                                           fg = 'white',
                                           width = 20,
                                           font = ('Comic Sans MS', 12),
                                           text = 'Lobby Port')
        self.lobbyHeadRowLabel2.grid(row = 1, column = 2)

        #Matrix of Buttons to appear in the Table
        self.lobbyButtonMatrix = []
        #list of the Colors of the row. 1 index represents 1 row
        self.lobbyColorList = []
        #Matrix of strings on the Buttons (Variable due to Game creation)
        self.lobbyContentMatrix = []

        self.lobbyTableFrame.grid(row = 4, column = 1, columnspan = 10)

        """CONNECTBUTTONFRAME"""

        self.connectBtnFrame = tkinter.Frame(self.serverFrame, bg = 'black')

        self.placeholder7 = tkinter.Frame(self.connectBtnFrame, bg = 'black', height = 10, bd = 10)
        self.placeholder7.grid(row = 1, column = 1)

        self.joinLobbyBtn = tkinter.Button(self.connectBtnFrame,
                                           bg = 'gray10',
                                           fg = 'white',
                                           bd = 0,
                                           font = ('Comic Sans MS', 12),
                                           text = 'Join Lobby',
                                           width = 20,
                                           height = 1,
                                           #state = 'disabled',
                                           activeforeground = 'thistle3',
                                           activebackground = 'black',
                                           command = self.join_lobby)

        self.joinLobbyBtn.grid(row = 2, column = 1)

        self.placeholder8 = tkinter.Frame(self.connectBtnFrame, bg = 'black', height = 15, bd = 10)
        self.placeholder8.grid(row = 3, column = 1)

        self.connectBtnFrame.grid(row = 5, column = 1, columnspan = 10)

        self.serverFrame.grid(row = 2, column = 1)

        """TABLE FRAME"""
        #mainFrame of the table (size adapts to the game List)
        self.tableFrame = tkinter.Frame(self, bg = 'gray8')
        headlineColor = 'gray25'
        #available Games Headrow
        self.headRowLabel1 = tkinter.Label(self.tableFrame,
                                           bg = headlineColor,
                                           fg = 'white',
                                           width = 15,
                                           font = ('Comic Sans MS', 12),
                                           text = 'Match name')
        self.headRowLabel1.grid(row = 1, column = 1)

        #Features Headrow
        self.headRowLabel2 = tkinter.Label(self.tableFrame,
                                           bg = headlineColor,
                                           fg = 'white',
                                           width = 20,
                                           font = ('Comic Sans MS', 12),
                                           text = 'Features')
        self.headRowLabel2.grid(row = 1, column = 2)

        #Matrix of Buttons to appear in the Table
        self.buttonMatrix = []
        #list of the Colors of the row. 1 index represents 1 row
        self.colorList = []
        #Matrix of strings on the Buttons (Variable due to Game creation)
        self.contentMatrix = []
        #selected game to join next:
        self.selectedGame = None

        self.update_table()

        self.tableFrame.grid(row = 3, column = 1)

        """BUTTON FRAME"""
        self.buttonFrame = tkinter.Frame(self, bg = 'black')

        #placeholder between Table and Buttons
        self.placeholder9 = tkinter.Frame(self.buttonFrame, bg = 'black', height = 20, bd = 10)
        self.placeholder9.grid(row = 1, column = 1)

        #refresh-Table Button
        self.refreshTableBtn = tkinter.Button(self.buttonFrame,
                                              bg = 'gray10',
                                              fg = 'white',
                                              bd = 0,
                                              width = 12,
                                              font = ('Comic Sans MS', 12),
                                              text = 'Refresh',
                                              activeforeground = 'thistle3',
                                              activebackground = 'black',
                                              state='disabled',
                                              command = self.refresh_table)
        self.refreshTableBtn.grid(row = 2, column = 2)

        #placeholder between refresh Table and join Game Button
        self.placeholder10 = tkinter.Frame(self.buttonFrame, bg = 'black', width = 20, bd = 10)
        self.placeholder10.grid(row = 2, column = 3)

        #Button that opens the join Game Dialog
        self.joinGameBtn = tkinter.Button(self.buttonFrame,
                                          bg = 'gray10',
                                          fg = 'white',
                                          bd = 0,
                                          width = 12,
                                          font = ('Comic Sans MS', 12),
                                          text = 'Join',
                                          activeforeground = 'thistle3',
                                          activebackground = 'black',
                                          state='disabled',
                                          command = self.join_match)
        self.joinGameBtn.grid(row = 2, column = 6)

        #placeholder between join Game and create Game Button
        self.placeholder11 = tkinter.Frame(self.buttonFrame, bg = 'black', width = 20, bd = 10)
        self.placeholder11.grid(row = 2, column = 5)

        self.leaveGameBtn = tkinter.Button(self.buttonFrame,
                                           bg = 'gray10',
                                           fg = 'white',
                                           bd = 0,
                                           width = 12,
                                           font = ('Comic Sans MS', 12),
                                           text = 'Leave',
                                           activeforeground = 'thistle3',
                                           activebackground = 'black',
                                           state='disabled',
                                           command = self.leave_game)
        self.leaveGameBtn.grid(row = 2, column = 8)

        self.placeholder13 = tkinter.Frame(self.buttonFrame, bg = 'black', width = 20, bd = 10)
        self.placeholder13.grid(row = 2, column = 7)

        self.createGameBtn = tkinter.Button(self.buttonFrame,
                                            bg = 'gray10',
                                            fg = 'white',
                                            bd = 0,
                                            width = 12,
                                            font = ('Comic Sans MS', 12),
                                            text = 'Create',
                                            activeforeground = 'thistle3',
                                            activebackground = 'black',
                                            state='disabled',
                                            command = self.create_match)
        self.createGameBtn.grid(row = 2, column = 4)

        self.placeholder8 = tkinter.Frame(self.buttonFrame, bg = 'black', height = 20)
        self.placeholder8.grid(row = 3, column = 1)

        self.iamreadyBtn = tkinter.Button(self.buttonFrame,
                                          bg = 'gray10',
                                          fg = 'white',
                                          bd = 0,
                                          width = 18,
                                          font = ('Comic Sans MS', 12),
                                          text = 'Ready?',
                                          activeforeground = 'thistle3',
                                          activebackground = 'black',
                                          state='disabled',
                                          command = self.i_am_ready)

        self.iamreadyBtn.grid(row = 4, column = 1, columnspan = 8)

        self.buttonFrame.grid(row = 4, column = 1)

        """"BOTTOM FRAME"""

        self.bottomFrame = tkinter.Frame(self, bg = 'black')

        self.exitButton = tkinter.Button(self.bottomFrame,
                                         bg = 'gray10',
                                         fg = 'white',
                                         bd = 0,
                                         width = 16,
                                         font = ('Comic Sans MS', 12),
                                         text = 'Exit',
                                         activeforeground = 'thistle3',
                                         activebackground = 'black',
                                         command = self.exit_window)
        self.exitButton.grid(row = 2, column = 1)

        self.bottomFrame.grid(row = 6, column = 1)

        """CHAT FRAME"""

        self.chatFrame = tkinter.Frame(self, bg = 'black')

        #Chat Title Label
        self.chatTitle = tkinter.Label(self.chatFrame,
                                             bg = 'black',
                                             fg = 'white',
                                             width = 40,
                                             font = ('Comic Sans MS', 15),
                                             text = "Chat ",
                                             anchor = 'w')

        #Chat Textbox to see Mesages
        self.chatTextBox = tkinter.Text(self.chatFrame,
                                        bg = 'gray39',
                                        height = 6,
                                        width = 85,
                                        font =('Times', 10),
                                        state="disabled")

        #Chat scrollbar to scroll through Messages
        self.chatScrollbar = tkinter.Scrollbar(self.chatFrame)

        self.chatTextBox.config(yscrollcommand = self.chatScrollbar.set)
        self.chatScrollbar.config(command = self.chatTextBox.yview)

        self.placeholder12 = tkinter.Frame(self.chatFrame, bg = 'black', height = 5, bd = 10)

        self.chatEntryLabel = tkinter.Label(self.chatFrame,
                                        bg = 'black',
                                        fg = 'white',
                                        font = ('Comic Sans MS', 15),
                                        text = "Entry: ",
                                        anchor = 'w')

        self.chatEntry = tkinter.Entry(self.chatFrame,
                                       font = ('Times', 12),
                                       fg = 'black',
                                       bg = 'gray45',
                                       width = 55,
                                       justify = 'center')

        self.chatEntry.bind('<Return>', self.send_chat_message)

        self.chatTitle.grid(row = 1, column = 1, columnspan = 3)
        self.chatTextBox.grid(row = 2, column = 1, columnspan = 2)
        self.chatScrollbar.grid(row = 2, column = 3, sticky = 'nse')
        self.placeholder12.grid(row = 3, column = 1)
        self.chatEntryLabel.grid(row = 4, column = 1)
        self.chatEntry.grid(row = 4, column = 2)

        self.chatFrame.grid(row = 5, column = 1)

        self.joinGameBtn.config(state='disabled')
        self.refreshTableBtn.config(state='disabled')
        self.createGameBtn.config(state='disabled')
        self.joinLobbyBtn.config(state='disabled')
        self.createGameBtn.config(state='disabled')
        self.chatEntry.config(state='disabled')

    def find_lobbies(self):
        """
        Invokes UDP broadcast/message and displays current lobby pool
        :return: None
        """
        lobbies = LobbyClient.discover_lobby(True if self.demo_var.get() else False)
        self.remove_all_lobbies()
        if lobbies:
            for ip, port in lobbies:
                self.add_lobby(ip, port)
            self.joinLobbyBtn.config(state='normal')
        else:
            self.joinLobbyBtn.config(state='disabled')
        self.update_lobby_table()

    def set_connection_stat(self, status, addr=None):
        """
        manipulates the connection status Label according to status
        :param status: Integer specifying the connection state
        :param addr: Tuple of (String, Integer) specifying an address pair (IP, port)
        :return: None
        """
        if status == 0 and addr:
            self.connectionStatLabel.config(fg='green')
            self.vconnectionStatLabel.config(fg='green', text=addr[0])
        elif status == 1:
            self.connectionStatLabel.config(fg='yellow')
            self.vconnectionStatLabel.config(fg='yellow', text='Searching...')
        elif status == 2:
            self.connectionStatLabel.config(fg='red')
            self.vconnectionStatLabel.config(fg='red', text='No connection')
        elif status == 3:
            self.connectionStatLabel.config(fg='red')
            self.vconnectionStatLabel.config(fg='red', text='Timeout')
        else:
            raise NotImplementedError("only values between 0 and 3 are valid")

    def highlight_row(self, row):
        """
        Button callback of the Buttons inside the Table.
        highlights the buttons inside the clicked row.
        :param row: Integer specifying the row number
        :return: None
        """
        for i in range(len(self.buttonMatrix)):
            if i == row:
                for j in range(2):
                    self.buttonMatrix[i][j].config(bg = 'gray40', activebackground = 'gray40')
            else:
                for j in range(2):
                    self.buttonMatrix[i][j].config(bg = self.colorList[i], activebackground = self.colorList[i])

        self.selectedGame = self.contentMatrix[row]

    def add_game(self, name, features ='N/A'):
        """
        Adds a match to the contentMatrix
        :param name: String specifying the name of the match
        :param features: String specifying a comma-separated list of feature parameters
        :return: None
        """
        self.contentMatrix.append([])
        i = len(self.contentMatrix) - 1
        self.contentMatrix[i].append(tkinter.StringVar())
        self.contentMatrix[i][0].set(name)
        self.contentMatrix[i].append(tkinter.StringVar())
        self.contentMatrix[i][1].set(features)

    def remove_match(self, name):
        """
        Checks for the specified name in the content table and removes the whole row
        :param name: String specifying the name of the match
        :return: Boolean which is True if an element was removed
        """
        for i in range(len(self.contentMatrix)):
            if self.contentMatrix[i][0].get() == name:
                self.contentMatrix.pop(i)
                return True
        return False

    def update_table(self):
        """
        Updates the Table strictly according to the contentMatrix
        :return: None
        """
        for i, v in enumerate(self.buttonMatrix):
            for j in range(2):
                self.buttonMatrix[i][j].destroy()
        self.buttonMatrix = []

        color1 = 'gray14'
        color2 = 'gray10'
        size_list = [15,20,15,10]

        for i in range(len(self.contentMatrix)):
            self.buttonMatrix.append(list())
            self.colorList.append('')
            self.colorList[i] = color1 if i%2==0 else color2

            for j in range(2):
                self.buttonMatrix[i].append(tkinter.Button(self.tableFrame,
                                                           text = self.contentMatrix[i][j].get(),
                                                           bg = self.colorList[i],
                                                           fg = 'white',
                                                           activebackground = self.colorList[i],
                                                           activeforeground = 'white',
                                                           bd = 0,
                                                           font = ('Comic Sans MS', 12),
                                                           width = size_list[j],
                                                           height = 1,
                                                           command = lambda current_i = i: self.highlight_row(current_i)))

                self.buttonMatrix[i][j].grid(row = i + 2, column = j + 1)
        self.tableFrame.grid(row = 3, column = 1)

    def refresh_table(self):
        """
        Callback function for the refresh-Button
        :return: None
        """
        LobbyClient.execute_command('/list_matches pong')
        self.contentMatrix = []
        for i in LobbyClient.get_open_matches():
            LobbyClient.execute_command('/match_features {}'.format(i))
            feature = ",".join(LobbyClient.get_features())
            self.add_game(i, features=feature)
        self.update_table()

    def join_match(self):
        """
        Callback function for the join Game Button
        :return: None
        """
        if self.selectedGame:
            joinDlg = JoinGameDialog(self, self.selectedGame)

    def button_state_joined_match(self):
        """
        Sets the buttons to the correct button state
        :return: None
        """
        self.button_find_lobby.config(state="disabled")
        self.joinLobbyBtn.config(state="disabled")
        self.joinGameBtn.config(state="disabled")
        self.createGameBtn.config(state="normal")
        self.refreshTableBtn.config(state="normal")
        self.iamreadyBtn.config(state="normal")
        self.leaveGameBtn.config(state="normal")

    def create_match(self):
        """
        Callback function for the join Game Button
        :return: None
        """
        createMatchDlg = CreateMatchDialog(self, self.supported_features)

    def exit_window(self):
        """
        Stops the chat update loop and closes itself correctly
        :return: None
        """
        if hasattr(self, 'chat_update'):
            self.after_cancel(self.chat_update)
        if __name__ == "__main__":
            self.destroy()
        else:
            if self.menu is not None:
                self.menu.toggle_client()

    def close_window(self):
        LobbyClient.end_client()
        if self.exists:
            self.exists = False
            self.destroy()

    """LOBBY FUNCTIONS"""

    def add_lobby(self, IP, port):
        """
        Adds a lobby to the lobbyContentMatrix
        :param IP: String specifying the IP address
        :param port: Integer specifying the port number
        :return: None
        """
        self.lobbyContentMatrix.append([])
        i = len(self.lobbyContentMatrix) - 1
        self.lobbyContentMatrix[i].append(tkinter.StringVar())
        self.lobbyContentMatrix[i][0].set(IP)
        self.lobbyContentMatrix[i].append(tkinter.IntVar())
        self.lobbyContentMatrix[i][1].set(port)

    def remove_all_lobbies(self):
        """
        Empty the lobby content matrix containing the lobby information
        :return: None
        """
        self.lobbyContentMatrix = []

    def update_lobby_table(self):
        """
        Updates the lobby table strictly according to the lobbyContentMatrix
        :return: None
        """
        self.lobbyButtonMatrix.clear()

        color1 = 'gray14'
        color2 = 'gray10'
        size_list = [15, 20, 15, 10]

        for i in range(len(self.lobbyContentMatrix)):
            self.lobbyButtonMatrix.append(list())
            self.lobbyColorList.append('')
            self.lobbyColorList[i] = color1 if i % 2 == 0 else color2
            for j in range(2):
                self.lobbyButtonMatrix[i].append(tkinter.Button(self.lobbyTableFrame,
                                                                text = self.lobbyContentMatrix[i][j].get(),
                                                                bg = self.lobbyColorList[i],
                                                                fg = 'white',
                                                                activebackground = self.lobbyColorList[i],
                                                                activeforeground = 'white',
                                                                bd = 0,
                                                                font = ('Comic Sans MS', 12),
                                                                width = size_list[j],
                                                                height = 1,
                                                                command = lambda current_i = i: self.highlight_lobby_row(current_i)))
                self.lobbyButtonMatrix[i][j].grid(row = i + 2, column = j + 1)
        self.lobbyTableFrame.grid(row = 4, column = 1, columnspan = 10)

    def highlight_lobby_row(self, row):
        """
        Button callback of the Buttons inside the Table.
        highlights the buttons inside the clicked row.
        saves the selected row index into self.selectedLobby
        :param row: Integer specifying the row to highlight
        :return: None
        """
        for i in range(len(self.lobbyButtonMatrix)):
            if i == row:
                for j in range(2):
                    self.lobbyButtonMatrix[i][j].config(bg='gray40', activebackground='gray40')
            else:
                for j in range(2):
                    self.lobbyButtonMatrix[i][j].config(bg=self.lobbyColorList[i], activebackground=self.lobbyColorList[i])

        self.selectedLobby = self.lobbyContentMatrix[row]

    def join_lobby(self):
        """
        Callback function for the 'join Lobby' Button
        :return: None
        """
        if self.selectedLobby:
            self.forbid_name_change()

    def forbid_name_change(self):
        """
        Disables name entry and remote checkbox
        :return: None
        """
        self.nameEntry.config(state='disabled')
        self.demo_checkbox.config(state='disabled')
        self.after(1, self.check_name)

    def check_name(self):
        """
        Checks if name is provided
        :return: None
        """
        if self.nameEntry.get():
            self.insertNameLabel.config(fg='white')
            self.nameEntry.after(1, self.handshake)
        else:
            self.insertNameLabel.config(fg='red')
            self.set_connection_stat(2, '')
            self.nameEntry.config(state='normal')
            self.demo_checkbox.config(state='normal')

    def handshake(self):
        """
        Performs TCP handshake with lobby server
        :return: None
        """
        addr, self.supported_features = LobbyClient.connect_to_lobby(self.nameEntry.get(), tuple([i.get() for i in self.selectedLobby]), self)
        if addr:
            # set Status Label on OK
            self.set_connection_stat(0, addr)
            self.joinGameBtn.config(state='normal')
            self.refreshTableBtn.config(state='normal')
            self.createGameBtn.config(state='normal')
            self.chatEntry.config(state='normal')
            self.after(1, self.update_chat)
        else:
            # set Status Label on NO Connection
            self.set_connection_stat(2, '')
            self.nameEntry.config(state='normal')
            self.demo_checkbox.config(state='normal')

    def send_chat_message(self, event):
        """
        Reads user input from entry box and sends it as chat message to server
        :param event: Event specifying the pressed key (mandatory parameter)
        :return: None
        """
        message = self.chatEntry.get()
        self.chatEntry.delete(0, tkinter.END)
        LobbyClient.execute_command(message)

    def display_chat_message(self, message):
        """
        Write a message to the chat box
        :param message: String specfying the message to write
        :return: None
        """
        self.chatTextBox.config(state="normal")
        self.chatTextBox.insert(tkinter.END, message + '\n')
        self.chatTextBox.see(tkinter.END)
        self.chatTextBox.config(state="disabled")

    def update_chat(self):
        """
        Updates the chat with new messages and starts update loop
        :return: None
        """
        if self.exists:
            new_messages = LobbyClient.get_chat()
            for i in new_messages:
                self.display_chat_message(i)
            self.chat_update = self.after(1000, self.update_chat)

    def leave_game(self):
        """
        Leaves the currently joined game and adjusts usable buttons
        :return: None
        """
        LobbyClient.execute_command('/leaving_match User left match')
        self.display_chat_message(create_system_message('You left the match.'))
        self.after(1, self.button_state_left_game)

    def button_state_left_game(self):
        """
        Sets all buttons to the correct button state
        :return: None
        """
        self.button_find_lobby.config(state="normal")
        self.joinLobbyBtn.config(state="normal")
        self.joinGameBtn.config(state="normal")
        self.createGameBtn.config(state="normal")
        self.refreshTableBtn.config(state="normal")
        self.iamreadyBtn.config(state="disabled", text="Ready?")
        self.leaveGameBtn.config(state="disabled")

    def i_am_ready(self):
        """
        Signals the server that the user is ready and adjusts usable buttons
        :return: None
        """
        LobbyClient.execute_command('/i_am_ready')
        self.after(1, self.button_state_ready)

    def button_state_ready(self):
        """
        Sets all buttons to the correct button state
        :return: None
        """
        self.button_find_lobby.config(state="disabled")
        self.joinLobbyBtn.config(state="disabled")
        self.joinGameBtn.config(state="disabled")
        self.createGameBtn.config(state="disabled")
        self.refreshTableBtn.config(state="disabled")
        self.iamreadyBtn.config(state="disabled", text="Ready!")
        self.leaveGameBtn.config(state="normal")

if __name__ == "__main__":

    a = ClientMainWindow()
    a.mainloop()


import os
from typing import List, Tuple

from nazurin.models import Caption, Illust, Image
from nazurin.utils import Request
from nazurin.utils.exceptions import NazurinError

class Twitter(object):
    async def getTweet(self, status_id: int):
        """Get a tweet from API."""
        # Old: 'https://syndication.twitter.com/tweets.json?ids='+ status_id +'&lang=en'
        api = 'https://cdn.syndication.twimg.com/tweet?id=' + str(
            status_id) + '&lang=en'
        async with Request() as request:
            async with request.get(api) as response:
                if response.status == 404:
                    raise NazurinError('Tweet not found or unavailable.')
                tweet = await response.json()
                return tweet

    async def fetch(self, status_id: int) -> Illust:
        """Fetch & return tweet images and information."""
        tweet = await self.getTweet(status_id)
        imgs = self.getImages(tweet)
        caption = self.buildCaption(tweet)
        return Illust(imgs, caption, tweet)

    def getImages(self, tweet) -> List[Image]:
        """Get all images in a tweet."""
        if 'photos' not in tweet.keys():
            raise NazurinError('No photo found.')
        photos = tweet['photos']
        imgs = list()
        for photo in photos:
            filename, url, thumbnail = self.parseUrl(photo['url'])
            imgs.append(
                Image('twitter - ' + tweet['id_str'] + ' - ' + filename,
                      url,
                      thumbnail,
                      width=photo['width'],
                      height=photo['height']))
        return imgs

    def buildCaption(self, tweet) -> Caption:
        return Caption({
            'url': f"https://twitter.com/{tweet['user']['screen_name']}/status/{tweet['id_str']}",
            'author': f"{tweet['user']['name']} #{tweet['user']['screen_name']}",
            'text': tweet['text']
        })

    def parseUrl(self, src: str) -> Tuple[str, str, str]:
        """Get filename, original file url & thumbnail url of the original image

        eg:

            src: 'https://pbs.twimg.com/media/DOhM30VVwAEpIHq.jpg'

            return: 'DOhM30VVwAEpIHq.jpg', 'https://pbs.twimg.com/media/DOhM30VVwAEpIHq?format=jpg&name=orig', 'https://pbs.twimg.com/media/DOhM30VVwAEpIHq?format=jpg&name=large'

        Doc: https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/entities-object
        """
        basename = os.path.basename(src)
        filename, extension = os.path.splitext(basename)
        url = 'https://pbs.twimg.com/media/' + filename + '?format=' + extension[
            1:]
        return basename, (url + '&name=orig'), (url + '&name=large')


"main rendering script"

import os
from math import cos, pi, sin

import matplotlib.pyplot as plt
from direct.actor.Actor import Actor
from direct.interval.IntervalGlobal import Sequence
from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from panda3d.core import Filename, Material, NodePath, Point3

class renderEngine(ShowBase):
    """
    the main renderer for pandas

    the costom rendering engien parameters
    """
    def __init__(self, higthMap):
        ShowBase.__init__(self)
        "initate pandas"

        self.boxes = []
        """a 3d list containning the rendered boxes"""
        self.gems = []
        """a 1d list containing the gem actors"""
        self.showHigtMap(higthMap)
        # set inital camera location
        self.camera.setPos(0,0,1000)

    def showHigtMap(self, hightMap):
        """create render objects from hightmap

        given a hightmap the function crates cubes stackt on top of each other to render the board
        for every position in the hightmap
        its not very optimized

        will alsow create list of gems called gems and add them bla bla bla

        @param hightmap: the hightmap we get render data from
        @type hightmap: hightmap object
        """
        #create every box and write it to boxes simultainously generate the box list using append
        for x in range(hightMap._arr.shape[0]):
            self.boxes.append([])
            for y in range(hightMap._arr.shape[1]):
                self.boxes[-1].append([])
                for z in range(int(hightMap._arr[x,y]+1)):
                    #crate the actor
                    actor = loader.loadModel("models/box")
                    actor.setScale(1,1,1)
                    actor.setPos(x,y,z)
                    actor.setTexture(renderEngine.getBlockTex(hightMap,x, y,z),2)
                    # add actor to render tree
                    actor.reparentTo(self.render)

        #crate the gems
        for x, y in hightMap.gemPoses:
            try:
                z = hightMap._arr[x,y]
            except:
                print(f"invalid gem location, location is {x}, {y} of map of shape {hightMap._arr.shape}")

            gemActor = loader.loadModel("models/smiley")
            gemActor.setPos(x+.5,y+.5,z+1.5)
            gemActor.setScale(.5,.5,.5)
            gemActor.reparentTo(self.render)
            self.gems.append(gemActor)

    @staticmethod
    def getBlockTex(hightmap, *loc):
        """returns the texture of the block

        given the position and hmap we crate a pandas texture to set the actor to
        this is an indev function and is subject to change

        @param hightmap: the hmap data to get data from
        @type hightmap: higthmap

        @param loc: the position of the block whos tex wer setting
        @type loc: 3 intagers

        @return: a pandas3d texture for the objects
        """
        # get panda path of this files dir
        path = Filename.fromOsSpecific(os.path.dirname(os.path.abspath(__file__)))
        # get witch text to load
        # it top most block make grass else dirt and bottom most wather
        imag = "wather" if loc[-1] == 0 else ("grass" if loc[-1] == hightmap[loc[:-1]] else "dirt")
        tex  = loader.loadTexture(f"{path}/blocks/{imag}.jpg")
        return tex

    def addPawn(self, pawn):
        """add a pawn to render scene using its actor to represent it

        @param pawn: the pawn to be added
        @type pawn: a pawn object defined int pawns.pawn
        """
        pawn.actor.reparentTo(self.render)
        pawn._setPawnLoc(pawn.pos)
        pawn._setPawnRenderRotation()


from bs4 import BeautifulSoup
import requests
import os
import codecs
class PageCheck:

    def __init__(self,url):
        self.url=url

    def pageExiste(self):
        existe=False
        response=requests.get(self.url)
        status_code=response.status_code
        if (status_code==200):
            regex=self.url.split(".")
            if "wikipedia" in regex:
                existe=True

        return existe

    def urlChek(self):
        regex1=self.url.split(":")
        regex=" ".join(regex1)
        if(regex.startswith("https")==False):
            urlp="https://en.wikipedia.org/wiki/"+ self.url

        elif(self.pageExiste()):
            urlp=self.url
        else:
            urlp=" "
        return urlp


"""
Synthetic and Endogenous RSS Dwell Time Distributions
--------------------------------------------------------------------------------
Authors: Soichi Hirokawa and Griffin Chure
Last Modified: September 25, 2019
License: MIT

Description
--------------------------------------------------------------------------------
This script generates a figure of representative dwell time distributions for
a variety of synthetic and endogenous RSS sequences, along with the credible
regions from fitting of a single exponential to the distribution.

Notes
--------------------------------------------------------------------------------
This script is designed to be run from the `code/figures` directory and uses a relative path to the `data` folder to access the appropriate CSV files.
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats
import vdj.io
import vdj.viz
vdj.viz.plotting_style()

#%%
# load the dwell time data
data = pd.read_csv('../../data/compiled_dwell_times.csv', comment='#')
data = data[(data['salt']=='Mg') & (data['hmgb1']==80)]

# Load the fitting statistics.
samps = pd.read_csv('../../data/exponential_fitting_samples.csv',
                    comment='#')
samps = samps[samps['salt']=='Mg']
stats = pd.read_csv('../../data/exponential_fitting_summary.csv',
                    comment='#')
stats = stats[stats['salt']=='Mg']

# select only the mutants of interest
endogenous = ['WT12rss', 'V19-93', 'V5-43']
heptamer = ['12HeptC3T', '12HeptA4T', '12HeptG7A']
spacer = ['12SpacC4T', '12SpacG11T', '12SpacA12C']
nonamer = ['12NonA1G', '12NonA3C', '12NonC8G']

rows = [endogenous, heptamer, spacer, nonamer]
colors = ['gray', 'tomato', 'dodgerblue', 'rebeccapurple']
DEADFILTER = 21 / 60 # Deadfilter of 21 seconds for shortest PC
time = np.linspace(0, 60, 500) -  DEADFILTER

#%%
# Set up the figure canvas
fig, ax = plt.subplots(4, 3, figsize=(4.5, 5), sharex=True, sharey=True)

# Format the axes
for a in ax.ravel():
    a.xaxis.set_tick_params(labelsize=8)
    a.yaxis.set_tick_params(labelsize=8)
    a.set_xscale('log')
    a.set_ylim([0, 1.1])
    a.set_xlim([DEADFILTER, 80])

# Add axis labels
for i in range(3):
    ax[-1,i].set_xlabel('dwell time [min]', fontsize=8)
for i in range(4):
    ax[i, 0].set_ylabel('cumulative\ndistribution', fontsize=8)

# Add row labels.
fig.text(-0.05, 0.85, 'Endogenous', rotation='vertical', color='slategrey',
         fontsize=9)
fig.text(-0.05, 0.62, 'Heptamer', rotation='vertical', color='tomato',
         fontsize=9)
fig.text(-0.05, 0.4, 'Spacer', rotation='vertical', color='dodgerblue',
         fontsize=9)
fig.text(-0.05, 0.22, 'Nonamer', rotation='vertical', color='rebeccapurple',
         fontsize=9)
fig.text(-0.12, 0.87, '(A)', fontsize=9)
fig.text(-0.12, 0.67, '(B)', fontsize=9)
fig.text(-0.12, 0.47, '(C)', fontsize=9)
fig.text(-0.12, 0.27, '(D)', fontsize=9)

# Plot the observed dwell times.
for i, row in enumerate(rows):
    for j, mut in enumerate(row):
        # Isolate the mutant
        mut_data = data[data['mutant']==mut]
        mut_stats = stats[stats['mutant']==mut]
        low = mut_stats[mut_stats['parameter']=='tau']['hpd_min'].values[0]
        high = mut_stats[mut_stats['parameter']=='tau']['hpd_max'].values[0]

        # Compute the empirical CDF
        x = list(np.sort(mut_data['dwell_time_min'] - DEADFILTER))
        y = list(np.arange(0, len(x), 1) / len(x))
        x.append(x[-1])
        y.append(1)
        # Plot the steps.
        ax[i, j].step(x, y, color='k', lw=1)

        # Compute the fit
        low= 1 - np.exp(-(time - DEADFILTER)/low)
        high = 1 - np.exp(-(time - DEADFILTER)/high)
        ax[i, j].fill_between(time, low, high, color=colors[i], alpha=0.5)

        # Add the titles
        if mut == 'WT12rss':
            title = 'V4-57-1'
        if 'Hept' in mut:
            title = f"Heptamer {mut.split('Hept')[-1]}"
        elif 'Spac' in mut:
            title = f'Spacer {mut.split("Spac")[-1]}'
        elif 'Non' in mut:
            title = f'Nonamer {mut.split("Non")[-1]}'
        else:
            title = mut
        ax[i, j].set_title(title, fontsize=8, y=0.95)

ax[0,0].set_title('V4-57-1', fontsize=8, y=0.95)
plt.savefig('../../figures/Fig_nonexponential_distributions.pdf',
            facecolor='white', bbox_inches='tight')