import numpy as np

# MAX_BRIGHTNESS = 255
MA4_SIZE = 4

uch_spo2_table =   [95, 95, 95, 96, 96, 96, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 99, 99, 99, 99,
                    99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
                    100, 100, 100, 100, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 97, 97,
                    97, 97, 96, 96, 96, 96, 95, 95, 95, 94, 94, 94, 93, 93, 93, 92, 92, 92, 91, 91,
                    90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 84, 84, 83, 82, 82, 81, 81,
                    80, 80, 79, 78, 78, 77, 76, 76, 75, 74, 74, 73, 72, 72, 71, 70, 69, 69, 68, 67,
                    66, 66, 65, 64, 63, 62, 62, 61, 60, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50,
                    49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 31, 30, 29,
                    28, 27, 26, 25, 23, 22, 21, 20, 19, 17, 16, 15, 14, 12, 11, 10, 9, 7, 6, 5,
                    3, 2, 1]

# def calculate(pun_ir_buffer, n_ir_buffer_length, pun_red_buffer, pn_spo2,pch_spo2_valid, pn_heart_rate, pch_hr_valid):
def calculate(pun_ir_buffer, pun_red_buffer, FS=25):
  BUFFER_SIZE = FS * 4
  # output var holders
  pn_spo2 = 0
  pn_heart_rate = 0

  # calculates DC mean and subtract DC from ir
  un_ir_mean = int(np.mean(pun_ir_buffer))

  # remove DC and invert signal so that we can use peak detector as valley detector
  an_x = (-1*(pun_ir_buffer - un_ir_mean)).astype(np.int32)

  # 4 pt Moving Average
  for k in range(BUFFER_SIZE - MA4_SIZE):
    an_x[k] = (an_x[k] + an_x[k+1] + an_x[k+2] + an_x[k+3]) / int(4)

  # calculate threshold
  n_th1 = int(np.mean(an_x))
  # min allowed
  if n_th1 < 30:
    n_th1 = 30

  # max allowed
  if n_th1 > 60:
    n_th1 = 60

  # an_ir_valley_locs = [0] * 15
  # since we flipped signal, we use peak detector as valley detector
  an_ir_valley_locs = maximFindPeaks(an_x, n_th1, 4, 15) # (input, peak_min_height, peaks_min_distance, max_peak_num)
  n_npks = len(an_ir_valley_locs)
  n_peak_interval_sum = 0
  if n_npks >= 2:
    for k in range(1, n_npks):
      n_peak_interval_sum += an_ir_valley_locs[k] - an_ir_valley_locs[k-1]
    n_peak_interval_sum = int(n_peak_interval_sum / (n_npks-1))
    pn_heart_rate = (int)((FS * 60) / n_peak_interval_sum)
  else:
    pn_heart_rate = float('nan') # unable to calculate because # of peaks are too small

  # load raw value again for SPO2 calculation : RED(=y) and IR(=X)
  an_x = pun_ir_buffer
  an_y = pun_red_buffer

  # find precise min near an_ir_valley_locs
  n_exact_ir_valley_locs_count = n_npks

  # using exact_ir_valley_locs , find ir-red DC and ir-red AC for SPO2 calibration an_ratio
  # finding AC/DC maximum of raw
  for k in range(n_exact_ir_valley_locs_count):
    if an_ir_valley_locs[k] > BUFFER_SIZE:
      pn_spo2 = float('nan') # do not use SPO2 since valley loc is out of range
      return pn_spo2, pn_heart_rate

  # find max between two valley locations
  # and use an_ratio betwen AC compoent of Ir & Red and DC compoent of Ir & Red for SPO2
  n_y_dc_max_idx = 0
  n_x_dc_max_idx = 0
  an_ratio = []
  n_i_ratio_count = 0
  for k in range(n_exact_ir_valley_locs_count - 1):
    n_y_dc_max = -16777216
    n_x_dc_max = -16777216
    if an_ir_valley_locs[k+1] - an_ir_valley_locs[k] > 3:
      for i in range(an_ir_valley_locs[k], an_ir_valley_locs[k+1]):
        if an_x[i] > n_x_dc_max:
          n_x_dc_max = an_x[i]
          n_x_dc_max_idx = i
        if (an_y[i] > n_y_dc_max):
          n_y_dc_max = an_y[i]
          n_y_dc_max_idx = i

      # Remove DC component from IR and RED raw
      n_y_ac = (an_y[an_ir_valley_locs[k+1]] - an_y[an_ir_valley_locs[k]]) * (n_y_dc_max_idx - an_ir_valley_locs[k]) # red
      n_y_ac =  int(an_y[an_ir_valley_locs[k]] + n_y_ac / (an_ir_valley_locs[k+1] - an_ir_valley_locs[k]))
      n_y_ac =  an_y[n_y_dc_max_idx] - n_y_ac # subracting linear DC compoenents from raw

      n_x_ac = (an_x[an_ir_valley_locs[k+1]] - an_x[an_ir_valley_locs[k]]) * (n_x_dc_max_idx - an_ir_valley_locs[k]) # ir
      n_x_ac =  int(an_x[an_ir_valley_locs[k]] + n_x_ac / (an_ir_valley_locs[k+1] - an_ir_valley_locs[k]))
      n_x_ac =  an_x[n_y_dc_max_idx] - n_x_ac # subracting linear DC compoenents from raw
      # print('n_ac: {}, {}'.format(n_y_ac, n_x_ac))
      n_nume = int((n_y_ac * n_x_dc_max) / 128) # prepare X100 to preserve floating value
      n_denom = int((n_x_ac * n_y_dc_max) / 128)

      if (n_denom > 0 and n_i_ratio_count < 5 and n_nume != 0):
        an_ratio.append(int((n_nume * 100) / n_denom)) # formular is ( n_y_ac *n _x_dc_max) / ( n_x_ac *n_y_dc_max) ;
        n_i_ratio_count += 1

  ## exit if empty findings
  if len(an_ratio) == 0:
    pn_spo2 = float('nan')
    return pn_spo2, pn_heart_rate
  # choose median value since PPG signal may varies from beat to beat
  maximSortAscend(an_ratio)
  # if len(an_ratio) != n_i_ratio_count: # sanity checks
  #   print 'WARN: an_ratio length ({}) != n_i_ratio_count ({})'.format(len(an_ratio), n_i_ratio_count)
  n_middle_idx = int(n_i_ratio_count / 2)

  n_ratio_average = 0
  if n_middle_idx > 1:
    n_ratio_average = int((an_ratio[n_middle_idx-1] + an_ratio[n_middle_idx]) / 2) # use median
  else:
    n_ratio_average = int(an_ratio[n_middle_idx])

  if n_ratio_average > 2 and n_ratio_average < 184:
    pn_spo2 = uch_spo2_table[n_ratio_average]
    # n_spo2_calc = uch_spo2_table[n_ratio_average]
    # pn_spo2 = n_spo2_calc
    # float_SPO2 =  -45.060*n_ratio_average* n_ratio_average/10000 + 30.354 *n_ratio_average/100 + 94.845 # for comparison with table
  else:
    pn_spo2 = float('nan') # do not use SPO2 since signal an_ratio is out of range
  # print('.. SPO2: {}'.format(pn_spo2))
  return pn_spo2, pn_heart_rate

# Find peaks: Find at most MAX_NUM peaks above MIN_HEIGHT separated by at least MIN_DISTANCE
# def maxim_find_peaks( pn_locs, n_npks, pn_x, n_size, n_min_height, n_min_distance, n_max_num ):
def maximFindPeaks(pn_x, n_min_height, n_min_distance, n_max_num):
  pn_locs = maximFindPeaksAboveMinHeight(pn_x, n_min_height)
  pn_locs = maximRemoveClosePeaks(pn_locs, pn_x, n_min_distance)
  return pn_locs[:n_max_num]

# Find peaks above n_min_height
# def maxim_peaks_above_min_height( pn_locs, n_npks, pn_x, n_size, n_min_height ):
def maximFindPeaksAboveMinHeight(pn_x, n_min_height):
  i = 1
  n_size = len(pn_x)
  n_width = 0
  n_npks = 0
  pn_locs = []
  while (i < n_size - 1):
    # if len(pn_locs) != n_npks: # sanity check
    #   print 'WARN: {} != {} in maximFindPeaksAboveMinHeight'.format(len(pn_locs), n_npks)
    if pn_x[i] > n_min_height and pn_x[i] > pn_x[i - 1]:              # find left edge of potential peaks
      n_width = 1
      while(i + n_width < n_size and pn_x[i] == pn_x[i + n_width]):   # find flat peaks
        n_width = n_width + 1
      if i + n_width >= 100:
        n_width = 99 - i
      if pn_x[i] > pn_x[i + n_width] and n_npks < 15:                 # find right edge of peaks
        pn_locs.append(i)
        n_npks += 1
        i += n_width + 1                                              # for flat peaks, peak location is left edge
      else:
        i += n_width
    else:
      i += 1
  return pn_locs

# Remove peaks: Remove peaks separated by less than MIN_DISTANCE
# def maxim_remove_close_peaks(pn_locs, pn_npks, pn_x, n_min_distance):
def maximRemoveClosePeaks(pn_locs, pn_x, n_min_distance):
  pn_npks = len(pn_locs)

  # Order peaks from large to small
  # maxim_sort_indices_descend(pn_x, pn_locs, pn_npks)
  maximSortIndicesDescend(pn_x, pn_locs)

  i = -1
  while i < pn_npks:
    n_old_npks = pn_npks
    pn_npks = i + 1
    for j in range(i + 1, n_old_npks):
      # lag-zero peak of autocorr is at index -1
      n_dist = pn_locs[j] - (-1 if i == -1 else pn_locs[i])
      if n_dist > n_min_distance or n_dist < -n_min_distance:
        pn_locs[pn_npks] = pn_locs[j]
        pn_npks += 1
    i += 1

  pn_locs = pn_locs[:pn_npks]

  # Resort indices int32_to ascending order
  maximSortAscend(pn_locs)
  return pn_locs

# Sort array: Sort array in ascending order (insertion sort algorithm)
# def maxim_sort_ascend(pn_x, n_size):
def maximSortAscend(pn_x):
  i = 0
  j = 0
  n_temp = 0
  for i in range(1, len(pn_x)):
    n_temp = pn_x[i]
    j = i
    while j > 0 and n_temp < pn_x[j-1]:
      pn_x[j] = pn_x[j-1]
      j = j - 1
    pn_x[j] = n_temp

# Sort indices: Sort indices according to descending order (insertion sort algorithm)
def maximSortIndicesDescend(pn_x, pn_locs):
  j = 0
  n_temp = 0
  for i in range(1, len(pn_locs)):
    n_temp = pn_locs[i]
    j = i
    while j > 0 and pn_x[n_temp] > pn_x[pn_locs[j-1]]:
      pn_locs[j] = pn_locs[j-1]
      j = j - 1
    pn_locs[j] = n_temp


"""
Test output selection.
"""

import numpy as np
import unittest

import andes

class TestOutput(unittest.TestCase):
    """
    Class for Output test.
    """

    def test_output_xyname(self):
        """
        Test x_name and y_name for Output
        """

        ss = andes.load(andes.get_case("5bus/pjm5bus.json"),
                        no_output=True,
                        setup=False,
                        default_config=True)

        ss.add("Output", {"model": "GENCLS", "varname": "omega"})
        ss.add("Output", {"model": "GENCLS", "varname": "delta", "dev": 2})
        ss.add("Output", {"model": "Bus"})

        ss.setup()

        ss.PFlow.run()
        ss.TDS.config.tf = 0.1
        ss.TDS.run()
        ss.TDS.load_plotter()

        nt = len(ss.dae.ts.t)
        nx = 5
        ny = 10

        self.assertEqual(len(ss.dae.x_name_output), nx)
        self.assertEqual(len(ss.dae.y_name_output), ny)

        self.assertEqual(ss.dae.ts.x.shape[1], nx)
        self.assertEqual(ss.dae.ts.y.shape[1], ny)

        np.testing.assert_array_equal(ss.Output.xidx, [1, 4, 5, 6, 7])
        np.testing.assert_array_equal(ss.Output.yidx, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

        # test loaded data by plot
        self.assertEqual(ss.TDS.plt._data.shape, (nt, nx + ny + 1))
        np.testing.assert_array_equal(
            ss.TDS.plt._process_yidx(ss.GENCLS.omega, a=None),
            [2, 3, 4, 5])

        np.testing.assert_array_equal(
            ss.TDS.plt._process_yidx(ss.GENCLS.delta, a=None),
            [1])

        np.testing.assert_array_equal(
            ss.TDS.plt._process_yidx(ss.TG2.pout, a=None),
            [])

        # test `DAE.ts.get_data`
        np.testing.assert_equal(
            ss.dae.ts.get_data(ss.GENCLS.omega, a=None).shape[1],
            4)

        np.testing.assert_equal(
            ss.dae.ts.get_data(ss.GENCLS.delta, a=None).shape[1],
            1)

        np.testing.assert_equal(
            ss.dae.ts.get_data(ss.TG2.pout, a=None).shape[1],
            0)


# # Dictionary to store already computed values
# memo = {}
# def threeFib(number):
#     if number in memo:
#         return memo[number]
#     if number == 0:
#         result = 0
#     elif number == 1:
#         result = 1
#     elif number == 2:
#         result = 1
#     else:
#         result = threeFib(number - 1) + threeFib(number - 2) + threeFib(number - 3)
#     memo[number] = result
#     return result
#
# printNumber = []
# num_test_cases = int(input("Enter the number of test cases: "))
# for _ in range(num_test_cases):
#     number = int(input("Enter the number to find in the threeFib sequence: "))
#     printNumber.append(threeFib(number))
# for i in printNumber:
#     print(i)

notcheck = {}
def ThreeFib(number):
    if number in notcheck:
        return notcheck[number]
    elif number == 0:
        result = 0
    elif number == 1:
        result = 1
    elif number ==  2:
        result = 1
    else:
        result = ThreeFib(number - 1) + ThreeFib(number - 2) + ThreeFib(number- 3)
    notcheck[number] = result
    return result

printNumber = []
for _ in range(int(input("Enter the number of test case: "))):
    number = int(input("Enter the number: "))
    printNumber.append(ThreeFib(number))

for i in printNumber:
    print(i)


from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

def paddingPKCS7(bytestr, size):
    i = size - (len(bytestr) % size)
    return bytestr + bytes([i] * i)

def padding_validation(text):
    i = text[-1]
    if bytes([i] * i) != text[-i:]:
        raise ValueError('{} bad padding'.format(text))
    return text[:-i]

def encrypt_ecb(plaintext, key, pad = True):
    if pad:
        plaintext = paddingPKCS7(plaintext, len(key))
    encrypt= Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()).encryptor()
    return encrypt.update(plaintext)

def decrypt_ecb(cipertext, key):
    decrypt = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()).decryptor()
    return padding_validation(decrypt.update(cipertext))

def test():
    key = b"YELLOW SUBMARINE"
    plaintext = b"this is a test"
    ciphertext = encrypt_ecb(plaintext, key)
    print(decrypt_ecb(ciphertext, key) == plaintext)

if __name__ == "__main__":
    test()


class Solution:
    """
    @param nums: a list of integers.
    @param k: length of window.
    @return: the sum of the element inside the window at each moving.
    """
    def winSum(self, nums, k):
        # write your code here
        if k > len(nums) or not nums:
            return []

        result = []
        sum = 0
        for i in range(0, k):
            sum += nums[i]
        result.append(sum)

        m = 0
        for j in range(k, len(nums)):
            sum = sum + nums[j] - nums[m]
            result.append(sum)
            m += 1
        return result


##******************* Import libaries *******************##
import imageio
import numpy as np
import matplotlib.pyplot as plt
import scipy
import scipy.signal
import math
import time

## ****************** Function ***********************##
# Function rgb to gray
# convert a RGB image to gray image
# Lizhong Wang 6 Feb
def rgb2gray(rgb_image):
    gray_image=1/3*rgb_image[:,:,0]+1/3*rgb_image[:,:,1]+1/3*rgb_image[:,:,2]
    #gray_image=1/3*gray_image;
    return gray_image

# Function 1 dimensional Gaussian filter generator(sigma)
# sigma is the size of Gaussian filter, larger sigma cause image more blurred
# Design the Gaussian filter
# Lizhong Wang 6 Feb
def gaussian_filter_1d(sigma):
    # sigma: the parameter sigma in the Gaussian kernel (unit: pixel)
    #
    # return: a 1D array for the Gaussian kernel
    N = 3*sigma*2+1
    pi = math.pi
    h = np.zeros([1,N])
    for i in range(N):
        h[0,i] = 1/((2*pi)**(1/2)*sigma)*math.exp(-((i-(N-1)/2)**2)/(2*sigma**2));
    h = h/np.sum(h)
    return h

# Function Canny edge detection(gray image input, sigma, threshold)
# Implementation of Canny edge detection
# gray image is size M x N x 1
# sigma is the size of Gaussian filter, larger sigma cause less details in coloring image
# threshold controls the noisy line, low value cause more noisy line
# Lizhong Wang 6 Feb
def Canny(input_directory, output_directory, sigma, threshold=5):
    # input image file
    image = imageio.imread(input_directory)
    image = rgb2gray(image)

    # Design the Prewitt filters
    prewitt_x = np.array([[1,0,-1],[1,0,-1],[1,0,-1]])
    prewitt_y = np.array([[1,1,1],[0,0,0],[-1,-1,-1]])

    # The Gaussian filter along x-axis. Its shape is (1, sz).
    h_x = gaussian_filter_1d(sigma)

    # The Gaussian filter along y-axis. Its shape is (sz, 1).
    h_y = gaussian_filter_1d(sigma).T

    # Perform separable Gaussian smoothing
    image_smoothed = scipy.signal.convolve2d(image,h_x,mode='same',boundary='symm')
    image_smoothed = scipy.signal.convolve2d(image_smoothed,h_y,mode='same',boundary='symm')

    # Prewitt filtering
    image_filtered_x = scipy.signal.convolve2d(image_smoothed,prewitt_x,mode='same',boundary='symm')
    image_filtered_y = scipy.signal.convolve2d(image_smoothed,prewitt_y,mode='same',boundary='symm')

    # Calculate the gradient magnitude
    grad_mag = (image_filtered_x**2+image_filtered_y**2)**(1/2)

    coloring_image=np.zeros(grad_mag.shape)
    cos_thresh=math.cos(22.5/180*math.pi)
    for i in range(1,image.shape[0]-1):
        for j in range(1,image.shape[1]-1):
            vector=np.array([image_filtered_x[i,j],image_filtered_y[i,j]])
            vector=vector/(grad_mag[i,j]+0.0000001)
            if(~(vector[0]>=cos_thresh or vector[0]<=-cos_thresh)):
                if(grad_mag[i,j]>grad_mag[i+1,j] and grad_mag[i,j]>grad_mag[i-1,j]):
                    coloring_image[i,j]=grad_mag[i,j]
            elif(~(vector[1]>=cos_thresh or vector[1]<=-cos_thresh)):
                if(grad_mag[i,j]>grad_mag[i,j+1] and grad_mag[i,j]>grad_mag[i,j-1]):
                    coloring_image[i,j]=grad_mag[i,j]
            elif(~((vector[0]<=cos_thresh and vector[1]<=cos_thresh)or(vector[0]>=-cos_thresh and vector[1]>=-cos_thresh))):
                if(grad_mag[i,j]>grad_mag[i+1,j+1] and grad_mag[i,j]>grad_mag[i-1,j-1]):
                    coloring_image[i,j]=grad_mag[i,j]
            else:
                if(grad_mag[i,j]>grad_mag[i+1,j-1] and grad_mag[i,j]>grad_mag[i-1,j+1]):
                    coloring_image[i,j]=grad_mag[i,j]

    #inverse image binaryzation with user specified threshold

    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            if(coloring_image[i,j]>threshold):
                coloring_image[i,j]=0
            else:
                coloring_image[i,j]=255

    # Display the gradient magnitude image
    # plt.imshow(coloring_image, cmap='gray')
    # plt.gcf().set_size_inches(10, 8)
    # plt.show()
    # return image
    # plt.savefig('logo2.png')
    imageio.imsave(output_directory, coloring_image)

##********************** Example Main *************************##

# if __name__ == "__main__":
#     # # Read the image
#     # image = imageio.imread('Logo.png')
#     # image = rgb2gray(image)
#     # # plt.imshow(image, cmap='gray')
#     # # plt.gcf().set_size_inches(10, 8)
#     # # plt.show()
#     # sigma = 5
#     # threshold = 5
#     Canny('Logo.png','Logo2.png',5)


__author__ = 'ANDRE'
import os
import math
def quadrado():
    print("Termo inicial:")
    a = int(input())
    print("Numero de Termos")
    numter = int(input())
#    while (numter > 1):
    if numter == 0:
        print("Sequencia sem termos")

    elif numter < 0:
        print("Numero de termos invalido")
    else:
        while numter > 1:
            print(a,end = ", ")
            a = a*a
            numter -= 1
        print(a*a)

def ncom1 ():
    print("Termo inicial:")
    a = int(input())
    b = 0
    print("Numero de Termos")
    numter = int(input())
    while (numter > -1):
        a = a + b
        print(a,end = ", ")
        numter -= 1
        b += 1

def q3 ():
    print("Termo inicial:")
    print("Numero de Termos")
    numter = int(input())
    res = numter
    while numter >= 0:
            res = -res + numter
            if numter == 0 or res == 0:
                print("0",end=", ")
                numter += -1

            else:
                print(numter,end =' e ')
                print(res,end=", ")
                numter+= -1

def menu():
    print("")
    print("1 - Sequencia de Quadrados:")
    print("2 - Sequencia X+(N+1):")
    print("3 - Sequencia sei la:")
    print("0 - Sair:")

    esc = int(input())
    return esc

def principal():
    a = 1
    while a == 1:
        b = menu()
        if b == 1:
            #proc limpa tela
            quadrado()
        elif b  == 2:
            #proc limpa tela
            ncom1()
        elif b  == 3:
            #proc limpa tela
            q3()
        elif b  == 0:
            a = 0
            print("Programa Encerrado")

principal()


import pytest

from typing import Callable
from fibonacci.my_decorator import my_parametrized
from fibonacci import naive, cached
from fixtures import time_tracker

@my_parametrized(identifiers="n,expected", values=[(0, 0), (1, 1), (2, 1), (20, 6765)])
def test_fib_naive(n: int, expected: int) -> None:
    res = naive.fibonacci_naive(n=n)
    assert res == expected

@pytest.mark.parametrize(
    "fib_func",
    [naive.fibonacci_naive, cached.fibonacci_cached, cached.fibonacci_lru_cached],
)
@pytest.mark.parametrize("n,expected", [(0, 0), (1, 1), (2, 1), (20, 6765)])
def test_cached(
    time_tracker, fib_func: Callable[[int], int], n: int, expected: int
) -> None:
    res = fib_func(n)
    assert res == expected


import sys
sys.path.append("C:/Users/41774/Desktop/game folder/util")
import pygame
from block import block
import mesh

pygame.init()

screenWidth = 900
screenHeight = 900
win =  pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption("Tron Game")
clock = pygame.time.Clock()

run = True

Right = 1
Down = 2
Left = 3
Up = 4
blue = (0, 0, 255)
red = (255, 0, 0)
timeCount = 0
hit1 = False
hit2 = False
computer = True
snake2_newblock = block(810, 450)

foo = False

all_blocks = [[foo for i in range(900 // 15)] for j in range(900 // 15)]
block_num = 10

def judge(direct1, direct2, x, y):
    num1 = 0
    num2 = 0
    if direct2 == Right:
        for i in range(900 // 15):
            for j in range(900 // 15):
                if i < (x // 15):
                    if all_blocks[i][j]:
                        num1 += 1
                if i > (x // 15):
                     if all_blocks[i][j]:
                        num2 += 1

    else:
        for i in range(900 // 15):
            for j in range(900 // 15):
                if j < (y // 15):
                    if all_blocks[i][j]:
                        num1 += 1
                if j > (y // 15):
                     if all_blocks[i][j]:
                        num2 += 1
    if num1 > num2:
        return direct2
    else:
        return direct1

class snake(object):
    def __init__(self, x, y, vel, direction):
        self.x = x
        self.y = y
        self.vel = vel
        self.blocks = []
        self.direction = direction

    def move(self, snake_other, num):
        global snake2_newblock
        if not self.blocks:
            new_block = block(self.x, self.y)

        else:
            if self.direction == Right:
                new_block = block(self.blocks[-1].x + 15, self.blocks[-1].y)
                if new_block.x >= screenWidth:
                    return True
            elif self.direction == Left:
                new_block = block(self.blocks[-1].x - 15, self.blocks[-1].y)
                if new_block.x < 0:
                    return True
            elif self.direction == Up:
                new_block = block(self.blocks[-1].x , self.blocks[-1].y - 15)
                if new_block.y < 0:
                    return True
            elif self.direction == Down:
                new_block = block(self.blocks[-1].x, self.blocks[-1].y + 15)
                if new_block.y >= screenHeight:
                    return True

        for i in self.blocks:

            if new_block.x == i.x and new_block.y == i.y:
                return True
        for i in snake_other.blocks:

            if new_block.x == i.x and new_block.y == i.y:
                return True

        all_blocks[new_block.x // 15][new_block.y // 15] = True
        if num == 2:
            snake2_newblock = new_block
        self.blocks.append(new_block)

        return False

    def draw(self, win, color):
        for i in self.blocks:
            i.draw(win, color)

snake1 = snake(90, 450, 15, Right)
snake2 = snake(810, 450, 15, Left)

def redraw():
    win.fill((255, 255, 255))

    snake1.draw(win, red)
    snake2.draw(win, blue)
    mesh.draw_mesh(win, 0, 0, 900, 900, 15, 15)
    pygame.display.update()

while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    keys = pygame.key.get_pressed()
    if snake1.direction != Down and keys[pygame.K_w]:
        snake1.direction = Up
    elif snake1.direction != Up and keys[pygame.K_s]:
        snake1.direction = Down
    elif snake1.direction != Left and keys[pygame.K_d]:
        snake1.direction = Right
    elif snake1.direction != Right and keys[pygame.K_a]:
        snake1.direction = Left

    left_block = False
    right_block = False
    down_block = False
    up_block = False

    if computer:
        for i in range (1, block_num):
            if snake2_newblock.x - i * 15 <= 0:
                left_block = True
            else:
                if all_blocks[(snake2_newblock.x - i * 15) // 15][snake2_newblock.y // 15]:
                    left_block = True
            if snake2_newblock.x + i * 15 >= 900:
                right_block = True
            else:
                if all_blocks[(snake2_newblock.x + i * 15) // 15][snake2_newblock.y // 15]:
                    right_block = True
            if snake2_newblock.y - i * 15 <= 0:
                up_block = True
            else:
                if all_blocks[snake2_newblock.x // 15][(snake2_newblock.y - i * 15) // 15]:
                    up_block = True
            if snake2_newblock.y + i * 15 >= 900:
                down_block = True
            else:
                if all_blocks[snake2_newblock.x // 15][(snake2_newblock.y + i * 15) // 15]:
                    down_block = True

        if snake2.direction == Left:
            if left_block:
                if not up_block and not down_block:
                    snake2.direction = judge(Up, Down, snake2_newblock.x, snake2_newblock.y)
                elif up_block and not down_block:
                    snake2.direction = Down
                elif down_block and not up_block:
                    snake2.direction = Up
                else:
                    block_num -= 1
        if snake2.direction == Up:
            if up_block:
                if not left_block and not right_block:
                    snake2.direction = judge(Left, Right, snake2_newblock.x, snake2_newblock.y)
                elif left_block and not right_block:
                    snake2.direction = Right
                elif right_block and not left_block:
                    snake2.direction = Left
                else:
                    block_num -= 1
        if snake2.direction == Right:
            if right_block:
                if not up_block and not down_block:
                    snake2.direction = judge(Up, Down, snake2_newblock.x, snake2_newblock.y)
                elif up_block and not down_block:
                    snake2.direction = Down
                elif down_block and not up_block:
                    snake2.direction = Up
                else:
                    block_num -= 1
        if snake2.direction == Down:
            if down_block:
                if not left_block and not right_block:
                    snake2.direction = judge(Left, Right, snake2_newblock.x, snake2_newblock.y)
                elif left_block and not right_block:
                    snake2.direction = Right
                elif right_block and not left_block:
                    snake2.direction = Left
                else:
                    block_num -= 1

    else:
        if snake2.direction != Down and keys[pygame.K_UP]:
            snake2.direction = Up
        elif snake2.direction != Up and keys[pygame.K_DOWN]:
            snake2.direction = Down
        elif snake2.direction != Left and keys[pygame.K_RIGHT]:
            snake2.direction = Right
        elif snake2.direction != Right and keys[pygame.K_LEFT]:
            snake2.direction = Left

    if timeCount == 100:
        hit1 = snake1.move(snake2, 1)
        hit2 = snake2.move(snake1, 2)
        timeCount = 0

    redraw()
    timeCount += 1

    if hit1 or hit2:

        if hit1 and hit2:
            text = "tie"
        elif hit1:
            text = "red player lose"
        elif hit2:
            text = "blue player lose"

        font = pygame.font.Font("freesansbold.ttf", 32)

        end_l = font.render(text, True, (255, 0, 0))

        textRect = end_l.get_rect()

        textRect.center = (screenWidth / 2, screenHeight / 2)

        win.blit(end_l, textRect)

        pygame.display.update()

        pygame.time.wait(5000)

        run = False


from builtins import map
from builtins import range
from builtins import object
from geocal_swig import *
from .igc_collection_extension import *
from .tie_point_extension import *
from .ray_intersect import *
from .feature_detector_extension import *
from .misc import *
import math
import itertools
import multiprocessing
from multiprocessing import Pool
import time
import logging
from tabulate import tabulate
import numpy as np

# Might not have cv2 available
try:
    import cv2
    have_cv2 = True
except ImportError:
    have_cv2 = False

class TiePointWrap(object):
    '''Wrapper around tp_collect.tie_point that can be pickled. We can\'t
    directly use pool.map on tp_collect.tie_point because python can\'t
    pickle a instance function'''
    def __init__(self, tp_collect):
        self.tp_collect = tp_collect
    def __call__(self, ic):
        log = logging.getLogger("geocal-python.tie_point_collect")
        log.debug("Processing point (%f, %f)" % (ic.line, ic.sample) )
        for h in logging.getLogger("geocal-python").handlers:
            h.flush()
        try:
            tp, diag = self.tp_collect.tie_point(ic)
            if(tp is None):
                log.debug("Got 0 matches")
            else:
                log.debug("Got %d matches" % tp.number_image_location)
            return tp, diag
        except RuntimeError:
        # We may try to find points that don't actually intersect
        # the ground (e.g., we are at a steep angle and above
        # the surface). In that case, just skip this point and
        # go to the next one
            log.debug("Got 0 matches")
            pass
        for h in logging.getLogger("geoca1-python").handlers:
            h.flush()
        return None, None

class TiePointDiagnostic(object):
    '''This contains information about tiepoint matching.'''
    def __init__(self, num_image):
        '''Initialize all counts to 0.'''
        # Have diagnostic codes from 0 to 10.
        max_diag_code = 10
        # Add in one extra bin for unrecognized codes
        self.image_match_diagnostic = np.zeros((num_image, max_diag_code + 2),
                                               dtype=int)
        # Maximum tp_diagnotic code
        max_tp_diag_code = 3
        self.tp_diagnostic = np.zeros((max_tp_diag_code + 1,), dtype=int)

    def add_tp_diag(self, d):
        '''Update fields based on the contents of diag returned by
        TiePointCollect.tie_point'''
        for i in range(self.image_match_diagnostic.shape[0]):
            if(d[i] >= 0):
                self.image_match_diagnostic[i, d[i]] += 1
        self.tp_diagnostic[d[-1]] += 1

    def _print_or_log(self, v):
        if(self.log):
            self.log.info(v)
        else:
            print(v, file=self.fh)
    def _print_tab_helper(self, a, b):
        '''In python 3, this is just [a, *b]. But we can not do that in
        python 2, so use this simple helper function.'''
        return list(itertools.chain([a], b))

    def print_report(self, fh=None, log=None):
        self.log = log
        self.fh = fh
        d = self.image_match_diagnostic
        self._print_or_log("        Tiepoint Matching")
        tp_tab = [self._print_tab_helper("Reason", range(d.shape[0]))]
        for i, v in enumerate(["Good Match", "Image masked",
                               "Too close to edge", "Variance too low",
                               "Correlation too low",
                               "Exceed Max Sigma",
                               "Exceed max radiance variance",
                               "Exceed precision requirement",
                               "Move past target",
                               "Solve failed",
                               "Exceed max iteration",
                               "Other"]):
            tp_tab.append(self._print_tab_helper(v, d[:,i]))
        self._print_or_log(tabulate(tp_tab, headers="firstrow"))
        self._print_or_log("\n")

        d = self.tp_diagnostic
        self._print_or_log("        Tiepoint Filtered")
        filt_tab = [["Reason", "Count"],
                    ["Only one match", d[1]],
                    ["Ray intersect exceed max_ground_covariance", d[2]],
                    ["RANSAC outlier", d[3]]]
        self._print_or_log(tabulate(filt_tab, headers="firstrow"))

class TiePointCollect(object):
    '''Given a IgcCollection, collect tiepoints by image matching.'''
    def __init__(self, igc_collection, map_info = None, base_image_index = 0,
                 max_ground_covariance = 20 * 20,
                 start_image_index = 0,
                 end_image_index = None,
                 avg_level = 0, use_intersection = False,
                 grid_spacing = 1,
                 image_matcher = None,
                 gcp_image_matcher = None,
                 ref_image = None,
                 ref_dem = None,
                 surface_image = None,
                 scale_factor = None):
        '''This sets up for doing tie point collection. A IgcCollection
        needs to be supplied.

        You can optionally specify avg_level to use. If supplied, we
        use a PyramidImageMatcher on top of the CcorrLsmMatcher, useful for
        difficult to match imagery.

        You can optionally pass in the grid spacing to use if we are
        projecting to the surface. This has a significant effect on
        how long this process takes. If the underlying DEM is coarse,
        there is no reason to do the ImageGroundConnection calculation
        at every point.

        You can optionally pass in a scale factor. This is applied to
        the raster data before image matching. This is useful for
        example AirMSPI data where the image is a reflectance value
        between 0.0 and 1.0. Since the image matchers expect integer
        data, you want get any results unless you scale to a different
        range.

        You can pass a list of surface projected images to match with.
        These should be the projection of the igc_collection, and can
        be used as an alternative to doing the projection on the fly.

        There is a trade off between getting the largest coverage (by
        taking a union of all the igc on the surface) and the
        strongest points (by looking at places seen by all the
        cameras. You may want to do both - so generate a set of GCPs
        using the largest coverage first and then the intersection
        second.  which one is used is controlled by the option
        "use_intersection"

        Can supply a reference image. If present, we use this as ground
        truth and generate GCPs if we can.
        '''
        if(image_matcher is None):
            self.image_matcher = CcorrLsmMatcher()
            if(avg_level > 0):
                self.image_matcher = PyramidImageMatcher(self.image_matcher, avg_level)
        else:
            self.image_matcher = image_matcher
        if(gcp_image_matcher is not None):
            self.gcp_image_matcher = gcp_image_matcher
        else:
            self.gcp_image_matcher = self.image_matcher
        self.start_image_index = start_image_index
        if(end_image_index is None):
            self.end_image_index = igc_collection.number_image
        else:
            self.end_image_index = end_image_index
        self.ref_image = ref_image
        self.ref_dem = ref_dem
        self.avg_level = avg_level
        self.scale_factor = scale_factor
        self.map_info = map_info
        self.base_image_index = base_image_index
        self.max_ground_covariance = max_ground_covariance
        self.igc_collection = igc_collection
        self.surface_image = surface_image
        if(self.igc_collection.number_image > 1):
            self.ri = RayIntersect3(self.igc_collection,
                                  max_ground_covariance = max_ground_covariance)
        if(self.ref_image is not None):
            self.itoim = [None]*(self.igc_collection.number_image + 1)
        else:
            self.itoim = [None]*self.igc_collection.number_image
        i = self.base_image_index
        igc1 = self.igc_collection.image_ground_connection(i)
        if(scale_factor is not None):
            igc1 = ScaleImageGroundConnection(igc1, scale_factor)
        for j in range(self.igc_collection.number_image):
            igc2 = self.igc_collection.image_ground_connection(j)
            if(scale_factor is not None):
                igc2 = ScaleImageGroundConnection(igc2, scale_factor)
            if(map_info is None):
                if(surface_image is None):
                    self.itoim[j] = IgcImageToImageMatch(igc1, igc2,
                                                         self.image_matcher)
                else:
                    self.itoim[j] = \
                        SurfaceImageToImageMatch(igc1, surface_image[i],
                                                 igc2, surface_image[j],
                                                 self.image_matcher)
            else:
                self.itoim[j] = SurfaceImageToImageMatch(igc1, igc2,
                              map_info, self.image_matcher, grid_spacing)
        if(self.ref_image is not None):
            dem = self.ref_dem
            if(dem is None):
                dem = igc1.dem
            self.ref_igc = MapInfoImageGroundConnection(self.ref_image,
                dem, "Reference Image")
            j = self.igc_collection.number_image
            if(surface_image is not None):
                self.itoim[j] = SurfaceImageToImageMatch(igc1, surface_image[i],
                        self.ref_igc, self.ref_image, self.gcp_image_matcher)
            else:
                mi = map_info
                if(mi is None):
                    mi = igc1.coverage(ref_image.map_info)
                self.itoim[j] = SurfaceImageToImageMatch(igc1, self.ref_igc,
                                 mi, self.gcp_image_matcher, grid_spacing)

    def __getstate__(self):
        return {"igc_collection": self.igc_collection,
                "map_info" : self.map_info,
                "base_image_index" : self.base_image_index,
                "max_ground_covariance" : self.max_ground_covariance,
                "start_image_index" : self.start_image_index,
                "end_image_index" : self.end_image_index,
                "avg_level" : self.avg_level,
                "image_matcher" : self.image_matcher,
                "gcp_image_matcher" : self.gcp_image_matcher,
                "ref_image" : self.ref_image,
                "ref_dem" : self.ref_dem,
                "surface_image" : self.surface_image,
                "scale_factor": self.scale_factor
                }

    def __setstate__(self, dict):
        self.__init__(dict["igc_collection"], map_info = dict["map_info"],
                      base_image_index = dict["base_image_index"],
                      max_ground_covariance = dict["max_ground_covariance"],
                      start_image_index = dict["start_image_index"],
                      end_image_index = dict["end_image_index"],
                      image_matcher = dict["image_matcher"],
                      gcp_image_matcher = dict["gcp_image_matcher"],
                      ref_image = dict["ref_image"],
                      ref_dem = dict["ref_dem"],
                      avg_level = dict["avg_level"],
                      surface_image = dict["surface_image"],
                      scale_factor = dict["scale_factor"]
                      )

    @property
    def number_image(self):
        return self.igc_collection.number_image

    def tie_point_grid(self, num_x, num_y, aoi = None, dem = None,
                       border = 100, pool = None, diagnostic = None):
        '''Return a grid of tie points. Note that we may be missing results
        for particular grid points if matching isn\'t successful.

        There are two common ways to collect tie points. One is to simply
        search through the full images supplied with the
        ImageGroundConnection. The other is to restrict this to an area
        of interest (AOI). You can optionally supply a MapInfo to define
        a AOI, along with a Dem to use. If present, we find tiepoints
        distributed on that. If not, then we find relative to the first
        image in the image list.

        We report diagnostics on the tiepoints that we tried matching,
        as the class TiePointDiagnostic. You can pass in an existing one
        to add in more data, or if not supplied we start with an empty
        one.
        '''
        tstart = time.time()
        log = logging.getLogger("geocal-python.tie_point_collect")
        if(aoi):
            nline = aoi.number_y_pixel
            nsamp = aoi.number_x_pixel
            step_line = max(int(math.floor((nline - 2 * border) / num_y)), 1)
            step_samp = max(int(math.floor((nsamp - 2 * border) / num_x)), 1)
            iplist = []
            for ln in range(border, nline - border, step_line):
                for smp in range(border, nsamp - border, step_samp):
                    gp = aoi.ground_coordinate(smp, ln)
                    gp = dem.surface_point(gp)
                    ic1 = self.igc_collection.image_coordinate(
                       self.base_image_index, gp)
                    ic1.line = round(ic1.line)
                    ic1.sample = round(ic1.sample)
                    iplist.append(ic1)
        else:
            fd = ForstnerFeatureDetector()
            log.info("Starting interest point")
            log.info("Time: %f" % (time.time() - tstart))
            img = self.igc_collection.image(self.base_image_index)
            if(self.scale_factor):
                img = ScaleImage(img, self.scale_factor)
            iplist = fd.interest_point_grid(img,
                num_y, num_x, border, pool = pool)
        log.info("Done with interest point")
        log.info("Time: %f" % (time.time() - tstart))
        log.info("Starting matching")
        func = TiePointWrap(self)
        if(pool):
            res = pool.map(func, iplist,
                           max(len(iplist) // multiprocessing.cpu_count(), 1))
        else:
            res = list(map(func, iplist))
        log.info("Done with matching")
        log.info("Time: %f" % (time.time() - tstart))
        res2 = TiePointCollection()
        res2.extend([i for i, diag in res if i is not None])
        if(diagnostic is not None):
            diagsum = diagnostic
        else:
            diagsum = TiePointDiagnostic(self.number_image)
        for i, diag in res:
            if(diag is not None):
                diagsum.add_tp_diag(diag)
        log.info("Total number tp: %d" % len(res2))
        log.info("Number GCPs:     %d" % res2.number_gcp)
        return res2, diagsum

    def tie_point(self, ic1):
        '''Return a tie point that is roughly at the given location in the
        first image. Note that we try matching all the other images to the
        first image, i.e., we don\'t chain by map 2 to 3 and 3 to 4.
        If we aren't successful at matching, this returns None.

        In addition to the tiepoint, this returns a diagnostic array for
        determining why matching might have failed, or the tiepoint was
        rejected.  This is number_image+1 in size. For image i, we return
        the diagnostic code from the matcher. This is 0 for success, or a
        positive number indicating why it failed in not. Just to keep things
        straight, we return -1 if we skipped the image (e.g., it is the base
        image we are matching to). This can be used to not count matching as
        successful if we didn't do it.

        The last entry in diagnostic array is 0 if we successfully created
        a tie point, 1 if we dropped it because it had only one match so we
        can't determine the intersection (not and issue for GCPs), or 2 if
        dropped because the point was rejected by RayIntersect3 because of
        the max_ground_covariance test.
        '''
        tp = TiePoint(self.number_image)
        diag = np.empty((self.number_image+1,),dtype=int)
        diag[:] = -1
        diag[-1] = 0
        tp.image_coordinate(self.base_image_index, ic1, 0.05, 0.05)
        for i in range(self.start_image_index, self.end_image_index):
            if(i != self.base_image_index):
                ic2, lsigma, ssigma, success, diagnostic = \
                    self.itoim[i].match(ic1)
                diag[i] = diagnostic
                if(success):
                    tp.image_coordinate(i, ic2, lsigma, ssigma)
        if(self.ref_image is not None):
            i = self.igc_collection.number_image
            ic2, lsigma, ssigma, success, diagnostic = \
                self.itoim[i].match(ic1)
            diag[self.base_image_index] = diagnostic
            if(success):
                tp.ground_location = self.ref_igc.ground_coordinate(ic2).convert_to_cf()
                tp.is_gcp = True
                return tp, diag
        if(self.igc_collection.number_image > 1):
            r = self.ri.ray_intersect(tp)
            # Indicate why we may throw the tiepoint away
            if(r is None):
                if(tp.number_image_location == 1):
                    diag[-1] = 1
                elif(tp.number_image_location > 1):
                    diag[-1] = 2
            return r, diag
        else:
            return None, diag

class TiePointCollectFM(object):
    '''Given a IgcCollection, collect tiepoints by feature matching. This is
    very similar to TiePointCollect, except we use feature matching.

    Note that unlike TiePointCollect we don't have the concept of a
    'base_image' here, instead we match all the images at once.

    Note also that feature matching can have much larger blunders than
    we typically see for image matching (since it can match any 2 features
    in an image). You will want to do some kind of outlier rejection after
    using this class to determine tiepoints (e.g., outlier_reject_ransac).

    I have not had much success with using this class to generate tie points,
    the accuracy of the feature matching tends to be pretty poor. We will
    leave this is place for now, perhaps this will be of some use in the
    future.
    '''
    def __init__(self, igc_collection, max_ground_covariance = 20 * 20,
                 ref_image = None,
                 number_feature = 500, number_octave_levels = 4,
                 number_ref_feature = 1000,
                 skip_ray_intersect = False,
                 norm_type = None,
                 fdetect = None, fdetect_ref = None):
        '''Note if you have a reference image, make sure fdetect and
        fdetect_ref are the same type (e.g., both SURF). They can have
        different parameters, but need to be the same time so the matching
        can be done.'''
        if(not have_cv2):
            raise RuntimeError("This class requires the openCV python library cv2, which is not available.")
        self.raster_image = [igc_collection.image(i) for i in range(igc_collection.number_image)]
        if(igc_collection.number_image > 1 and not skip_ray_intersect):
            self.ri = RayIntersect3(igc_collection,
                                max_ground_covariance = max_ground_covariance)
        else:
            self.ri = None
        self.max_ground_covariance = max_ground_covariance
        if(fdetect is not None):
            self.fdetect = fdetect
        else:
            self.fdetect = cv2.xfeatures2d.SIFT_create(number_feature,
                                                       number_octave_levels)
        if(fdetect_ref is not None):
            self.fdetect_ref = fdetect_ref
        else:
            self.fdetect_ref = cv2.xfeatures2d.SIFT_create(number_ref_feature,
                                                           number_octave_levels)
        if(ref_image is not None):
            mi = ref_image.map_info
            mi_ref = None
            for i in range(igc_collection.number_image):
                mi_t = igc_collection.image_ground_connection(i).cover(mi)
                if(mi_ref is None):
                    mi_ref = mi_t
                else:
                    mi_ref = mi_ref.map_union(mi_t)
            self.ref_image = SubRasterImage(ref_image, mi_ref)
        else:
            self.ref_image = None
        if(norm_type is None):
            self.bf = cv2.BFMatcher()
        else:
            self.bf = cv2.BFMatcher(norm_type)

    def detect_and_compute(self, ind, log):
        '''Detect keypoints and compute descriptor the given raster image.'''
        log.info("Detecting features for image %d " % ind)
        d = self.raster_image[ind].read_all_byte_scale()
        kp, des = self.fdetect.detectAndCompute(d, None)
        return [kp, des]

    def detect_and_compute_ref(self, log):
        '''Detect keypoints and compute descriptor in the reference image.'''
        log.info("Detecting features for reference image")
        d = self.ref_image.read_all_byte_scale()
        kp, des = self.fdetect_ref.detectAndCompute(d, None)
        return [kp, des]

    def match_feature(self, kp_and_desc, ind1, ind2):
        '''Match features between two images'''
        kp1, des1 = kp_and_desc[ind1]
        kp2, des2 = kp_and_desc[ind2]
        matches = self.bf.knnMatch(des1, des2, k=2)
        # This test is from the SIFT paper. If selects matches only if they
        # have a single unique match that is significantly better than the
        # next match.
        good = []
        for m,n in matches:
            if m.distance < 0.75*n.distance:
                good.append(m)
        good = sorted(good, key = lambda x:x.distance)
        res = []
        for g in good:
            ic1 = ImageCoordinate(kp1[g.queryIdx].pt[1], kp1[g.queryIdx].pt[0])
            ic2 = ImageCoordinate(kp2[g.trainIdx].pt[1], kp2[g.trainIdx].pt[0])
            res.append([ic1, ic2, g.queryIdx])
        return res

    def match_feature_ref(self, kp_and_desc, kp_and_desc_ref, ind1):
        '''Match features between two images'''
        kp1, des1 = kp_and_desc[ind1]
        kp2, des2 = kp_and_desc_ref
        matches = self.bf.knnMatch(des1, des2, k=2)
        # This test is from the SIFT paper. If selects matches only if they
        # have a single unique match that is significantly better than the
        # next match.
        good = []
        for m,n in matches:
            if m.distance < 0.75*n.distance:
                good.append(m)
        good = sorted(good, key = lambda x:x.distance)
        res = []
        for g in good:
            ic1 = ImageCoordinate(kp1[g.queryIdx].pt[1], kp1[g.queryIdx].pt[0])
            ic2 = ImageCoordinate(kp2[g.trainIdx].pt[1], kp2[g.trainIdx].pt[0])
            res.append([ic1, ic2, g.queryIdx])
        return res

    def tp_list(self, kp_and_desc, kp_and_desc_ref, ind):
        '''Generate list of tie points, starting with the given image.'''
        res = {}
        for i in range(ind + 1, len(self.raster_image)):
            good = self.match_feature(kp_and_desc, ind, i)
            for ic1, ic2, idx in good:
                if idx in res:
                    tp = res[idx]
                else:
                    tp = TiePoint(len(self.raster_image))
                    tp.image_coordinate(ind, ic1, 0.5, 0.5)
                tp.image_coordinate(i, ic2, 0.5, 0.5)
                res[idx] = tp
        if(kp_and_desc_ref is not None):
            good = self.match_feature_ref(kp_and_desc, kp_and_desc_ref, ind)
            for ic1, ic2, idx in good:
                if idx in res:
                    tp = res[idx]
                else:
                    tp = TiePoint(len(self.raster_image))
                    tp.image_coordinate(ind, ic1, 0.5, 0.5)
                tp.is_gcp = True
                tp.ground_location = self.ref_image.ground_coordinate(ic2).convert_to_cf()
                res[idx] = tp

        return res

    def tie_point_list(self, pool = None):
        '''Generate a TiePointCollect.'''
        res = TiePointCollection()
        tstart = time.time()
        log = logging.getLogger("geocal-python.tie_point_collect")
        log.info("Starting feature detection")
        kp_and_desc = [self.detect_and_compute(i, log)
                       for i in range(len(self.raster_image))]
        if(self.ref_image):
            kp_and_desc_ref = self.detect_and_compute_ref(log)
        else:
            kp_and_desc_ref = None
        log.info("Done with feature detection")
        log.info("Time: %f" % (time.time() - tstart))
        log.info("Starting feature matching")
        for i in range(len(self.raster_image)):
            tpl = self.tp_list(kp_and_desc, kp_and_desc_ref, i)
            for tp in tpl.values():
                if(not tp.is_gcp and self.ri is not None):
                    tp2 = self.ri.ray_intersect(tp)
                    if(tp2 is not None):
                        res.append(tp2)
                else:
                    res.append(tp)
        log.info("Done with feature matching")
        log.info("Time: %f" % (time.time() - tstart))
        return res

def _point_list(ind1, ind2_or_ref_image, tpcol):
    '''Internal function, gives list of points between 2 images.'''
    pt1 = []
    pt2 = []
    ind = []
    for i, tp in enumerate(tpcol):
        ic1 = tp.image_coordinate(ind1)
        if(isinstance(ind2_or_ref_image,RasterImage)):
            if(tp.is_gcp):
                ic2 = ind2_or_ref_image.coordinate(tp.ground_location)
            else:
                ic2 = None
        else:
            ic2 = tp.image_coordinate(ind2_or_ref_image)
        if(ic1 is not None and
           ic2 is not None):
            pt1.append([ic1.line, ic1.sample])
            pt2.append([ic2.line, ic2.sample])
            ind.append(i)
    return [np.array(pt1), np.array(pt2), np.array(ind)]

def _point_list_surface_proj(ind1, ind2_or_ref_image, tpcol,
                             igc1, igc2, ref_image):
    '''Internal function, gives list of points between 2 images. This version
    uses the supplied igc and reference image to first project to the surface,
    and then collect points in the reference image space. This is useful for
    images where the differences with a frame camera are too great (e.g.,
    aircraft data).'''
    pt1 = []
    pt2 = []
    ind = []
    for i, tp in enumerate(tpcol):
        if(tp.image_coordinate(ind1) is not None):
            ic1 = ref_image.coordinate(igc1.ground_coordinate(tp.image_coordinate(ind1)))
        else:
            ic1 = None
        if(isinstance(ind2_or_ref_image,RasterImage)):
            if(tp.is_gcp):
                ic2 = ref_image.coordinate(tp.ground_location)
            else:
                ic2 = None
        else:
            if(tp.image_coordinate(ind2_or_ref_image) is not None):
                ic2 = ref_image.coordinate(igc2.ground_coordinate(tp.image_coordinate(ind2_or_ref_image)))
            else:
                ic1 = None
        if(ic1 is not None and
           ic2 is not None):
            pt1.append([ic1.line, ic1.sample])
            pt2.append([ic2.line, ic2.sample])
            ind.append(i)
    return [np.array(pt1), np.array(pt2), np.array(ind)]

def _outlier_reject_ransac(ind1, ind2_or_ref_image, tpcol, threshold,
                           igc1 = None, igc2 = None, ref_image = None):
    '''Internal function used to filter bad points between 2 images.'''
    if(not have_cv2):
        raise RuntimeError("This function requires the openCV python library cv2, which is not available.")
    if(igc1 is None):
        pt1, pt2, ind = _point_list(ind1, ind2_or_ref_image, tpcol)
    else:
        pt1, pt2, ind = _point_list_surface_proj(ind1, ind2_or_ref_image, tpcol,
                                                 igc1, igc2, ref_image)
    if(pt1.shape[0] < 1):
        return tpcol
    m, mask = cv2.findFundamentalMat(pt1, pt2, cv2.FM_RANSAC, threshold)
    # if we have too few points, we don't get a result. Really shouldn't
    # keep any of the tiepoints then
    if(mask is None):
        bad_pt = ind
    else:
        m = (mask == 0)
        bad_pt = ind[m[:,0]]
    return [tp for i, tp in enumerate(tpcol) if i not in bad_pt]

def outlier_reject_ransac(tpcol, ref_image = None, threshold = 3.0,
                          igccol = None, diagnostic = None):
    '''This remove outliers from a TiePointCollection. This fits the
    tiepoints between pairs of images to create the Fundamental Matrix,
    rejecting outliers using Random sample consensus (RANSAC).

    Note that the Fundamental Matrix really only applies for epipolar
    geometry, e.g., a pair of frame pinhole cameras as single position.
    Our cameras often aren't this (e.g., a pushbroom camera). However often
    we are close enough that we can still used this approximation to look
    for outliers.

    If a reference image is passed in, we also look at rejecting GCPs that
    are outliers.

    If the Igccol is passed in, then we use that to project to the surface
    first before looking for outliers. This can be useful for Igcs that are
    too far from a frame camera, e.g., aircraft data

    If diagnostic is passed in, it should be a TiePointDiagnostic which we
    update with points that are rejected.
    '''
    nimg = tpcol[0].number_image
    res = tpcol
    log = logging.getLogger("geocal-python.tie_point_collect")
    log.info("Starting using RANSAC to reject outliers")
    if(igccol is not None):
        log.info("Projecting to surface first")
    len1 = len(tpcol)
    log.info("Starting %s" % tpcol)
    for i in range(nimg):
        for j in range(i + 1, nimg):
            if(igccol is None):
                res = _outlier_reject_ransac(i, j, res, threshold)
            else:
                igc1 = igccol.image_ground_connection(i)
                igc2 = igccol.image_ground_connection(j)
                if(ref_image is not None):
                    rimg = ref_image
                else:
                    mibase = cib01_mapinfo(igc1.resolution_meter())
                    mi = igc1.cover(mibase)
                    rimg = MemoryRasterImage(mi);
                res = _outlier_reject_ransac(i, j, res, threshold,
                                             igc1 = igc1, igc2 = igc2,
                                             ref_image = rimg)
    len2 = len(res)
    for i in range(nimg):
        if(ref_image is not None):
            if(igccol is None):
                res = _outlier_reject_ransac(i, ref_image, res, threshold)
            else:
                igc1 = igccol.image_ground_connection(i)
                igc2 = None
                res = _outlier_reject_ransac(i, ref_image, res, threshold,
                                             igc1 = igc1, igc2 = igc2,
                                             ref_image = ref_image)

    len3 = len(res)
    res2 = TiePointCollection()
    res2.extend(res)
    log.info("Removed %d tiepoints" % (len1 - len2))
    log.info("Removed %d more GCPs" % (len2 - len3))
    log.info("Ending %s" % res2)
    log.info("Completed using RANSAC to reject outliers")
    if(diagnostic):
        ransac_diag_code = 3
        diagnostic.tp_diagnostic[3] += len1 - len3
    return res2

__all__ = ["TiePointDiagnostic", "TiePointCollect", "TiePointCollectFM",
           "outlier_reject_ransac"]


from rest_framework.views import APIView
from rest_framework.response import Response
import requests
from hashlib import sha1
import hmac
from .funciones_bodega import *
from .datos import *
import json
from django.shortcuts import render, render_to_response
from django.http.response import JsonResponse

name_sku_dict = {"Sesamo": "1011",
                "Nori_Entero": "1016",
                "Camaron": "1006",
                "Azucar": "1003",
                "Arroz_Grano_Corto": "1001"}

almacen_dict_id = { "5cc7b139a823b10004d8e6d3" : "recepcion",
                     "5cc7b139a823b10004d8e6d4" : "despacho",
                     "5cc7b139a823b10004d8e6d5" : "almacen_1",
                     "5cc7b139a823b10004d8e6d6" : "almacen_2",
                     "5cc7b139a823b10004d8e6d7" : "pulmon",
                     "5cc7b139a823b10004d8e6d8" : "cocina"}

sku_stock_dict = {  "1301" : 50, "1201" : 250, "1209" : 20, "1109" : 50,"1309" : 170,
                    "1106" : 400,"1114" : 50,"1215" : 20,"1115" : 30,"1105" : 50,
                    "1216" : 50,"1116" : 250,"1110" : 80,"1310" : 20,
                    "1210" : 150,"1112" : 130,"1108" : 10,"1407" : 40,"1207" : 20,
                    "1107" : 50,"1307" : 170,"1211" : 60}

def inventories_view(request):
    lista = stock()
    query = {"query": lista}
    return render_to_response('inventoriestotal.html', query)

def bodegas_view(request):
    lista = []
    for item in revisarBodega().json():
        dict = {"almacen": almacen_dict_id[item['_id']], "total" : item['totalSpace'], "used": item['usedSpace']}
        lista.append(dict)

    query = {"query": lista}
    return render_to_response('bodegas.html', query)

def estadisticas_view(request):
    datos = productos()
    lista_ = []
    lista = stock()
    for sku, information in datos.items():
        if information['stock_minimo'] is not None:
            dict = {"sku": sku, "stock_minimo": str(information['stock_minimo']), "name": information['nombre']}
            cantidad_actual = 0
            for items in lista:
                if items['sku'] == sku:
                    cantidad_actual += items["total"]

            dict["cantidad_actual"] = str(cantidad_actual)

            porcentaje = cantidad_actual * 100 / information['stock_minimo']
            dict["porcentaje"] = porcentaje
            lista_.append(dict)

    query = {"query": lista_}
    return render_to_response('index.html', query)

class InventoriesView(APIView):
    def get(self, request):
        #ESTA ES LA FUNCIÓN QUE HAY QUE MODIFICAR PARA LOS GET
        #SOLO SE MUESTRAN PRODUCTOS DE ALMACEN DESPACHO, ALMACENES GENERALES Y PULMON
        lista = stock_fixed()
        return JsonResponse(lista, status=200, safe=False)

# Cuando hagan post con POSTMAN hay que ponerle un / al final de la URL, así:
# http://127.0.0.1:8000/api/orders/
class OrdersView(APIView):
    def post(self, request):
        #ESTA ES LA FUNCION QUE HAY QUE MODIFICAR PARA LOS POST
        sku = request.data.get("sku")
        cantidad = request.data.get("cantidad")
        almacenId = request.data.get("almacenId")

        if not sku or not cantidad or not almacenId:
            return Response(data="No se creó el pedido por un error del cliente en la solicitud", status=status.HTTP_400_BAD_REQUEST)
        elif sku not in sku_producidos or cantidad > cantidad_producto(sku):
            return Response(data="Producto no se encuentra o cantidad no disponible", status=status.HTTP_404_NOT_FOUND)
        else:
            despachar_producto(sku, cantidad)
            mover_entre_bodegas(sku, cantidad, almacenId)
            dictionary = {"sku": sku, "cantidad": cantidad, "almacenId": almacenId, "grupoProveedor": "2", "aceptado": True, "despachado": True}
            return JsonResponse(dictionary, status=200, safe=False)


#!/usr/bin/env python

from distutils.core import setup
import distutils.command.build
import distutils.command.install_data
import os.path
import xray4scm
import sys

# optional support for py2exe
try:
    import py2exe
    HAVE_PY2EXE = True
except:
    HAVE_PY2EXE = False

addparams = {}
if HAVE_PY2EXE:
    addparams['console'] = [{'script': 'xray', 'dest_base': 'xray4scm'}]
    addparams['zipfile'] = 'shared.lib'
    addparams['options'] = {
        'py2exe': {
            'optimize': 0,
            'compressed': True,
            'packages': ['pysvn', 'cmdln', 'SQLObject', 'StringIO', 'gzip']
        }
    }

setup(
    name='xray',
    version = xray4scm.__version__,
    description = 'XRay: Coding Analysis for SCMs',
    long_description =
        'XRay is an analysis tool built upon your SCMs, aimed to '
        'consolidade project statistics from many repositories at the same '
        'time, generating code reports and development statistics from '
        'your repository log data.',
    author = 'Guilherme Balena Versiani',
    author_email = 'guibv@comunip.com.br',
    license = 'GPL',
    platforms = ['Linux','Mac OSX','Windows XP/2000/NT','Windows 95/98/ME'],
    keywords = ['x-ray', 'coding', 'analysis', 'scm', 'svn', 'hg'],
    url = 'http://xray.sourceforge.net/',
    download_url = 'http://sourceforge.net/projects/xray/files/',
    packages = ['xray4scm'],
    scripts = ['xray'],
    **addparams
)


import numpy as np
import matplotlib.pyplot as plt

A = np.array([[1, 2], [3, 4]])
s0 = np.array([[1], [0]])
s1 = np.array([[0], [1]])

num_points = 100
n1 = np.random.normal(0, 1, (num_points, 1))
n2 = np.random.normal(0, 1, (num_points, 1))
n = np.hstack((n1, n2))

y_s0 = A @ s0 + n
y_s1 = A @ s1 + n

plt.scatter(y_s0[:,0], y_s0[:,1], c='red', label='$\mathbf{y}|\mathbf{s}_0$')
plt.scatter(y_s1[:,0], y_s1[:,1], c='blue', label='$\mathbf{y}|\mathbf{s}_1$')
plt.legend()
plt.xlabel('$y_1$')
plt.ylabel('$y_2$')
plt.savefig('./5.1.1.pdf')
plt.show()


# ================================================================================================================================== #
#                                                              Parser                                                                #
# ================================================================================================================================== #
import spacy
from dialog_utils.words import (objects_list, destination_list, name_list, sinonyms_list)

class Parser():

    def __init__(self):
        self.nlp = spacy.load("en_core_web_sm")

        # ================== Possible object ================== #
        self.objects = objects_list()

        # ================ Possible destination =============== #
        self.destinations = destination_list()

        # ==================== Possible names ================== #
        self.persons = name_list()

        # ==================== Possible verbs ================== #
        self.verbs = {"go":[] , "find":[], "follow":[], "take":[], "place":[], "say": []}
        self.verbs["go"], self.verbs["find"], self.verbs["follow"], self.verbs["take"], self.verbs["place"], self.verbs["say"] = sinonyms_list()

    #////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////#

    def classifier(self, string):

        string = string.lower()
        self.doc = self.nlp(string)

        action = []
        actions_num = 0
        index = []

        for word in self.doc:
            if word.pos_ == "VERB" and word.text in self.verbs.keys():
                action.append(word.text)
                actions_num += 1
                index.append(list(self.doc).index(word))

            # forced search to save some cases where Spacy does't recognize the verb as "VERB"
            elif (word.text in (self.verbs["go"] + self.verbs["find"] + self.verbs["follow"] + self.verbs["take"] + self.verbs["place"] + self.verbs["say"])):
                action.append(word.text)
                actions_num += 1
                index.append(list(self.doc).index(word))

        self.previousPerson = self.previousObject = self.previousDestination = ""
        self.dic_res = ""
        self.dic = {"intent" : "", "person" : "", "object" : "", "destination" : "", "who" : "", "what" : ""}

        for it in range(actions_num):

            flag_go_add = False
            flag_to = False
            self.index_adp = -1
            self.index_go_add = -1

            if actions_num > 1 :
                if it < actions_num - 1: doc = self.doc[index[it]:index[it+1]]
                else: doc = self.doc[index[it]:]
            else:
                doc = self.doc[index[0]:]

            # specials cases for FIND and TAKE verbs
            for word in doc:
                if word.text == "to" and not flag_to:
                    self.index_adp = list(doc).index(word)
                    flag_to = True

                if (word.text in self.destinations[0] and not word.text == "to"):
                    self.index_go_add = list(doc).index(word)
                    flag_go_add = True

            # ================== GO --> place ==================== #
            if action[it] in self.verbs["go"]:
                self.dic["intent"] = self.verbs["go"][0]
                self.dic["destination"] = self.find(doc, "destination")

            # ======= FIND --> object or person (and place) ====== #
            elif action[it] in self.verbs["find"]:

                if flag_go_add:
                    flag_go_add = False

                    action.append("go")
                    self.dic["intent"] = "go"

                    self.dic["destination"] = self.find(doc, "destination")

                    doc = doc[0:self.index_go_add]

                    self.add_action()

                self.dic["person"] = self.find(doc, "person")
                if len(self.dic["person"]) > 0: self.dic["intent"] = "to find someone"

                if not (len(self.dic["person"]) > 0):
                    del self.dic["person"]
                    self.dic["object"] = self.find(doc, "object")
                    self.dic["intent"] = "to find something"

            # ================ FOLLOW --> person ================= #
            elif action[it] in self.verbs["follow"]:
                self.dic["intent"] = self.verbs["follow"][0]
                self.dic["person"] = self.find(doc, "person")

            # =========== TAKE --> object (and place) ============ #
            elif action[it] in self.verbs["take"]:

                if (flag_go_add and not flag_to) or ((flag_go_add and flag_to) and self.index_adp - self.index_go_add < 0):
                    flag_go_add = False

                    action.append("go")
                    self.dic["intent"] = "go"

                    self.dic["destination"] = self.find(doc, "destination")

                    doc = doc[0:self.index_go_add]

                    self.add_action()

                elif (flag_go_add and flag_to) and self.index_adp - self.index_go_add > 0:
                    flag_go_add = False

                    action.append("go")
                    self.dic["intent"] = "go"

                    docd = doc[self.index_go_add:self.index_adp]
                    self.dic["destination"] = self.find(docd, "destination")

                    doc = [*doc[:self.index_go_add], *doc[self.index_adp:]]
                    doc = str(doc)
                    doc = doc.replace("[", "").replace("]", "").replace(",", "")
                    doc = self.nlp(doc)

                    self.index_adp -= (self.index_adp - self.index_go_add)
                    self.add_action()

                self.dic["intent"] = self.verbs["take"][0]

                pos = ["back", "there"]
                index_pos = -1
                for word in doc:
                    if word.text in pos:
                        index_pos = pos.index(word.text)
                        break

                if index_pos != -1:

                    if self.previousDestination != "": self.dic["destination"] = self.previousDestination
                    elif index_pos == 0: self.dic["destination"] = '"STARTING POINT"'

                    self.dic["person"] = self.find(doc, "person")
                    if len(self.dic["person"]) == 0: self.dic["object"] = self.find(doc, "object")

                else:

                    if self.index_adp != -1 and self.index_adp <= 2: self.dic["person"] = self.find(doc, "person")
                    else: self.dic["object"] = self.find(doc, "object")

                    for k in self.destinations[0]:
                        if k in doc.text:
                            self.dic["destination"] = self.find(doc, "destination")
                            break
                    if self.dic["destination"] == "":
                        self.dic["destination"] = self.find(doc, "person")

            # ========== PLACE --> object (and place) =========== #
            elif action[it] in self.verbs["place"]:
                self.dic["intent"] = self.verbs["place"][0]
                self.dic["object"] = self.find(doc, "object")
                for k in self.destinations[0]:
                    if k in doc.text:
                        self.dic["destination"] = self.find(doc, "destination")
                        break

            # ================= SAY --> person =================== #
            elif action[it] in self.verbs["say"]:
                self.dic["intent"] = "say"

                whats = ["what", "whats"]
                wh = ["which", "who", "whos", "whose", "hows", "how", "that", "where", "wheres"]

                index_what = -1
                it_what = 0
                it_s = 0
                for word in doc:
                    if word.text in whats:
                        index_what = list(doc).index(word)

                    if word.text in ["'s", " 's"]  and doc[it_what-1].text in whats:
                        it_s = 1
                    it_what += 1

                index_wh = -1
                if index_what != -1:
                    for word in doc:
                        if word.text in wh:
                            index_wh = list(doc).index(word)
                            break

                if not action[it] == "ask":
                    if flag_to:
                        if self.index_adp - index[it] == 1:

                            if index_what != -1:
                                self.dic["what"] = doc[index_what+it_s+1:]
                                self.dic["who"] = doc[self.index_adp + 1 : index_what]

                            elif index_wh != -1:

                                self.dic["what"] = doc[index_wh :]
                                self.dic["who"] = doc[self.index_adp + 1 : index_wh]

                        elif self.index_adp - index[it] > 1:
                            self.dic["what"] = doc[1 : self.index_adp]
                            self.dic["who"] = doc[self.index_adp + 1 :]

                    else:
                        if index_what != -1:
                            if index_what == 1: self.dic["what"] = doc[index_what+it_s+1:]
                            else:
                                self.dic["what"] = doc[index_what+it_s+1:]
                                self.dic["who"] = doc[1 : index_what]

                        elif index_wh != -1:

                            if index_wh == 1: self.dic["what"] = doc[index_wh:]
                            else:
                                self.dic["what"] = doc[index_wh:]
                                self.dic["who"] = doc[1 : index_wh]

                        else:
                            if (doc[1].pos_ in ["PROPN", "PRON"] and doc[1].dep_ != "poss")or doc[1].text in self.persons:
                                self.dic["what"] = doc[2:]
                                self.dic["who"] = doc[1]
                            else:
                                self.dic["what"] = doc[1:]

                else:

                    if str(doc[1]) in ["him","her"] and self.previousPerson != "":
                        self.dic["who"] = self.previousPerson
                    else:   self.dic["who"] = doc[1]

                    if flag_to: self.dic["what"] = doc[3:]

                    else: self.dic["what"] = doc[2:]

                self.dic["what"] = str(self.dic["what"]).rstrip()
                self.dic["what"] = str(self.dic["what"]).lstrip()
                self.dic["who"] = str(self.dic["who"])

            # ================ add a new action ================ #
            self.add_action()

        return self.dic_res

    #////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////#

    def find(self, spacy_doc, category):

        try:

            # Utils for category "Person"
            if category == "person":
                verbs = []
                for v in self.verbs.keys():
                    for w in self.verbs[v]:
                        verbs.append(w)

            # Utils for category "Object"
            if category == "object":
                article_index = -1

                two_verbs = -1
                for word in spacy_doc[1:]:
                    if word.pos_ == "VERB" and not word.dep_ in ["xcomp", "compound"]: two_verbs = list(spacy_doc).index(word)

            dic = ""

            it = 0
            for word in spacy_doc:

                # ======================== Persons ============================ #
                if category == "person":
                    if (((word.pos_ in ["PROPN", "PRON"] or word.text in self.persons) and word.text not in verbs) and not word.text in ["him", "her"]) and word.dep_ != "poss":
                        dic = word.text
                        self.previousPerson = word.text
                        break

                    elif word.text in ["him", "her"]:
                        if self.previousPerson: dic = self.previousPerson
                        else: dic = word.text
                        break

                # ======================== Objects ============================ #
                elif category == "object":

                    if not word.text in ["it"]:

                        if word.text in self.objects.keys(): article_index = list(spacy_doc).index(word)

                        if article_index != -1:

                            if two_verbs != -1:
                                w_it = 0
                                for w in spacy_doc[article_index+1:]:
                                    if (w.text in self.destinations[0] and w.text != "to") or (w.text == "to" and ((article_index + 1) + w_it) - two_verbs != 1) or (w.dep_ == "cc"):
                                        break
                                    else:
                                        dic += w.text + " "
                                        w_it += 1
                                self.previousObject = dic
                                break

                            if (word.text in self.objects[spacy_doc[article_index].text]) or (word.dep_ in ["pobj", "dobj"]):
                                if self.index_adp != -1: dic = spacy_doc[article_index + 1 : self.index_adp].text
                                elif self.index_go_add != -1: dic = spacy_doc[article_index + 1 : self.index_go_add].text
                                else: dic = spacy_doc[article_index + 1 : list(spacy_doc).index(word) + 1].text

                                self.previousObject = dic
                                break

                        # forced search when there is no article or expression introduccing the object
                        elif word.dep_ in ["pobj", "dobj"]:
                            if self.index_adp != -1: dic = spacy_doc[1 : self.index_adp].text
                            elif self.index_go_add != -1: dic = spacy_doc[1 : self.index_go_add].text
                            else: dic = spacy_doc[1 : list(spacy_doc).index(word) + 1].text

                            self.previousObject = dic
                            break

                    else:
                        if self.previousObject: dic = self.previousObject
                        else: dic = word.text
                        break

                # ====================== Destinations ========================= #
                elif category == "destination":

                    if word.text in self.destinations[1]:
                        dic = word.text
                        self.previousDestination = dic
                        break

                    if self.index_adp < self.index_go_add:
                        if word.pos_ == "ADP" and (word.text in self.destinations[0] and word.text != "to"):
                            for w in spacy_doc[it+2:]:
                                if (w.dep_ == "cc"): break
                                else: dic += w.text + " "
                            self.previousDestination = dic
                            break

                    else:
                        if word.pos_ == "ADP" and word.text in self.destinations[0]:
                            for w in spacy_doc[it+2:]:
                                if (w.dep_ == "cc"): break
                                else: dic += w.text + " "
                            self.previousDestination = dic
                            break

                it += 1

            return dic

        except not (category in ["person", "object", "destination"]):
            print("Error: category not found")
            return ""

    #////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////#

    def add_action(self):

        keys = list(self.dic.keys()).copy()
        for k in keys:
            self.dic[k] = self.dic[k].replace(",", "").rstrip().lstrip()
            if len(self.dic[k]) == 0: del self.dic[k]

        if len(self.dic.keys()) > 0:
            self.dic_res += str(self.dic) + '\n'

            self.dic_res = self.dic_res.replace("[", "").replace("]", "")

        self.dic = {"intent":"","person" : "", "object" : "", "destination" : "", "who" : "", "what" : ""}

    #////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////#

if __name__ == "__main__":
    import sys

    try:

        while(True):
            string = input("Write your request: ")
            nlp = Parser()
            answer = nlp.classifier(string)
            print("\n---> " + answer + "\n\n-----------------\n")

    except KeyboardInterrupt:
        sys.exit(1)


from .configs import ResizeConfig, MaxResolutionResize, TargetResolutionResize
from typing import Tuple

def calculate_downscale(size: "Tuple[int, int]", config: ResizeConfig) -> "Tuple[int, int]":
    width, height = size

    if isinstance(config, MaxResolutionResize):
        downscale_factors = [1.0]
        if config.max_width is not None:
            downscale_factors.append(width / config.max_width)
        if config.max_height is not None:
            downscale_factors.append(height / config.max_height)
        downscale_factor = max(downscale_factors)

        output_width = int(width / downscale_factor)
        output_height = int(height / downscale_factor)
        return (output_width, output_height)
    elif isinstance(config, TargetResolutionResize):
        width = config.width or size[0]
        height = config.height or size[1]
        return width, height
    else:
        raise ValueError(f"Unknown resize config type: {type(config).__name__}")


import time
import sys
import re
import random
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from nltk.stem import PorterStemmer
import kb_manager as kbm

# it infers tokens from user input
def tokenize(sentence):
    sentence = sentence.lower()
    word_tokens = word_tokenize(sentence)
    tokenized_sentence = [w for w in word_tokens if w not in stopwords.words('english')]
    return tokenized_sentence

# it replaces the star * with the string in replacement
def replace_a_star(sentence, replacement):
    return sentence.replace("*", replacement)

# it takes the words next to the keyword until it finds an "and", a comma, or a dot
def complete_keywords(sentence, keyword):
    to_add = (sentence.split(keyword)[1]).split("and")[0]
    to_add = to_add.split(",")[0]
    to_add = to_add.split(".")[0]
    modified = keyword + to_add
    return modified

# if the flag is slow, it prints the sentences as if someone was typing
# otherwise it prints the file normally
def my_print_file(file, flag):
    if flag == "slow":
        lines = file.readlines()
        for line in lines:
            for char in line:
                sys.stdout.write(char)
                sys.stdout.flush()
                time.sleep(0.09)
        print("\n")
    else:
        print(file.read())

# if the flag is slow, it prints the sentences as if someone was typing
# otherwise it prints the string normally
def my_print_string(sentence, flag):
    if flag == "slow":
        for char in sentence:
            sys.stdout.write(char)
            sys.stdout.flush()
            time.sleep(0.09)
        print()
    else:
        print(sentence)

# it creates the summary that must be printed in session 2
def create_string_list(list):
    string_list = list[0]
    if len(list) != 1:
        i = 1
        while i < len(list)-1:  # all elements but the last one
            string_list = string_list + ", " + list[i]
            i += 1
        string_list = string_list + ", and " + list[i]
    return string_list

# it adds the needed particles to the given reactions
def add_particles(reaction, keyword):
    composed_sentence = ""
    if "thoughts1" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you are worried they " + reaction
    elif "thoughts2" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you are worried to seem " + reaction
    elif "thoughts3" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you are worried that " + reaction
    elif "phys1" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you become " + reaction
    elif "phys2" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you start " + reaction
    elif "phys3" in keyword or "sft" in keyword or "focus" in keyword or "sit" in keyword:
        reaction = to_second_person(reaction)
        composed_sentence = "you " + reaction
    return composed_sentence

def add_particles_from_topic(reaction):
    typology = kbm.find_typology(reaction)
    replacement = ""
    if typology == "phys1":
        replacement = "become " + reaction
    elif typology == "phys2":
        replacement = "start " + reaction
    elif typology == "phys3":
        replacement = reaction
    return replacement

# it changes the first person in user's sentence to the second person
def to_second_person(reaction):
    reaction = reaction.replace("I ", "you ")
    reaction = reaction.replace(" me", " you")
    reaction = reaction.replace(" my", " your")
    return reaction

# it returns sentence stems
def find_stems(sentence):
    ps = PorterStemmer()
    sentence = sentence.lower()
    words = sentence.split()
    sentence_stems = ""
    for word in words:
        if sentence_stems:
            sentence_stems = sentence_stems + " " + ps.stem(word)
        else:  # the first time the white space must not be present
            sentence_stems = sentence_stems + ps.stem(word)
    print("find_stems:", sentence_stems)
    return sentence_stems

# it takes a sentence from the given topic
def choose_sentence(topic):
    grm = open("data/grammar/" + topic + ".grm", "r")
    topic_file = grm.read()
    grm.close()
    sentences = (topic_file.split(";")[1])
    sentences_list = re.findall("{topic}.+", sentences)
    # . -> Any character (except newline character)
    # + -> One or more occurrences
    sentence = sentences_list[random.randint(0, len(sentences_list)-1)]
    sentence = sentence[7:len(sentence)]  # remove {topic}
    sentence = choose_optional(sentence)
    sentence = choose_slots(sentence)
    sentence = choose_pipe(sentence)
    return sentence

# it decides whether to keep the string between the brackets
def choose_optional(sentence):
    while "[" in sentence:
        index_left_bracket = sentence.find("[")
        index_right_bracket = sentence.find("]")
        in_brackets = sentence[index_left_bracket+1:index_right_bracket]
        include = random.randint(0, 1)
        if include:
            sentence = sentence.replace("[" + in_brackets + "]", in_brackets)
        else:
            sentence = sentence.replace("[" + in_brackets + "]", "")
    return sentence

# it chooses an appropriate slot to be replaced
def choose_slots(sentence):
    system_file = open("data/sistemi.igrm", "r")
    system = system_file.read()
    system_file.close()
    while "{" in sentence:
        index_left_bracket = sentence.find("{")
        index_right_bracket = sentence.find("}")
        slot = sentence[index_left_bracket:index_right_bracket+1]
        synonyms = (system.split(slot+" =\n")[1]).split("\n;")[0]
        syn_list = (synonyms.split("\n"))
        sentence = sentence.replace(slot, syn_list[random.randint(0, len(syn_list)-1)])
    return sentence

# it chooses which part of the string in brackets to keep
def choose_pipe(sentence):
    while "(" in sentence:
        index_left_bracket = sentence.find("(")
        index_right_bracket = sentence.find(")")
        in_brackets = sentence[index_left_bracket+1:index_right_bracket]
        in_brackets_list = in_brackets.split("|")
        chosen = in_brackets_list[random.randint(0, len(in_brackets_list)-1)]
        sentence = sentence.replace("("+in_brackets+")", chosen)
    return sentence