#!/usr/bin/env python3
import matplotlib.pyplot as plt
import csv
import math
from statistics import mean
import sys

def add_or_append(_dict, _key, _elt):
    if _key in _dict:
        _dict[_key] += [_elt]
    else:
        _dict[_key] = [_elt]

def constr_dict(_list, _keygen):
    _dict = {}
    for x in _list:
        y, z = _keygen(x)
        add_or_append(_dict, y, z)
    return _dict

axes_fontsize = 13
legend_fontsize = 13

threadNumFilter = [2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16]
methodName = {"par0": "Lifted", "par1": "Splitting"}
methodColor = {"par0": "#B00020", "par1": "#3700B3"}
sizeLineStyle = {1: ':',
                 2: (0, (2, 10)),
                 3: (0, (3, 9)),
                 4: (0, (4, 8)),
                 5: (0, (5, 10)),
                 6: (0, (6, 5)),
                 7: (0, (5, 1)),
                 8: '-.',
                 9: '-'}

# lis       ,      par1,         100000,         0,         8, 0.0001696,   2.70873
nameIndex = 0
methodIndex = 1
sizeIndex = 2
distrIndex = 3
numThreadsIndex = 4
speedupIndex = 6

def plot_for_size(name, size, s_measures, sizeFilter):
    fig = plt.figure(figsize=(7, 5), dpi=80, facecolor='w', edgecolor='k')
    ax = fig.add_subplot(1, 1, 1)
    chartname = "lis_n=%i.pdf" % size
    print(chartname)
    for_method = constr_dict(s_measures, lambda l: (l[methodIndex], l))

    for method, m_measures in for_method.items():
        method = method.strip()
        if not (method == "seq0"):
            for_distr = constr_dict(m_measures,
                                    lambda l: (int(l[distrIndex]),
                                               [int(l[numThreadsIndex]), float(l[speedupIndex])]))

            for distr, d_measures in for_distr.items():
                distrNum = math.log10(distr)
                if distrNum in sizeFilter:
                    for_thread = constr_dict(
                        d_measures, lambda l: (l[0], l[1]))
                    plot_data = []
                    for tc, speedups in for_thread.items():
                        if tc in threadNumFilter:
                            plot_data += [(tc, mean(speedups))]
                    threads, speedups = zip(*plot_data)
                    _label = "%s (%1.2f)" % (
                        methodName[method], float(math.log10(distr) / math.log10(size)) * 0.75)
                    ax.plot(threads, speedups,
                            color=methodColor[method],
                            label=_label,
                            linestyle=sizeLineStyle[distrNum])

            # plt.minorticks_on()
    plt.setp(ax.get_xticklabels(), fontsize=axes_fontsize)
    plt.setp(ax.get_yticklabels(), fontsize=axes_fontsize)
    plt.legend(bbox_to_anchor=(0.01, 0.75, 0.60, 1.102), loc=3,
               ncol=2, mode="expand", borderaxespad=0.,
               prop={'size': legend_fontsize})
    ax.set_ylabel('speedup parallel / sequential', fontsize=axes_fontsize)
    ax.set_xlabel('number of threads', fontsize=axes_fontsize)
    ax.grid(b=True, which="major", color=(0.8, 0.8, 0.8))
    ax.axhline(y=1, color=(0.9, 0.9, 0.9))
    ax.margins(x=0.01)
    # ax.grid(b=True, which="minor", color=(0.9, 0.9, 0.9))
    fig.tight_layout(pad=0.05)
    plt.savefig(chartname)
    return chartname

def plot_lis(datafile, nofilter=False):
    chartNames = []
    sizeFilter = [1, 5, 7, 8, 9]
    if nofilter:
        sizeFilter = [1, 2, 3, 4, 5, 6, 7, 8, 9]

    with open(datafile, 'r') as csvfile:
        data = constr_dict(csv.reader(csvfile, delimiter=","),
                           lambda x: (x[nameIndex], x))

    for name, measures in data.items():
        for_size = constr_dict(measures, lambda l: (int(l[sizeIndex]), l))

        for size, s_measures in for_size.items():
            chartNames.append(plot_for_size(
                name, size, s_measures, sizeFilter))
    return chartNames

if __name__ == "__main__":
    # plot_pareto_stair_scatter_threads("exp_par_stair_scatter.csv")
    if len(sys.argv) < 2:
        print("Usage: python3 plot_figure7c.py CSV_INPUT_FILE")
    else:
        csvInputFileName = sys.argv[1].strip()
        plot_lis(csvInputFileName, nofilter=(len(sys.argv) > 2))


"""
This script is used to get detailed data about experiments from the 'learning1'.

Unfortunately, it cannot be used as-is because it relies on the Smart Grid
simulator (located in `/Users/rchaput/PhD/Code`) and experiments data
(located in `../data/contribution1/remote/`).
It is provided just in case, to show how the experiments data were processed
to produce `agents_details.pkl.xz`.

Detailed data include:
- rewards per agent at each time step
- properties (comfort, equity, ...) about agents at each time step
- etc.
"""

import os
from pathlib import Path
from glob import glob
import sys
import traceback

import pandas as pd
from tqdm import tqdm

from scripts.common import get_run_id

sys.path.insert(0, '/Users/rchaput/PhD/Code')
from src.simulator import Simulator

# Paths to the different folders
data_dir = (Path(__file__).parent / '..' / 'data/contribution1').resolve()
print(f'Data dir = {data_dir}')
experiments_dir = data_dir / 'remote'
print(f'Experiments dir = {experiments_dir}')

# Variables that describe both our experiments and the file hierarchy
all_models = ['DDPG', 'MADDPG', 'Q-DSOM-1', 'Q-SOM-1']
all_profiles = ['annually']
all_sizes = ['small']
all_rewards = ['equity', 'overconsumption', 'multiobj-prod', 'multiobj-sum',
               'adaptability1', 'adaptability2']

def get_details():
    data = []
    for model in tqdm(all_models, position=0):
        for profile in tqdm(all_profiles, position=1):
            for size in tqdm(all_sizes, position=2):
                for reward in tqdm(all_rewards, position=3):
                    path = os.path.join(experiments_dir, model, profile, size, reward)
                    runs = glob(f'{path}/job_*/run_*/')
                    for run in tqdm(runs, position=4):
                        try:
                            run_id = get_run_id(run)
                            sim = Simulator.load(os.path.join(run, 'data.pkl.bz'))
                            for num_step, step in tqdm(enumerate(sim.env.history), position=5):
                                for agent in tqdm(sim.env.agents, position=6):
                                    agent_reward = step.rewards[agent]
                                    agent_comfort = step.agent_comfort[agent]
                                    data.append({
                                        'Model': model,
                                        'ConsumptionProfile': profile,
                                        'EnvironmentSize': size,
                                        'RewardFunction': reward,
                                        'Run': run_id,
                                        'Step': num_step,
                                        'Agent': agent.name,
                                        'Reward': agent_reward,
                                        'Comfort': agent_comfort,
                                    })
                            del sim
                        except:
                            traceback.print_exc()
    df = pd.DataFrame(data)
    return df

if __name__ == '__main__':
    df = get_details()
    result_file = data_dir / 'agents_details.pkl.xz'
    df.to_pickle(result_file, compression='xz')


import socket
import thread
import xml.etree.ElementTree as ET
import emb

x = 0.0
y = 0.0
z = 0.0

posLock = thread.allocate_lock()
goLock = thread.allocate_lock()

host = '127.0.0.1'
port = 1000
BUF_SIZE = 1024

theID = 0
sock = None

def Parse(document):
    import xml.dom.minidom
    from xml.dom.minidom import Node
    dom = xml.dom.minidom.parseString(document)

    for name in dom.getElementsByTagName("user"):
        theID = name.getAttribute('id')
        children = name.getElementsByTagName("pos")
        for child in children:
            if child.nodeType == Node.ELEMENT_NODE:
                emb.update_user(
                    int(theID),
                    float(child.getAttribute("x")),
                    float(child.getAttribute("y")),
                    float(child.getAttribute("z"))
                    )

def SetPos(newx, newy, newz):
    global x, y, z, posLock
    posLock.acquire()
    x, y, z = newx, newy, newz
    posLock.release()

def Connect():
    global host, port, BUF_SIZE, sock, theID
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((host, port))
    theID = sock.recv( BUF_SIZE )
    return int(theID)

def Run():
    global sock, theID
    allinfo = sock.recv(2048)
    Parse(str(allinfo))
    return allinfo

def Send():
    global sock, theID
    pos = '<user id="' + theID + '">'
    posLock.acquire()
    pos += '<pos x="' + str(x) + '" y="' + str(y) + '" z="'+ str(z) + '"/>'
    posLock.release()
    pos += "</user>"
    sock.send(pos)

if __name__=="__main__":
    Connect()
    while 1:
        Run()
        Send()
#   locks = []
#
#    lock = thread.allocate_lock()
#    lock.acquire()
#    locks.append(lock)
#    thread.start_new_thread( mailLoop, (lock, ) )
#
#    for i in range( len(locks) ):
#        while locks[ i ].locked() : pass


from __future__ import print_function
from lib import file_tools as ft
from lib import streamlit_wrapper as mlib
from data.daos import dao_facade_streamlit as dao_fac

import config_logging
import controllers.sd_report_type_passed_controller as sd_report_controller
import logging
# import managers.sd_report_type_crime as sd_report_man_crime

## TIDY
import managers.sd_report_type_general as sd_report_man_general

# import managers.sd_report_type_health as sd_report_man_health
# import managers.sd_report_type_income as sd_report_man_income
import streamlit as st

import uuid

log = logging.getLogger(__name__)

def clear_text():
    st.session_state["search_borough"] = ""
    st.session_state["search_ward_name"] = ""
    st.session_state["search_post_code"] = ""

session_id = str(uuid.uuid4())[:8]

query_params = st.experimental_get_query_params()
log.debug(f"query_params:{query_params}")

url_search_city = ""
url_search_borough = ""
url_search_ward_name = ""
url_search_post_code = ""
url_report_type = "General"
url_report_auto_generate = ""

if "search_city" in  query_params:
    url_search_city = query_params["search_city"][0]

if "search_borough" in  query_params:
    url_search_borough = query_params["search_borough"][0]

if "search_ward_name" in  query_params:
    url_search_ward_name = query_params["search_ward_name"][0]

if "search_post_code" in  query_params:
    url_search_post_code = query_params["search_post_code"][0]

if "report_type" in  query_params:
    url_report_type = query_params["report_type"][0]

if "report_auto_generate" in  query_params:
    url_report_auto_generate = query_params["report_auto_generate"][0]

##
## Start of Streamlit
##
st.markdown("# SD Map Reports")
st.sidebar.markdown("#  SD Map Reports")

def x(borough_wards, borough_ward_name=None):
  # print("in x")
  search_terms_options = []
  if borough_ward_name == None:
    borough_wards_reduced = borough_wards
    for borough_name in borough_wards_reduced.keys():
      # print(f"{borough_name}")
      search_terms_options.append(borough_name)

      for ward_name in borough_wards_reduced[borough_name]['WARD_NAMES']:
        # print(f"\t{ward_name}")
        search_terms_options.append(ward_name)

  elif borough_ward_name != None:
    # print("Not None")
    if len(borough_ward_name) == 1:
      # print("1")
      # print(f"x:ward_name:{borough_ward_name[0]}")
      borough_wards_reduced = borough_wards[borough_ward_name[0]]
      print(borough_wards_reduced )

      for ward_name in borough_wards_reduced['WARD_NAMES']:
        # print(f"\t{ward_name}")
        search_terms_options.append(ward_name)

  return search_terms_options

## Input the post code to search with
## City
search_city = url_search_city if url_search_city != "" else "London"
search_borough   = st.text_input("Borough", value=url_search_borough, key="search_borough", help="Borough you want to analyse")
search_ward_name = st.text_input("Ward Name", value=url_search_ward_name, key="search_ward_name", help="Ward in the borough you want to analyse")
search_post_code = st.text_input("Post Code", value=url_search_post_code, key="search_post_code", help="Post Code in the City you want to analyse")

## Clear input text
st.button("Clear", on_click=clear_text)
#report_type_idx = {"Crime":0, "General":1, "Health":2, "Earnings":3}

report_type_idx = {"General":0}

# print(f"url_report_type:{url_report_type}")
# print(report_type_idx[url_report_type])

# report_type = None

## These will come from a json file I think, but for now, we'll hard code them
# report_type_options = {"Crime":{"Full Report"}, "General":{"Full Report", "Condensed Report"}, "Health":{"Full Report"}, "Earnings":{"Full Report"}}
report_type_options = {"General":{"Full Report"}}
## Choose the initial set to dispaly as options
report_type_option = report_type_options[url_report_type]
## Stick it into the streamlit session
st.session_state.report_type_option = report_type_option

def report_type_on_chage():
  """
  When the report_type selectbox chnages we need to set the
  value for the options
  """
  if "report_type" in st.session_state:
    if st.session_state.report_type != None:
        ## Update the available options for the report_type
        report_type_option = report_type_options[st.session_state.report_type]
        ## Stick it into the streamlit session
        st.session_state.report_type_option = report_type_option

## This is the report type
report_type = st.selectbox(key="report_type",
                           label="Report Type",
                           # options=["Crime", "General", "Health", "Earnings"],
                           options=["General"],
                           index=report_type_idx[url_report_type],
                           on_change = report_type_on_chage())

## And the options of the report we can choose from
report_option = st.selectbox(key="report_option",
                             label="Report Option",
                             options=st.session_state.report_type_option)

st.session_state["report_option_obj"] = report_option

year_from_to = st.slider("Date Range", min_value=2010, max_value=2022, value=[2010,2022], step=1)
# year_from_to = st.slider("Date Range", min_value=2001, max_value=2022, value=[2001,2022], step=1)

## Capture the input and run generate_report
if url_report_auto_generate != "" and url_report_auto_generate.lower() == "true":
    generate_report_link = True
else:
    generate_report_link = st.button("Generate Report")

##
## Generate Link
##
if generate_report_link:

    search_term = {"city"      : search_city
                 , "borough"   : search_borough
                 , "ward_name" : search_ward_name
                 , "post_code" : search_post_code
                 , "year_from" : year_from_to[0]
                 , "year_to"   : year_from_to[1]}

    ## Generate a context to place items in which is used when generating the report in the final step
    report_context = {}
    # report_context["template_processor_file_name"] = "./reports/processors/sd_general_report_data_manager.json"
    ### This should come from another drop down
    report_context["report_option"] = report_option

    ## This comes from Streamlit so fake here
    properties = st.secrets

    try:
        log.debug(f"report_type:{report_type}")

        rep_man = None
        if report_type == "Crime":
            rep_man = sd_report_man_crime
        elif report_type == "General":
            rep_man = sd_report_man_general
            template_processor_file_name = "./reports/processors/sd_general_report_template_processor.json"
            report_context["template_processor_file_name"] = template_processor_file_name

        elif report_type == "Health":
            rep_man = sd_report_man_health
        elif report_type == "Earnings":
            rep_man = sd_report_man_income

        generated_report = rep_man.generate_report(session_id=session_id, search_term=search_term, report_context=report_context, properties=properties, lib=mlib, dao_fac=dao_fac)

        ###
        ### Read in the document to send out on the link
        ###
        for file in [generated_report]:
                with open(file, "rb") as report:
                    encoded = report.read()

        city      = report_context["city"]
        borough   = report_context["borough"]
        ward_name = report_context["ward_name"]
        post_code = report_context["post_code"]

        gernerated_report_download = "sd_{}_report_{}_{}_{}{}{}.docx".format(report_type.lower(), city, borough, ward_name, ("_" if post_code != "" else ""), post_code).replace(" ", "_")

        html_link = mlib.create_download_link(encoded , gernerated_report_download, f"[{report_type} - {report_option}]")

        st.markdown(html_link, unsafe_allow_html=True)
    except Exception as e:
        st.error(e)


import json as json
import http.client, urllib.request, urllib.parse, urllib.error, base64
import pandas as pd
from time import sleep

# Return United State locations
def retrieve_all_us_states(api_key):

    headers = {'token': api_key}

    try:
        conn = http.client.HTTPSConnection('www.ncdc.noaa.gov')

        conn.request("GET", "/cdo-web/api/v2/locations?locationcategoryid=ST&limit=52" ,None,  headers)
        response = conn.getresponse()
        data = response.read()
        jdata = json.loads(data.decode("utf-8") )

        df = pd.DataFrame(data=jdata['results'])

        conn.close()

        return df
    except Exception as e:
        print(e)
        return pd.DataFrame()

def retrieve_data_sets(api_key):

    headers = {'token': api_key}

    try:
        conn = http.client.HTTPSConnection('www.ncdc.noaa.gov')

        conn.request("GET", "/cdo-web/api/v2/datasets?limit=100" ,None,  headers)
        response = conn.getresponse()
        data = response.read()
        jdata = json.loads(data.decode("utf-8") )

        df = pd.DataFrame(data=jdata['results'])

        conn.close()

        return df
    except Exception as e:
        print(e)
        return pd.DataFrame()

def retrieve_data_categories(api_key):

    headers = {'token': api_key}

    try:
        conn = http.client.HTTPSConnection('www.ncdc.noaa.gov')

        conn.request("GET", "/cdo-web/api/v2/datacategories?limit=100" ,None,  headers)
        response = conn.getresponse()
        data = response.read()
        jdata = json.loads(data.decode("utf-8") )

        df = pd.DataFrame(data=jdata['results'])

        conn.close()

        return df
    except Exception as e:
        print(e)
        return pd.DataFrame()

def retrieve_data_types_by_categoryid(api_key, datacategoryid= 'TEMP'):

    headers = {'token': api_key}

    params = urllib.parse.urlencode({
      'datacategoryid':datacategoryid,
      'limit':1000
    })

    try:
        conn = http.client.HTTPSConnection('www.ncdc.noaa.gov')

        conn.request("GET", "/cdo-web/api/v2/datatypes?%s" % params ,None,  headers)
        response = conn.getresponse()
        data = response.read()
        jdata = json.loads(data.decode("utf-8") )

        df = pd.DataFrame(data=jdata['results'])

        conn.close()

        return df
    except Exception as e:
        print(e)
        return pd.DataFrame()

def retrieve_weather(api_key,start,stop,fips,datasetid='GHCND',datatype='TAVG' ):

  offset = 0 #staring offset
  remaining = 100 #default, gets overwritten
  cnt = 1 #used as limit multiplier
  limit = 1000 #bring back full 1000 limit from NOAA API
  retry = 0

  print("Start: " + start + " Stop: " + stop )
  print(fips)
  print(datasetid)
  print(datatype)

  tempdata = pd.DataFrame({'A' : [1]})

  # NOAA API limits records to 1000, loop until all records for call are returned
  while remaining > 0:

    headers = {
      'token': api_key
    }

    params = urllib.parse.urlencode({
      'datasetid':datasetid,
      'locationid': fips,
      'startdate':start,
      'enddate': stop,
      'limit':limit,
      'units':'standard',
      'datatypeid':datatype,
      'offset':offset
    })

    try:
        conn = http.client.HTTPSConnection('www.ncdc.noaa.gov')

        conn.request("GET", "/cdo-web/api/v2/data?%s" % params,None,  headers)
        response = conn.getresponse()
        data = response.read()
        jdata = json.loads(data.decode("utf-8") )

        conn.close()
    except Exception as e:
        print(e)

    if 'metadata' in jdata.keys():

        #How many records are in the result set
        recCount = int(jdata['metadata']['resultset']['count'])

        #offset by returned records (anything less than full limit will be last loop)
        offset += limit

        #calc remaining records for debugging
        remaining = recCount - (limit*cnt)

        print(remaining)

        df = pd.DataFrame(data=jdata['results'])

        if cnt <=1:
            tempdata = df

        else:
            tempdata = tempdata.append(df)

        cnt+=1

        sleep(2)
    else:
        print('no metadata')
        if retry > 6:
            return tempdata
        else:
            retry += 1
            sleep(4)

  return tempdata


import time, cv2, threading, math
import mediapipe as mp, numpy as np
from mediapipe.tasks import python
# from scipy.spatial import distance as dist
# from imutils import face_utils

class GestureRecognizer:
    def main(self):
        num_hands = 2

        model_path1 = 'D:/Proj/HandReg/env/project/keep/model/gesture_recognizer.task'
        model_path2 = 'D:/Proj/HandReg/env/project/keep/model/gesture_recognizer_ok.task'

        GestureRecognizer1 = mp.tasks.vision.GestureRecognizer
        GestureRecognizerOptions1 = mp.tasks.vision.GestureRecognizerOptions
        VisionRunningMode1 = mp.tasks.vision.RunningMode

        self.lock1 = threading.Lock()
        self.current_gestures1 = []

        self.lock2 = threading.Lock()
        self.current_gestures2 = []

        options1 = GestureRecognizerOptions1(base_options=python.BaseOptions(model_asset_path=model_path1), running_mode=VisionRunningMode1.LIVE_STREAM, num_hands = num_hands, result_callback=self.__result_callback1)

        options2 = GestureRecognizerOptions1(base_options=python.BaseOptions(model_asset_path=model_path2), running_mode=VisionRunningMode1.LIVE_STREAM, num_hands = num_hands, result_callback=self.__result_callback2)

        recognizer1 = GestureRecognizer1.create_from_options(options1)

        recognizer2 = GestureRecognizer1.create_from_options(options2)

        timestamp = 0
        timestamp2 = 0
        mp_drawing = mp.solutions.drawing_utils
        mp_hands = mp.solutions.hands
        hands = mp_hands.Hands(static_image_mode=False, max_num_hands=num_hands, min_detection_confidence=0.65, min_tracking_confidence=0.65)

        self.count = 0
        self.count2 = 0

        cap = cv2.VideoCapture(0)
        # cap = cv2.VideoCapture("rtsp://admin:admin@192.168.7.160:554/2/1")
        # cap = cv2.VideoCapture("rtsp://admin:$Gets12345@172.24.1.9:30180/live")

        self.isCount = False

        # self.fourcc = cv2.VideoWriter_fourcc(*"MP4V") # screen recoder*********
        # self.writer = cv2.VideoWriter(r'D:/Proj/HandReg/env/project/keep/video/eyeshand_gesture250966.mp4', self.fourcc, 20, (int(cap.get(3)), int(cap.get(4)))) # screen recoder*********

        COUNTER = 0
        TOTAL_BLINKS = 0
        WITHIN = 1
        CLOSED_EYES_FRAME = 1
        FONT_SIMP = cv2.FONT_HERSHEY_SIMPLEX
        FONT_COMP = cv2.FONT_HERSHEY_COMPLEX

        LEFT_EYE =[ 362, 382, 381, 380, 374, 373, 390, 249, 263, 466, 388, 387, 386, 385,384, 398 ]
        RIGHT_EYE=[ 33, 7, 163, 144, 145, 153, 154, 155, 133, 173, 157, 158, 159, 160, 161 , 246 ]

        iscount = False
        c_time = None
        oldblink = 0

        map_face_mesh = mp.solutions.face_mesh
        face_mesh = map_face_mesh.FaceMesh(min_detection_confidence = 0.5, min_tracking_confidence = 0.5)

        while True:
            ret, frame = cap.read()
            if not ret:
                break
            # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            result = hands.process(frame)
            frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
            np_array = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

            if result.multi_hand_landmarks:
                # list_hands = result.multi_hand_landmarks
                for hand_landmarks in result.multi_hand_landmarks:
                    mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
                    mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=np_array)
                    recognizer1.recognize_async(mp_image, timestamp)
                    timestamp = timestamp + 1
                    recognizer2.recognize_async(mp_image, timestamp2)
                    timestamp2 = timestamp2 + 1

                self.put_gestures(frame)

            #eye blinks
            rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            results = face_mesh.process(rgb_frame)
            if results.multi_face_landmarks:
                mesh_coords = self.landmarksDetection(frame, results, False)
                ratio = self.blinkRatio(frame, mesh_coords, RIGHT_EYE, LEFT_EYE)

                if ratio > 4: # close eye
                    COUNTER += 1
                    # print(COUNTER)
                else:
                    if COUNTER > CLOSED_EYES_FRAME: #For blink and count
                        TOTAL_BLINKS += 1
                        COUNTER = 0

                if TOTAL_BLINKS > 0:
                    if not iscount:
                        s_time = time.time()
                        oldblink += 1
                        iscount = True
                    else:
                        c_time = time.time()
                        if c_time-s_time < WITHIN and TOTAL_BLINKS > oldblink:
                            s_time = time.time()
                            iscount = False
                        elif c_time-s_time > WITHIN:
                            s_time = time.time()
                            iscount = False
                            TOTAL_BLINKS = oldblink = 0

                if TOTAL_BLINKS >= 3:
                    cv2.rectangle(frame, (5, 70), (220, 100), (255, 255, 255), -1)
                    cv2.putText(frame, f"Eyes detected", (10, 90), FONT_SIMP, 0.7, (0, 0, 255), 2)
                    cv2.rectangle(frame, (50, 210), (410, 150), (255, 255, 255), -1)
                    cv2.putText(frame, "HELP ME!!!", (50, 200), FONT_COMP, 2, (0,0,255), 2, cv2.LINE_AA)

                if iscount and c_time is not None:
                    cv2.putText(frame, f"time(s): {c_time-s_time:.2f}", (10, 60), FONT_SIMP, 0.7, (0, 0, 255), 2)

                cv2.putText(frame, "Blinks: {}".format(TOTAL_BLINKS), (10, 30), FONT_SIMP, 0.7, (0, 0, 255), 2)

                cv2.rectangle(frame, (3, frame.shape[0]-50), (frame.shape[1]-5, frame.shape[0]-10), (255, 255, 255), -1)
                cv2.putText(frame, "blink 3 times continuously = need help", (6, frame.shape[0]-20), FONT_SIMP, 1, (0, 0, 255), 2)

            # self.writer.write(frame) # screen recoder*********
            cv2.imshow('MediaPipe Hands', frame)
            if cv2.waitKey(1) & 0xFF == 27:
                break
            elif cv2.waitKey(1) == 32:
                help = False

        # self.writer.release() # screen recoder*********
        cap.release()

    def landmarksDetection(self, img, results, draw=False):
        img_height, img_width = img.shape[:2]
        mesh_coord = [(int(point.x * img_width), int(point.y * img_height)) for point in results.multi_face_landmarks[0].landmark]
        if draw:
            [cv2.circle(img, p, 2, (0, 255, 0), -1) for p in mesh_coord]
        return mesh_coord

    # Euclaidean distance
    def euclaideanDistance(self, point, point1):
        x, y = point
        x1, y1 = point1
        distance = math.sqrt((x1 - x)**2 + (y1 - y)**2)
        return distance

    # Blinking Ratio
    def blinkRatio(self, img, landmarks, right_indices, left_indices):
        # Right eyes
        # horizontal line
        rh_right = landmarks[right_indices[0]]
        rh_left = landmarks[right_indices[8]]
        # vertical line
        rv_top = landmarks[right_indices[12]]
        rv_bottom = landmarks[right_indices[4]]
        # draw lines on right eyes
        # cv.line(img, rh_right, rh_left, utils.GREEN, 2)
        # cv.line(img, rv_top, rv_bottom, utils.WHITE, 2)

        # LEFT_EYE
        # horizontal line
        lh_right = landmarks[left_indices[0]]
        lh_left = landmarks[left_indices[8]]

        # vertical line
        lv_top = landmarks[left_indices[12]]
        lv_bottom = landmarks[left_indices[4]]

        rhDistance = self.euclaideanDistance(rh_right, rh_left)
        rvDistance = self.euclaideanDistance(rv_top, rv_bottom)

        lvDistance = self.euclaideanDistance(lv_top, lv_bottom)
        lhDistance = self.euclaideanDistance(lh_right, lh_left)

        reRatio = rhDistance/rvDistance
        leRatio = lhDistance/lvDistance

        ratio = (reRatio+leRatio)/2
        return ratio

    def put_gestures(self, frame):
        self.lock1.acquire()
        gestures = self.current_gestures1
        self.lock1.release()
        y_pos = 200

        self.lock2.acquire()
        gestures2 = self.current_gestures2
        self.lock2.release()

        # print(gestures2)

        for hand_gesture_name in gestures2:
            if (hand_gesture_name == 'ok'):
                self.count += 1
                if self.count > 15:
                    cv2.rectangle(frame, (50, 210), (160, 150), (255, 255, 255), -1)
                    cv2.putText(frame, "OK", (50, 200), cv2.FONT_HERSHEY_COMPLEX, 2, (0,0,255), 2, cv2.LINE_AA)
            else:
                self.count = 0

        for hand_gesture_name in gestures:

            # print(hand_gesture_name)

            if (hand_gesture_name == 'Thumb_Up'):
                # print('count: ', self.count2)
                self.count2 += 1
                if self.count2 > 15:
                    cv2.rectangle(frame, (50, 210), (210, 150), (255, 255, 255), -1)
                    cv2.putText(frame, "Good", (50, 200), cv2.FONT_HERSHEY_COMPLEX, 2, (0,0,255), 2, cv2.LINE_AA)
            else:
                self.count2 = 0

            if (hand_gesture_name == 'Open_Palm'):
                # print('hello')
                self.start_time = time.time()
                self.isCount = True
                # print('Open_Palm: ', self.start_time)

            if (hand_gesture_name == 'Closed_Fist' and self.isCount):
                self.end_time = time.time()
                self.total_time = self.end_time - self.start_time

                if self.total_time < 3:
                    cv2.rectangle(frame, (5, 70), (220, 100), (255, 255, 255), -1)
                    cv2.putText(frame, f"Hand detected", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
                    cv2.rectangle(frame, (50, 210), (410, 150), (255, 255, 255), -1)
                    cv2.putText(frame, "HELP ME!!!", (50, 200), cv2.FONT_HERSHEY_COMPLEX, 2, (0,0,255), 2, cv2.LINE_AA)

            y_pos += 100

    def __result_callback1(self, result, output_image, timestamp_ms):
        self.lock1.acquire()
        self.current_gestures1 = []
        if result is not None and any(result.gestures):
            # print("Recognized gestures: ")
            for single_hand_gesture_data in result.gestures:
                gesture_name = single_hand_gesture_data[0].category_name
                # print(gesture_name)

                self.current_gestures1.append(gesture_name)
        self.lock1.release()

    def __result_callback2(self, result, output_image, timestamp_ms):
        self.lock2.acquire()
        self.current_gestures2 = []
        if result is not None and any(result.gestures):
            # print("Recognized gestures: ")
            for single_hand_gesture_data in result.gestures:
                gesture_name = single_hand_gesture_data[0].category_name
                # print(gesture_name)

                self.current_gestures2.append(gesture_name)
        self.lock2.release()

if __name__ == "__main__":
    rec = GestureRecognizer()
    rec.main()


import pygame
from plane_sprite import *

pygame.init()

screen = pygame.display.set_mode((480, 650))

# initialize the game
bg = pygame.image.load('./images/background.png')
screen.blit(bg, (0, 0))

hero = pygame.image.load('./images/me1.png')
screen.blit(hero, (150, 300))

pygame.display.update()

# set clock
clock = pygame.time.Clock()

# set hero rect
hero_rect = pygame.Rect(150, 300, 102, 126)

# create sprites
enemy = GameSprite('./images/enemy1.png')
enemy1 = GameSprite('./images/enemy1.png', speed=2)

# create sprite group
enemy_group = pygame.sprite.Group(enemy, enemy1)

while True:
    clock.tick(60)
    hero_rect.y -= 1

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    if hero_rect.y <= -126:
        hero_rect.y = 650

    screen.blit(bg, (0, 0))
    screen.blit(hero, hero_rect)

    enemy_group.update()
    enemy_group.draw(screen)

    pygame.display.update()

pygame.quit()


# -*- coding: utf-8 -*-
# Created on Wed Feb 27 2019 8:40:28
# Author: WuLC
# EMail: liangchaowu5@gmail.com

# record the number of lights at each row, column, left diagonal and right diagonal
# use hashmap instead of list to avoid memory limit exceeded

from collections import defaultdict

class Solution(object):
    def gridIllumination(self, N, lamps, queries):
        """
        :type N: int
        :type lamps: List[List[int]]
        :type queries: List[List[int]]
        :rtype: List[int]
        """
        row, col = defaultdict(int), defaultdict(int)
        left_diagonal, right_diagonal = defaultdict(int), defaultdict(int)
        source = defaultdict(set)
        for i, j in lamps:
            source[i].add(j)
            row[i] += 1
            col[j] += 1
            left_diagonal[i+j] += 1
            right_diagonal[i-j] += 1

        result = []
        for i, j in queries:
            if row[i] > 0 or col[j] > 0 or left_diagonal[i+j] > 0 or right_diagonal[i-j] > 0:
                result.append(1)
            else:
                result.append(0)
            for r in [i-1, i+2]:
                for c in [j-1, j+2]:
                    if c in source[r]:
                        row[r] -= 1
                        col[c] -= 1
                        left_diagonal[r+c] -= 1
                        right_diagonal[r-c] -= 1
        return result


'''
    clone from: https://github.com/AvivYaish/SMTsolver/blob/master/smt_solver/sat_solver/sat_solver.py
'''

from collections import deque, Counter
from pprint import pprint
import sortedcontainers
import random
import copy
import time

class CDCLSolver:

    def __init__(self, formula, variables=None, max_new_clauses=float('inf'), halving_period=float('inf'),
                 layers_mapping=None, decider=None, theory_solver=None
            ):
        if formula is None:
            self._formula = set()
        else:
            self._formula = formula

        # theory
        self._theory_solver = theory_solver
        self._decider = decider

        self._max_new_clauses = max_new_clauses
        self._halving_period = halving_period

        self._assignment = dict()
        self._assignment_by_level = []
        self._satisfaction_by_level = []
        self._literal_to_clause = {}
        self._satisfied_clauses = set()
        self._last_assigned_literals = deque()
        self._variable_to_watched_clause = {}

        self._all_vars = sortedcontainers.SortedList(variables)

        for var in self._all_vars:
            self._formula.add(frozenset({var, -var}))

        for clause in self._formula:
            self._add_clause(clause)

        # print(variables)
        # exit()
        self.initialized = False

        self._learned_conflict_clauses = set()

    def _add_clause(self, clause):
        """
        Initialize all clause data structures for the given clause.
        """
        for idx, literal in enumerate(clause):
            variable = abs(literal)
            if literal not in self._literal_to_clause:
                self._literal_to_clause[literal] = set()
            if variable not in self._variable_to_watched_clause:
                self._variable_to_watched_clause[variable] = set()

            self._literal_to_clause[literal].add(clause)
            if idx <= 1:
                self._variable_to_watched_clause[variable].add(clause)

    def _assign(self, clause, literal: int, is_implied=False):
        """
        Assigns a satisfying value to the given literal.
        """
        variable = abs(literal)
        self._assignment[variable] = {
            "value": literal > 0,                           # Satisfy the literal
            "clause": clause,                               # The clause which caused the assignment
            "level": len(self._assignment_by_level) - 1,    # The decision level of the assignment
            "idx": len(self._assignment_by_level[-1]),      # Defines an assignment order in the same level
            "is_implied": is_implied
        }

        self._all_vars.discard(variable)

        # Keep data structures related to satisfied clauses up to date
        newly_satisfied_clauses = self._literal_to_clause[literal] - self._satisfied_clauses
        self._satisfaction_by_level[-1].extend(newly_satisfied_clauses)
        self._satisfied_clauses |= newly_satisfied_clauses

        # Keep data structures related to variable assignment up to date
        self._assignment_by_level[-1].append(variable)
        self._last_assigned_literals.append(literal)

    def _unassign(self, variable: int):
        """
        Unassigns the given variable.
        """
        del self._assignment[variable]
        self._all_vars.add(variable)

    def get_assignment(self) -> dict:
        return {var: val for var, val, _ in self.iterable_assignment()}

    def get_variable_assignment(self, variable) -> bool:
        return self._assignment.get(variable, {"value": None})["value"]

    def iterable_assignment(self):
        """
        :return: a (variable: int, value: bool) tuple for every assigned variable.
        """
        for var in self._assignment:
            yield var, self._assignment[var]["value"], self._assignment[var]["is_implied"]

    def _find_last_literal(self, clause, removed_vars=[]):
        """
        :return: the last assigned literal in the clause, the second highest assignment level of literals in the clause,
        and the number of literals from the highest assignment level.
        """
        last_literal, prev_max_level, max_level, max_idx, max_level_count = None, -1, -1, -1, 0
        for literal in clause:
            variable = abs(literal)

            # FIXME: looks not right
            if (variable in removed_vars) or (variable not in self._assignment):
                continue

            level, idx = self._assignment[variable]["level"], self._assignment[variable]["idx"]
            if level > max_level:
                prev_max_level = max_level
                last_literal, max_level, max_idx, max_level_count = literal, level, idx, 1
            elif level == max_level:
                max_level_count += 1
                if idx > max_idx:
                    last_literal, max_idx = literal, idx
            elif level > prev_max_level:
                prev_max_level = level

        if (prev_max_level == -1) and (max_level != -1):
            prev_max_level = max_level - 1
        # print('- [Find]:', last_literal, prev_max_level, max_level, max_level_count)
        return last_literal, prev_max_level, max_level, max_level_count

    def _conflict_resolution(self, conflict_clause):
        """
        Learns conflict clauses using implication graphs, with the Unique Implication Point heuristic.
        """
        # print('--------------_conflict_resolution--------------')
        conflict_clause = set(conflict_clause)
        # print('conflict_clause:', conflict_clause)
        # if frozenset(conflict_clause) not in self._generated_conflict_clauses:
        #     self._add_conflict_clause(frozenset(conflict_clause))

        removed_vars = []
        while True:
            last_literal, prev_max_level, max_level, max_level_count = self._find_last_literal(conflict_clause, removed_vars)
            if last_literal is None:
                return None, None, -1
            clause_on_incoming_edge = self._assignment[abs(last_literal)]["clause"]
            # print(last_literal, prev_max_level, max_level, max_level_count, clause_on_incoming_edge)
            if (max_level_count == 1) or (clause_on_incoming_edge is None):
                if max_level_count != 1:
                    # If the last literal was assigned because of the theory, there is no incoming edge
                    # The literal to reassign should be the decision literal of the same level
                    # print('    - last_literal before:', last_literal)
                    last_literal = self._assignment_by_level[max_level][0]
                    # print(self._assignment_by_level[max_level], conflict_clause)
                    # print('    - last_literal after:', last_literal)
                    if self._assignment[last_literal]["value"]:
                        last_literal = -last_literal
                    conflict_clause.add(last_literal)
                # If the last assigned literal is the only one from the last decision level:
                # return the conflict clause, the next literal to assign (which should be the
                # watch literal of the conflict clause), and the decision level to jump to
                return frozenset(conflict_clause), last_literal, prev_max_level

            # Resolve the conflict clause with the clause on the incoming edge
            # Might be the case that the last literal was assigned because of the
            # theory, and in that case it is impossible to do resolution
            # print('conflict_clause:', conflict_clause, 'last_literal:', last_literal)
            conflict_clause |= clause_on_incoming_edge
            # print()
            conflict_clause.remove(last_literal)
            conflict_clause.remove(-last_literal)
            removed_vars.append(abs(last_literal))

    def _bcp(self):
        """
        Performs BCP, as triggered by the last assigned literals. If new literals are assigned as part of the BCP,
        the BCP continues using them. The BCP uses watch literals.
        :return: None, if there is no conflict. If there is one, the conflict clause is returned.
        """
        # print('[bcp]', self._last_assigned_literals)

        # print('\t[variable to watched clause]')
        # for k, v in self._variable_to_watched_clause.items():
        #     print(k, '--->', v)
        # print()

        # print('\t[_satisfied_clauses]')
        # for k, v in enumerate(self._satisfied_clauses):
        #     print(k, '--->', v)
        # print()

        while self._last_assigned_literals:
            watch_literal = self._last_assigned_literals.popleft()
            # print('watch_literal:', watch_literal)
            for clause in self._variable_to_watched_clause[abs(watch_literal)].copy():
                if clause not in self._satisfied_clauses:
                    conflict_clause = self._replace_watch_literal(clause, watch_literal)
                    if conflict_clause is not None:
                        return conflict_clause
        return None  # No conflict-clause

    def _tcp(self):
        """
        Theory constraint propagation.
        """
        conflict_clause, new_assignments = self._theory_solver.propagate()
        if conflict_clause is not None:
            return conflict_clause
        for literal in new_assignments:
            self._assign(None, literal, is_implied=True)
            # print(f'- [Imply] {abs(literal)}={literal}')
        return None

    def _replace_watch_literal(self, clause, watch_literal: int):
        """
        - If the clause is satisfied, nothing to do.
        - Else, it is not satisfied yet:
          - If it has 0 unassigned literals, it is UNSAT.
          - If it has 1 unassigned literals, assign the correct value to the last literal.
          - If it has > 2 unassigned literals, pick one to become the new watch literal.
        """
        watch_variable, replaced_watcher, unassigned_literals = abs(watch_literal), False, []
        for unassigned_literal in clause:
            unassigned_variable = abs(unassigned_literal)
            if unassigned_variable in self._assignment:
                # If the current literal is assigned, it cannot replace the current watch literal
                continue
            unassigned_literals.append(unassigned_literal)

            if replaced_watcher:
                # If we already replaced the watch_literal
                if len(unassigned_literals) > 1:
                    break
            elif clause not in self._variable_to_watched_clause[unassigned_variable]:
                # If the current literal is not already watching the clause, it can replace the watch literal
                self._variable_to_watched_clause[watch_variable].remove(clause)
                self._variable_to_watched_clause[unassigned_variable].add(clause)
                replaced_watcher = True

        if len(unassigned_literals) == 0:
            # Clause is UNSAT, return it as the conflict-clause
            return clause
        if len(unassigned_literals) == 1:
            # The clause is still not satisfied, and has only one unassigned literal.
            # Assign the correct value to it. Because it is now watching the clause,
            # and was also added to self._last_assigned_literals, we will later on
            # check if the assignment causes a conflict
            literal = unassigned_literals.pop()
            self._assign(clause, literal)
            # print(f'\t- [c] {clause}, {literal}')
        return None

    def _add_conflict_clause(self, conflict_clause):
        """
        Adds a conflict clause to the formula.
        """
        # save conflict clauses
        print('conflict_clause:', conflict_clause)
        self._learned_conflict_clauses.add(conflict_clause)

        # bcp
        self._add_clause(conflict_clause)

    def _constraint_propagation_to_exhaustion(self, propagation_func):
        """
        Performs constraint propagation using the given function
        until exhaustion, returns False iff formula is UNSAT.
        """
        # print('- [BCP + TCP]', propagation_func)
        conflict_clause = propagation_func()
        while conflict_clause is not None:
            conflict_clause, watch_literal, level_to_jump_to = self._conflict_resolution(conflict_clause)
            # print(self.get_assignment(), conflict_clause)
            # print('watch_literal:', watch_literal, '\nlen:', len(list(conflict_clause)), '\nconflict_clause:', conflict_clause)
            # print(len(list(conflict_clause)), conflict_clause)
            # print()
            if level_to_jump_to == -1:
                # An assignment that satisfies the formula's unit clauses causes a conflict, so the formula is UNSAT
                return False

            self.backtrack(level_to_jump_to)
            self._add_conflict_clause(conflict_clause)
            self._assign(conflict_clause, watch_literal)
            # print(f'- [Conflict] {abs(watch_literal)}={watch_literal}, dl={level_to_jump_to}')
            # print(f'\t- [cc] {conflict_clause}, {watch_literal}')

            conflict_clause = propagation_func()
        return True

    def propagate(self) -> bool:
        if (self._theory_solver is not None) and (not self.initialized):
            self.initialized = True
            if not self._constraint_propagation_to_exhaustion(self._tcp):
                return False

        while self._last_assigned_literals:
            if (not self._constraint_propagation_to_exhaustion(self._bcp)) or \
                ((self._theory_solver is not None) and (not self._constraint_propagation_to_exhaustion(self._tcp))):
                return False
        return True

    def backtrack(self, level: int):
        """
        Non-chronological backtracking.
        """
        self._last_assigned_literals = deque()
        while len(self._assignment_by_level) > level + 1:
            for variable in self._assignment_by_level.pop():
                self._unassign(variable)
            for clause in self._satisfaction_by_level.pop():
                self._satisfied_clauses.remove(clause)

    def _decide(self):
        unassigned_variables = list(self._all_vars)
        if self._decider is None:
            variable, value = unassigned_variables[0], True
        else:
            variable, value = self._decider._get(unassigned_variables)
        assert variable not in self._assignment, print(variable, unassigned_variables)
        self.create_new_decision_level()
        self._assign(None, variable if value else -variable)

    def create_new_decision_level(self):
        self._assignment_by_level.append(list())
        self._satisfaction_by_level.append(list())

    def _satisfy_unit_clauses(self):
        # print('unit bcp')
        self.create_new_decision_level()
        for clause in self._formula:
            if len(clause) == 1:
                for literal in clause:
                    if abs(literal) not in self._assignment:
                        self._assign(clause, literal)

    def _is_sat(self) -> bool:
        return self._formula.issubset(self._satisfied_clauses)

    def solve(self, timeout=None) -> bool:
        self._satisfy_unit_clauses()
        start = time.perf_counter()
        while True:
            if timeout is not None:
                if time.perf_counter() - start >= timeout:
                    return 'TIMEOUT'
            if not self.propagate():
                return 'UNSAT'
            if self._is_sat():
                print(self.get_assignment())
                return 'SAT'
            self._decide()

if __name__ == "__main__":
    formula = set([
        frozenset([-2, -3, -4, 5]),
        frozenset([-1, -5, 6]),
        frozenset([-5, 7]),
        frozenset([-1, -6, -7]),
        frozenset([-1, -2, 5]),
        frozenset([-1, -3, 5]),
        frozenset([-1, -4, 5]),
        frozenset([-1, 2, 3, 4, 5, -6]),
    ])

    variables = list(sorted(set([abs(_) for i in formula for _ in list(i)])))

    solver = CDCLSolver(formula=formula, variables=variables)
    print(solver.solve())
    print(solver.get_assignment())
    pprint(solver._assignment)


from sage.structure.sequence import Sequence
from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing

class AlgebraicModel:

    def __init__(self, cipher):
        self._cipher = cipher
        self.input_postfix = "x"
        self.output_postfix = "y"
        self._ring = None

    def connection_polynomials(self):
        """
        Return a list of polynomials that connects system of equations from each component.

        INPUT:

        - None

        EXAMPLES::

            sage: from claasp.ciphers.block_ciphers.fancy_block_cipher import FancyBlockCipher
            sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
            sage: fancy = FancyBlockCipher(number_of_rounds=1)
            sage: connection = AlgebraicModel(fancy).connection_polynomials()
            sage: connection[:24]
            [plaintext_y0 + sbox_0_0_x0,
             plaintext_y1 + sbox_0_0_x1,
             plaintext_y2 + sbox_0_0_x2,
             ...
             plaintext_y21 + sbox_0_5_x1,
             plaintext_y22 + sbox_0_5_x2,
             plaintext_y23 + sbox_0_5_x3]
        """
        return sum([self.connection_polynomials_at_round(r) for r in range(self._cipher.number_of_rounds)], [])

    def connection_polynomials_at_round(self, r):
        """
        Return a list of connection polynomials at round `r`.

        INPUT:

        - ``r`` -- **integer**

        EXAMPLES::

            sage: from claasp.ciphers.block_ciphers.fancy_block_cipher import FancyBlockCipher
            sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
            sage: fancy = FancyBlockCipher(number_of_rounds=1)
            sage: connection = AlgebraicModel(fancy).connection_polynomials_at_round(0)
            sage: connection[:24]
            [plaintext_y0 + sbox_0_0_x0,
             plaintext_y1 + sbox_0_0_x1,
             plaintext_y2 + sbox_0_0_x2,
             ...
             plaintext_y21 + sbox_0_5_x1,
             plaintext_y22 + sbox_0_5_x2,
             plaintext_y23 + sbox_0_5_x3]
        """
        polynomials = []
        R = self.ring()

        for component in self._cipher.get_components_in_round(r):

            if component.type == "constant":
                continue

            input_vars = [component.id + "_" + self.input_postfix + str(i) for i in range(component.input_bit_size)]
            input_vars = list(map(R, input_vars))

            input_links = component.input_id_links
            input_positions = component.input_bit_positions

            prev_input_vars = []
            for k in range(len(input_links)):
                prev_input_vars += [input_links[k] + "_" + self.output_postfix + str(i) for i in
                                    input_positions[k]]
            prev_input_vars = list(map(R, prev_input_vars))

            polynomials += [x + y for (x, y) in zip(input_vars, prev_input_vars)]

        return polynomials

    def is_algebraically_secure(self, timeout):
        """
        Return `True` if the cipher is resistant against algebraic attack.

        INPUT:

        - ``timeout`` -- **integer**; the timeout for the Grobner basis computation in seconds

        EXAMPLES::

            sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
            sage: from claasp.ciphers.block_ciphers.identity_block_cipher import IdentityBlockCipher
            sage: identity = IdentityBlockCipher()
            sage: algebraic = AlgebraicModel(identity)
            sage: algebraic.is_algebraically_secure(120)
            False
        """
        from cysignals.alarm import alarm, cancel_alarm

        try:
            alarm(timeout)
            self.polynomial_system().groebner_basis()
            cancel_alarm()
            result = False
        except InterruptedError:
            result = True

        return result

    def nvars(self):
        """
        Return the number of variables.

        INPUT:

        - None

        EXAMPLES::

            sage: from claasp.ciphers.block_ciphers.fancy_block_cipher import FancyBlockCipher
            sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
            sage: fancy = FancyBlockCipher(number_of_rounds=1)
            sage: AlgebraicModel(fancy).nvars()
            96
        """
        nvars = 0
        for cipher_round in self._cipher.rounds_as_list:
            for component in cipher_round.components:
                if component.type == "sbox" or component.type == "linear_layer":
                    nvars += component.input_bit_size + component.output_bit_size

        return nvars

    def polynomial_system(self):
        """
        Return a polynomial system for the cipher.

        INPUT:

        - None

        EXAMPLES::

            sage: from claasp.ciphers.block_ciphers.fancy_block_cipher import FancyBlockCipher
            sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
            sage: fancy = FancyBlockCipher(number_of_rounds=1)
            sage: AlgebraicModel(fancy).polynomial_system()  # long time
            Polynomial Sequence with 468 Polynomials in 384 Variables
        """
        polynomials = sum([self.polynomial_system_at_round(r) for r in range(self._cipher.number_of_rounds)], [])
        polynomials += self.connection_polynomials()

        return Sequence(polynomials)

    def polynomial_system_at_round(self, r):
        """
        Return a polynomial system at round `r`.

        INPUT:

        - ``r`` -- **integer**; round index

        EXAMPLES::

            sage: from claasp.ciphers.block_ciphers.fancy_block_cipher import FancyBlockCipher
            sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
            sage: fancy = FancyBlockCipher(number_of_rounds=1)
            sage: AlgebraicModel(fancy).polynomial_system_at_round(0) # long time
            Polynomial Sequence with 252 Polynomials in 288 Variables
        """
        if not 0 <= r < self._cipher.number_of_rounds:
            raise ValueError(f"r must be in the range 0 <= r < {self._cipher.number_of_rounds}")

        polynomials = []

        for component in self._cipher.get_components_in_round(r):
            component_type = component.type
            operation = component.description[0]
            component_types = ["sbox", "linear_layer", "mix_column", "constant"]
            operations = ["XOR", "AND", "OR", "SHIFT", "ROTATE", "NOT"]

            if component_type in component_types or (component_type == "word_operation" and operation in operations):
                polynomials += component.algebraic_polynomials(self)

        return Sequence(polynomials)

    def ring(self):
        """
        Return the polynomial ring for the system of equations.

        INPUT:

        - None

        EXAMPLES::

            sage: from claasp.ciphers.block_ciphers.fancy_block_cipher import FancyBlockCipher
            sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
            sage: from claasp.cipher_modules.models.algebraic.boolean_polynomial_ring import is_boolean_polynomial_ring
            sage: fancy = FancyBlockCipher(number_of_rounds=1)
            sage: ring = AlgebraicModel(fancy).ring()
            sage: is_boolean_polynomial_ring(ring)
            True

            sage: ring.ngens()
            432
        """
        if self._ring is not None:
            return self._ring

        names = self.var_names()
        self._ring = BooleanPolynomialRing(len(names), names, order="degneglex")

        return self._ring

    def var_names(self):
        """
        Return a list of variable names in the polynomial ring.

        INPUT:

        - None

        EXAMPLES::

            sage: from claasp.ciphers.block_ciphers.fancy_block_cipher import FancyBlockCipher
            sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
            sage: fancy = FancyBlockCipher(number_of_rounds=1)
            sage: var_names = AlgebraicModel(fancy).var_names()
            sage: var_names[0]
            'sbox_0_0_x0'
        """
        var_names = []

        for component in self._cipher.get_all_components():
            component_id = component.id
            input_size = component.input_bit_size
            output_size = component.output_bit_size

            if component.type != "constant":
                var_names += [component_id + "_" + self.input_postfix + str(i) for i in range(input_size)]
            var_names += [component_id + "_" + self.output_postfix + str(i) for i in range(output_size)]

            if component.type == "word_operation" and component.description[0].lower() == "modadd":
                ninput_words = component.description[1]
                nadditions = ninput_words - 1

                for n in range(nadditions):
                    # carry variables
                    var_names += [component_id + "_" + "c" + str(n) + "_" + str(i) for i in range(output_size)]
                    if n < nadditions - 1:
                        # aux output variables
                        var_names += \
                            [component_id + "_" + "o" + str(n) + "_" + str(i) for i in range(output_size)]

        for i in range(len(self._cipher.inputs)):
            var_names += [self._cipher.inputs[i] + "_" +
                          self.output_postfix + str(j) for j in range(self._cipher.inputs_bit_size[i])]

        return var_names


from typing import Tuple, List
from openapi_server.annotator.load_data import AnnotationSet

PERSON_TYPES = {'PATIENT', 'DOCTOR'}

Tokens = List[str]
Label = int
Labels = List[int]
Span = Tuple[int, int]
Spans = List[Span]

def label_token(token: str, span: Span, annotation_set: AnnotationSet) -> Label:
    """Return majority annotation type for a given span
    """
    start, end = span

    # Count annotated characters
    overlap = 0
    for annotation in annotation_set:
        if annotation['TYPE'] in PERSON_TYPES:
            overlap += max(
                min(end, annotation['end']) - max(start, annotation['start']),
                0
            )

    # Return 1 if most of the characters in the range are in a person
    # annotation, else 0.
    span_length = end - start
    if overlap > (span_length / 2) and any(c.isalpha() for c in token):
        return 1
    else:
        return 0

def label_tokens(tokens: Tokens, spans: Spans,
                 annotation_set: AnnotationSet) -> Labels:
    """Take list of spans and iterable of annotations; use those annotations to
    make list of labels parallel to list of spans
    """
    return [label_token(token, span, annotation_set) for token, span in
            zip(tokens, spans)]


import config
import telebot
import db
from smtplib import SMTP
from threading import Timer
from time import strftime, localtime, time
from os import mkdir
from os.path import isfile, isdir
from email.utils import formataddr
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from requests import get
from shutil import disk_usage
from platform import system
from socket import gethostname, gethostbyname_ex

SUPPORTS = [i['chat_id'] for sub in (config.supports,) for i in sub]
SUPPORTGROUPS = [i['chat_id'] for sub in (config.supportgroups,) for i in sub]

bot = telebot.TeleBot(config.token)

def send_authcode(addr, regcode):
    subj = 'Код регистрации в Службе технической поддержки'
    _from =  formataddr((str(Header('Сервисный бот', 'utf-8')), config.email_address))
    to = addr
    body = 'Добрый день!\n\n\nВы получили это письмо, потому что отправили обращение Telegram-боту ' + \
           'службы технической поддержки.\n\nВам следует сообщить боту код аутентификации: ' + str(regcode)
    send_email(_from, to, subj, body)

def send_email(from_field=None, to_field=None, subject_field=None, msg_body=None):

    server = SMTP(config.mail_server, config.mail_port)
    server.starttls()
    server.login(config.email_login, config.email_password)
    msg = MIMEMultipart()
    msg['From'] = from_field
    msg['To'] = to_field
    msg['Subject'] = subject_field
    body = MIMEText(msg_body, 'plain', 'utf-8')
    msg.attach(body)
    server.sendmail(config.email_address, to_field, msg.as_string())

def print_userinfo(chat_id, with_log=False):

    user = db.get_user_namedtuple(chat_id)
    userinfo = ('Username: ' + user.first_name + ' ' + user.last_name + '\n'
                'Chat_id: ' + user.chat_id + '\n'
                'Email: ' + user.email_address + '\n'
               )
    if(with_log):
        userinfo += 'Message_log:\n' + user.message_log + '\n'
    return userinfo

def get_support_name_by_chat_id(chat_id):

    n = [i['name'] for i in config.supports if i['chat_id'] == chat_id]
    return n[0] if n[0] else None

def get_keyboard(buttons):

    keyboard = telebot.types.InlineKeyboardMarkup()
    for k in buttons:
        callback_button = telebot.types.InlineKeyboardButton(text=k[0], callback_data=k[1])
        keyboard.add(callback_button)
    return keyboard

# Таймер проверки времени с момента ответа специалиста
def timer(func, interval):

    func()
    Timer(interval, timer, (func, interval)).start()

def check_user_noreply_interval():

    communics = db.get_all_users_namedtuple()
    if communics:
        for u in communics:
            if u.last_msg_time_from_user != 0 and u.last_msg_time_from_specialist != 0 and u.current_communic_responsible != 0:
                if u.last_msg_time_from_user < u.last_msg_time_from_specialist and time() - u.last_msg_time_from_specialist > config.timeout_noreply:
                    archive_communic_from_chat_id(u.chat_id, timeout=True)
                    db.set_user(u.chat_id, has_active_communics=0, current_communic_is_appointed=0, current_communic_responsible=0, message_log = '\'' + config.REPLY['communic_closed'] + '\'')
                    bot.send_message(u.current_communic_responsible, 'Коммуникация, закрепленная ранее за Вами, автоматически закрыта по таймауту.')
                    for gr in SUPPORTGROUPS:
                        bot.send_message(gr, 'Коммуникация от пользователя: \n\n' + print_userinfo(u.chat_id, with_log=False) + '\nбыла автоматически закрыта по таймауту.')

def take_open_communic_by_button(support_chat_id, user_chat_id):

    user = db.get_user_namedtuple(user_chat_id)
    specialist_has_communics = (False if db.get_user_chat_id_by_responsible(support_chat_id) == None else True)
    if not specialist_has_communics and user.current_communic_is_appointed == 0 and user.has_active_communics == 1:
        db.append_message_to_history(user_chat_id, '[ServiceBot]: ' + get_support_name_by_chat_id(support_chat_id) + ' перевел на себя коммуникацию')
        db.set_user(user_chat_id, last_msg_time_from_specialist=int(time()))
        reply_to_group = ('{0} взял коммуникацию с пользователем: \n\n' + print_userinfo(user_chat_id, with_log=False))
        reply_to_specialist = ('{0}, Вы перевели на себя коммуникацию с пользователем: \n\n' + print_userinfo(user_chat_id, with_log=True) + '\nСообщения, которые Вы получаете от бота в личном чате, '
                               'перенаправляются Вам в том виде, в каком пользователь направляет их боту.\n\nСообщения, отправляемые Вами боту '
                               'в личном чате, перенаправляются пользователю.\n\nВсе сообщения попадают в историю коммуникации и после закрытия коммуникации архивируются.\n\nВам следует убедиться, что по данной коммуникации '
                               'еще не зарегистрирована заявка в сервисдеске, и зарегистрировать ее самостоятельно.\n\nДля открытия сервисного меню нажмите кнопку "/" и выберите позицию "/service" во всплывающем меню.\n\n'
                               'Для закрытия коммуникации нажмите кнопку "Закрыть текущую коммуникацию" в сервисном меню.'
                              )
        reply_to_user = ('Ваша коммуникация была переведена на специалиста. Имя специалиста: ' + get_support_name_by_chat_id(support_chat_id) + '.\n'
                         'Сообщения, отправляемые Вами боту, перенаправляются специалисту.')
        for gr in SUPPORTGROUPS:
            bot.send_message(gr, reply_to_group.format(get_support_name_by_chat_id(support_chat_id)))
        db.set_user(user_chat_id, current_communic_is_appointed=1)
        send_history(support_chat_id, reply_to_specialist.format(get_support_name_by_chat_id(support_chat_id)))
        db.set_user(user_chat_id, current_communic_responsible=support_chat_id)
        bot.send_message(user_chat_id, reply_to_user)
    elif not specialist_has_communics and user.current_communic_is_appointed == 0 and user.has_active_communics == 0:
        reply_to_specialist_1 = ('{0}, Вы хотели перевести на себя коммуникацию с пользователем {1}. Эта коммуникация уже закрыта. Пользователь не имеет активных коммуникаций.')
        bot.send_message(support_chat_id, reply_to_specialist_1.format(get_support_name_by_chat_id(support_chat_id), user.first_name + user.last_name))
    elif user.current_communic_is_appointed == 1 and user.has_active_communics == 1 and support_chat_id == user.current_communic_responsible:
        reply_to_specialist_2 = ('{0}, Вы хотели перевести на себя коммуникацию с пользователем {1}. Эта коммуникация уже закреплена за Вами. Вы можете общаться с пользователем через личный чат с ботом.')
        bot.send_message(support_chat_id, reply_to_specialist_2.format(get_support_name_by_chat_id(support_chat_id), user.first_name + user.last_name))
    elif user.current_communic_is_appointed == 1 and user.has_active_communics == 1 and support_chat_id != user.current_communic_responsible:
        reply_to_specialist_3 = ('{0}, Вы хотели перевести на себя коммуникацию с пользователем {1}. Эта коммуникация уже закреплена за другим специалистом.')
        bot.send_message(support_chat_id, reply_to_specialist_3.format(get_support_name_by_chat_id(support_chat_id), user.first_name + user.last_name))
    elif specialist_has_communics:
        reply_to_specialist_4 = ('{0}, Вы хотели перевести на себя коммуникацию с пользователем {1}. У Вас есть текущая коммуникация. Для перевода на Вас новой коммуникации следует сначала закрыть текущую.')
        bot.send_message(support_chat_id, reply_to_specialist_4.format(get_support_name_by_chat_id(support_chat_id), user.first_name + user.last_name))
    else:
        bot.send_message(support_chat_id, config.REPLY['incorrect_request'])

def close_current_communic_by_button(id_, support_chat_id, prefix):

    user_chat_id = db.get_user_chat_id_by_responsible(support_chat_id)
    u = db.get_user_namedtuple(user_chat_id)
    if user_chat_id != None:
        archive_communic_from_chat_id(user_chat_id)
        db.set_user(user_chat_id, current_communic_is_appointed=0, current_communic_responsible=0, has_active_communics=0, message_log='\'' + config.REPLY['communic_closed'] + '\'')
        reply_to_group = (('Специалист {0} закрыл коммуникацию с пользователем: \n\n' + print_userinfo(user_chat_id, with_log=False)).format(get_support_name_by_chat_id(support_chat_id)))
        reply_to_specialist = ('[ServiceBot] Вы закрыли коммуникацию с пользователем: \n\n' + print_userinfo(user_chat_id, with_log=False))
        bot.send_message(support_chat_id, prefix + reply_to_specialist)
        for gr in SUPPORTGROUPS:
            bot.send_message(gr, reply_to_group)
    elif user_chat_id == None:
        bot.answer_callback_query(id_, prefix + config.REPLY['no_active_communics'], show_alert=True)

def archive_communic_from_chat_id(chat_id, timeout=False):

    if chat_id != None:
        u = db.get_user_namedtuple(chat_id)
        if timeout:
            db.append_message_to_history(chat_id, '[ServiceBot]: Коммуникация была автоматически закрыта по таймауту')
        else:
            db.append_message_to_history(chat_id, '[ServiceBot]: ' + get_support_name_by_chat_id(u.current_communic_responsible) + ' закрыл коммуникацию')
        dir_log = config.archive + str(chat_id)
        file_log = config.archive + str(chat_id) + '/' + str(chat_id) + r'.txt'
        if(isdir(dir_log) == False):
            mkdir(dir_log)
        if(isfile(file_log) == False):
            f = open(file_log, 'w+')
            f.write(50*'#' + '\n\n' + 'Архив сообщений по пользователю' + '\n\n' + print_userinfo(chat_id) + '\n' + 50*'#' + '\n\n')
            f.close()
        f = open(file_log, 'a')
        f.write(60*'_' + '\n\n' + 'Запись от ' + strftime('%d.%m.%Y %H:%M:%S', localtime()) + ' (локальное время сервера)' + '\n' + 60*'_')

        # workaround for emoji logging
        res = ''
        for s in db.get_message_log_by_id(u.id):
            if (ord(s) > 0xfff):
                k = '[U+{:X}]'.format(ord(s))
                res += k
            else:
                res += s
        f.write('\n\n' + str(res) + '\n' + 60*'_' + '\n\n')
        f.close()

def get_prefix_for_servicebutton_reply(string):

    q = [k[0] for k in config.SUPPORTS_KEYBOARD or config.CONTROLLERS_KEYBOARD if k[1] == string]
    return 'Q: ' + q[0] + '\n\n' if q[0] else None

def process_content(message):

    dir_log = config.archive + str(message.chat.id)
    if(isdir(dir_log) == False):
            mkdir(dir_log)
    if message.photo:
        content = get_file_photo_id(message)
        filename_suff = content[-10:] + '.jpg'
        a = 'фото'
        b = '. Подпись к фото: ' + message.caption if message.caption else ''
    elif message.document:
        content = message.document.file_id
        filename_suff = message.document.file_name
        a = 'файл ' + message.document.file_name
        b = '. Подпись к файлу: ' + message.caption if message.caption else ''
    if message.chat.id in SUPPORTS:
        h = db.get_user_chat_id_by_responsible(message.chat.id)
        c = 'Специалист'
    else:
        h = message.chat.id
        c = 'Пользователь'
    filename = dir_log + '/' + strftime('%Y%m%d_%H%M%S', localtime()) + '__' + filename_suff
    db.append_message_to_history(h, config.REPLY['sent_content'].format(c, a, b, filename))
    download_content(content, filename)

def download_content(cont, filename):

    if system() == 'Linux':
        du = disk_usage('/')
    elif system() == 'Windows':
        du = disk_usage('C:')
    free_space_rate = du.free / du.total * 100
    if free_space_rate <= 10:
        for gr in SUPPORTGROUPS:
            bot.send_message(gr, '[WARNING] Free disk space on bot-server ' + gethostname() + ' is less than 10%\n\nBot-server info (hostname, aliaslist, ipaddrlist):\n\n' + \
                                  str(gethostbyname_ex(gethostname())) + '\n\nThis message was generated at file saving procedure.')
        send_warning('support@depit.ru')
    file_info = bot.get_file(cont)
    file = get('https://api.telegram.org/file/bot{0}/{1}'.format(config.token, file_info.file_path))
    new_file = open(filename, 'wb')
    new_file.write(file.content)
    new_file.close()

def send_warning(addr):

    subj = '[WARNING] Free disk space on bot-server ' + gethostname() + ' is less than 10%'
    _from =  formataddr((str(Header('Сервисный бот', 'utf-8')), config.email_address))
    to = addr
    body = '[WARNING] Free disk space on bot-server ' + gethostname() + ' is less than 10%\n\nBot-server info (hostname, aliaslist, ipaddrlist):\n\n' + \
            str(gethostbyname_ex(gethostname())) + '\n\nThis message was generated at file saving procedure.'
    send_email(_from, to, subj, body)

def get_file_photo_id(message):

    if message.photo:
        it = [i.file_size for i in message.photo]
        return message.photo[it.index(max(it))].file_id

# workaround for Telegram maximum message size
def break_history(h):
    s = 4096
    if len(h) > s:
        hist_list = []
        n = len(h) // s
        for i in range(1, n+1):
            hist_list.append(h[s*(i-1):s*i])
        hist_list.append(h[s*n:])
        print('hist_list', hist_list)
        return hist_list
    else:
        print('h', h)
        return h

def send_history(chat_id, h, **kwargs):

    if len(h) > 4096:
        k = 1
        while len(h) > k*4096:
            z = h[4096*(k-1):4096*k]
            bot.send_message(chat_id, z)
            k += 1
        if 'reply_markup' in kwargs:
            bot.send_message(chat_id, h[4096*(k-1):], reply_markup=kwargs['reply_markup'])
        else:
            bot.send_message(chat_id, h[4096*(k-1):])
    else:
        if 'reply_markup' in kwargs:
            bot.send_message(chat_id, h, reply_markup=kwargs['reply_markup'])
        else:
            bot.send_message(chat_id, h)


import cv2
import time
import math
import os

import numpy as np
import pandas as pd
import holisticModule as hm

class Preprocessor:
    def __init__(self):
        self.matrix = np.zeros(42)

    def add_columns(self, feat_vector):
        feat_vector = np.array(feat_vector)
        self.matrix = np.column_stack((self.matrix, feat_vector))

    def cvt2csv(self, file_path, file):
        print("PRUEBA 2")
        file = os.path.basename(file)[0:-4]
        file_name = file_path+file+'.csv'
        print(file_name)
        df = pd.DataFrame(self.matrix)
        if self.matrix.shape[1] > 1:
            df = df.iloc[:, 1:]  # Drops first column
        print("PRUEBA")
        print(file_name)
        df.to_csv(file_name, index=False)

    def convert2csv(self, file_path, file):
        file = os.path.basename(file)[0:-4]
        file_name = file_path+"/"+file+'.csv'
        df = pd.DataFrame(self.matrix)
        if self.matrix.shape[1] > 1:
            df = df.iloc[:, 1:]  # Drops first column
        df.to_csv(file_name, index=False)

    # p2 is ref point, If you want the the angle between the line defined by these two points and the horizontal axis
    def get_angleX(self, p1, p2):
        return int(np.round(np.arctan2((p2[1] - p1[1]), (p2[0] - p1[0])) * 180 / np.pi))

    def get_distance(self, p1, p2):
        coordinate_distance = math.sqrt(((p1[0] - p2[0]) ** 2) + ((p1[1] - p2[1]) ** 2))
        return int(coordinate_distance)

    # Calculate distance matrix from an specific point(in this case NOSE) to the other points of interest
    def get_distMat(self, matrixHolistic, matrixLeft, matrixRight):
        distList = []
        NOSE = matrixHolistic[0]
        for i in matrixHolistic:
            distList.append([self.get_distance(NOSE, i), self.get_angleX(NOSE, i)])  #{} or []
        for i in matrixLeft:
            distList.append([self.get_distance(NOSE, i), self.get_angleX(NOSE, i)])
        for i in matrixRight:
            distList.append([self.get_distance(NOSE, i), self.get_angleX(NOSE, i)])
        # print('Matriz de Dist')
        # print(distList)
        # print('Matriz de Dist - NOSE')
        # print(distList[1:])
        # print(f"El tamaño de DISTANCIA: {len(distList)}")
        return distList[1:]

def main():
    # Check current directory
    cwd = os.getcwd()
    # Check and create data directory
    if not (os.path.exists(f'{cwd}/data')):
        os.mkdir(f'{cwd}/data')
    DATA = cwd+'/data/'
    print(DATA)
    # Iterate through videos
    DATASET_PATH = '/home/d3m1ur60/Desktop/LSBv2/'
    PATH1 = '/home/d3m1ur60/Desktop/LSBv2/Ayuda/ayuda_V1-0002.mp4'
    PATH2 = '/home/d3m1ur60/Desktop/LSBv2/Bolivia/bolivia_V1-0033.mp4'
    cap = cv2.VideoCapture(PATH2)
    pastTime = 0
    detector = hm.HolisticDetector()
    counter = 0
    # TEST
    prep = Preprocessor()
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        # Call Detection
        detector.find_pose(frame)  # Must be called for each detection
        detector.get_lm()
        detector.draw_pose(frame)  # Optional, just for drawing
        mat1, mat2, mat3 = detector.get_matrix()  # Returns holistic,left hand,right hand
        feat_vec = prep.get_distMat(mat1, mat2, mat3)
        prep.add_columns(feat_vec)
        # Get FPS
        counter = counter + 1
        currentTime = time.time()
        fps = int(1 / (currentTime - pastTime))
        pastTime = currentTime
        # Draw INFO
        cv2.putText(frame, f'FPS:{fps}', (50, 50), cv2.FONT_HERSHEY_PLAIN, 2, (255, 0, 0), 2)
        cv2.putText(frame, f'COUNT:{counter}', (350, 50), cv2.FONT_HERSHEY_PLAIN, 2, (255, 0, 0), 2)
        # Display
        cv2.imshow("original", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    print(f'TOTAL: {counter}')
    print('INTENTO ')
    print(prep.matrix)
    print(prep.matrix.shape)
    print(DATA)
    prep.cvt2csv(DATA, PATH1)

if __name__ == '__main__':
    main()


from textwrap import indent
from PySide2.QtCore import QObject, Signal, Slot, Property, QUrl, QAbstractListModel, QByteArray
from PySide2.QtGui import QGuiApplication
from PySide2.QtQuick import QQuickView
from PySide2.QtPositioning import QGeoCoordinate
from PySide2 import QtCore
from enum import Enum
import typing
import sys
import json

VIEW_URL = "superview.qml"
PUVODNI_LIST_FILE = "data_ukol1_znak.json"

#Class for maintaining list of tasks
class FiltrModel(QAbstractListModel):

    #Enum with added custom roles
    class Roles(Enum):
        LOCATION = QtCore.Qt.UserRole+0
        AREA = QtCore.Qt.UserRole+1
        POPULATION = QtCore.Qt.UserRole+2
        TYP = QtCore.Qt.UserRole+3
        KRAJ = QtCore.Qt.UserRole+4
        OKRES = QtCore.Qt.UserRole+5
        ZNAK = QtCore.Qt.UserRole+6

    #Initialize and load list from given file
    def __init__ (self,filename=None):
        QAbstractListModel.__init__(self)
        self._min_po = 0
        self._max_po = 1500000
        self._min_area = 0.0
        self._max_area = 500.0
        self._obce = False
        self._mesta = False
        self.kraj_filtr = ["všechny"]
        self.okres_filtr = ["všechny"]
        self.kraj_all = set()
        self.okres_all = set()
        self._output_file = ""
        self.city_list = []
        self.puvodni_list = []
        if filename:
            self.load_from_json(filename)

    #Property min_po
    def get_min_po(self):
        return self._min_po

    def set_min_po(self,val):
        if val != self.min_po:
            self._min_po = val
            self.min_po_changed.emit()

    min_po_changed = Signal()
    min_po = Property(int, get_min_po, set_min_po, notify=min_po_changed)

    #Property max_po
    def get_max_po(self):
        return self._max_po

    def set_max_po(self,val):
        if val != self.max_po:
            self._max_po = val
            self.max_po_changed.emit()

    max_po_changed = Signal()
    max_po = Property(int, get_max_po, set_max_po, notify=max_po_changed)

    #Property min_area
    def get_min_area(self):
        return self._min_area

    def set_min_area(self,val):
        if val != self.min_area:
            self._min_area = int(val)
            self.min_area_changed.emit()

    min_area_changed = Signal()
    min_area = Property(float, get_min_area, set_min_area, notify=min_area_changed)

    #Property max_area
    def get_max_area(self):
        return self._max_area

    def set_max_area(self,val):
        if val != self.max_area:
            self._max_area = int(val)
            self.max_area_changed.emit()

    max_area_changed = Signal()
    max_area = Property(float, get_max_area, set_max_area, notify=max_area_changed)

    #Property obce
    def get_obce(self):
        return self._obce

    def set_obce(self,val):
        if val != self.obce:
            self._obce = val
            self.obce_changed.emit()

    obce_changed = Signal()
    obce = Property(bool, get_obce, set_obce, notify=obce_changed)

    #Property mesta
    def get_mesta(self):
        return self._mesta

    def set_mesta(self,val):
        if val != self.mesta:
            self._mesta = val
            self.mesta_changed.emit()

    mesta_changed = Signal()
    mesta = Property(bool, get_mesta, set_mesta, notify=mesta_changed)

    #Property output_file
    def get_output_file(self):
        return self._output_file

    def set_output_file(self,val):
        if val != self.output_file:
            self._output_file = val
            self.output_file_changed.emit()

    output_file_changed = Signal()
    output_file = Property(str, get_output_file, set_output_file, notify=output_file_changed)

    #Load list of cities from given file
    def load_from_json(self,filename):
        with open(filename,encoding="utf-8") as f:
            self.puvodni_list = json.load(f)

            for c in self.puvodni_list:
                #Create QGeoCoordinate from the original JSON location
                pos = c['location']
                lon,lat = pos.split("(")[1].split(")")[0].split(" ")
                c['location'] = QGeoCoordinate(float(lat),float(lon))

                #Add value of 'krajLabel' and 'okresLabel' to set property
                self.kraj_all.add(c['krajLabel'])
                self.okres_all.add(c['okresLabel'])

                #Check if feature contains attribute 'mestoLabel' and set value to 'obec' if not
                if "mestoLabel" not in c:
                    c["mestoLabel"] = "obec"

                #Check if feature contains URL of its symbol, add URL of white rectangle if not
                if "znak" not in c:
                    c["znak"] = "https://www.meme-arsenal.com/memes/422425412debbe780318e9bfee9efdac.jpg" #bílý obdélník

    #Return number of cities in the list
    def rowCount(self, parent:QtCore.QModelIndex=...) -> int:
        """ Return number of cities in the list"""
        return len(self.city_list)

    #For given index and role return information of the city
    def data(self, index:QtCore.QModelIndex, role:int=...) -> typing.Any:
        if role == QtCore.Qt.DisplayRole: # On DisplayRole return name
            return self.city_list[index.row()]["obecLabel"]
        elif role == self.Roles.LOCATION.value: # On location role return coordinates
            return self.city_list[index.row()]["location"]
        elif role == self.Roles.AREA.value: # On area role return area
            return self.city_list[index.row()]["area"]
        elif role == self.Roles.POPULATION.value: # On population role return population
            return self.city_list[index.row()]["population"]
        elif role == self.Roles.TYP.value: # On typ role return city/municipality
            return self.city_list[index.row()]["mestoLabel"]
        elif role == self.Roles.KRAJ.value: # On kraj role return name of the region
            return self.city_list[index.row()]["krajLabel"]
        elif role == self.Roles.OKRES.value: # On okres role return name of the district
            return self.city_list[index.row()]["okresLabel"]
        elif role == self.Roles.ZNAK.value: # On znak role return URL of city's symbol
            return self.city_list[index.row()]["znak"]

    #Returns dict with role numbers and role names for default and custom roles together
    def roleNames(self) -> typing.Dict[int, QByteArray]:
        roles = super().roleNames()
        roles[self.Roles.LOCATION.value] = QByteArray(b'location')
        roles[self.Roles.AREA.value] = QByteArray(b'area')
        roles[self.Roles.POPULATION.value] = QByteArray(b'population')
        roles[self.Roles.TYP.value] = QByteArray(b'typ')
        roles[self.Roles.KRAJ.value] = QByteArray(b'kraj')
        roles[self.Roles.OKRES.value] = QByteArray(b'okres')
        roles[self.Roles.ZNAK.value] = QByteArray(b'znak')
        return roles

    #Sets the value of property kraj_filtr
    @Slot(str)
    def set_kraj(self, val: str):
        self.kraj_filtr = []
        self.kraj_filtr.append(val)
        print(self.kraj_filtr)

    #Sets the value of property okres_filtr
    @Slot(str)
    def set_okres(self, val: str):
        self.okres_filtr = []
        self.okres_filtr.append(val)
        print(self.okres_filtr)

    #Filters the original list of cities
    @Slot()
    def filtrovat(self):
        #Delete all rows from city_list
        self.beginRemoveRows(self.index(0).parent(), 0 , len(self.city_list)-1)
        self.city_list = []
        self.endRemoveRows()

        #Set values of kraj_filtr and okres_filtr if all menu items are chosen
        if "všechny" in self.kraj_filtr:
            self.kraj_filtr = self.kraj_all

        if "všechny" in self.okres_filtr:
            self.okres_filtr = self.okres_all

        #Filter the original list and add items to new one
        input_idx = 0
        for feature in self.puvodni_list:
            pocet_obyv = int(feature["population"])
            rozloha = float(feature["area"])

            #Municipalities
            if self.obce == True:
                if feature["mestoLabel"] == "obec"\
                    and pocet_obyv > self.min_po and pocet_obyv < self.max_po\
                    and rozloha > self.min_area and rozloha < self.max_area\
                    and feature["krajLabel"] in self.kraj_filtr\
                    and feature["okresLabel"] in self.okres_filtr:

                    self.beginInsertRows(self.index(0).parent(),input_idx,input_idx)
                    self.city_list.append(feature)
                    self.endInsertRows()
                    input_idx += 1

            #Towns
            if self.mesta == True:
                if feature["mestoLabel"] == "město v Česku"\
                    and pocet_obyv > self.min_po and pocet_obyv < self.max_po\
                    and rozloha > self.min_area and rozloha < self.max_area\
                    and feature["krajLabel"] in self.kraj_filtr\
                    and feature["okresLabel"] in self.okres_filtr:

                    self.beginInsertRows(self.index(0).parent(),input_idx,input_idx)
                    self.city_list.append(feature)
                    self.endInsertRows()
                    input_idx += 1

        print(f"Načteno {input_idx} obcí.")

    #Save filtered list of cities to a file
    @Slot()
    def save_to_file(self):
        with open(self.output_file, 'w', encoding ='utf8') as json_file:
            for feature in self.city_list:
                feature["location"] = QGeoCoordinate.toString(feature["location"])
            json.dump(self.city_list, json_file, ensure_ascii = False, indent=4)

app = QGuiApplication(sys.argv)
view = QQuickView()
url = QUrl(VIEW_URL)
puvodnilist_model = FiltrModel(PUVODNI_LIST_FILE)
ctxt = view.rootContext()
ctxt.setContextProperty('filtrModel',puvodnilist_model)
view.setSource(url)
view.show()
app.exec_()


import os

from PySide2.QtCore import QObject, Slot
from PySide2.QtWidgets import QFileDialog

from ..model.main import MainModel

class MainController(QObject):
    def __init__(self, model: MainModel):
        super().__init__()

        self._model = model

    def open_input_shp(self) -> None:
        file_name = QFileDialog.getOpenFileName(
            self, "select input stream", os.path.expanduser("~")
        )
        if file_name:
            if os.path.exists(str(file_name)):
                self._model.stream_file = str(file_name)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: benoit.dufumier

"""
import sys; sys.path.append('../../')
import os, argparse
import numpy as np
import pandas as pd
import brainomics.image_preprocessing as preproc
import matplotlib
matplotlib.use('Agg')
import glob

def OUTPUT(dataset, output_path, modality='t1mri', mri_preproc='quasi_raw', type=None, ext=None):
    # type data64, or data32
    return os.path.join(output_path, dataset + "_" + modality+ "_" + mri_preproc +
                 ("" if type is None else "_" + type) + "." + ext)

def nii2npy(nii_path, phenotype_path, dataset_name, output_path, qc=None, sep='\t', id_type=str,
            check = dict(shape=(121, 145, 121), zooms=(1.5, 1.5, 1.5)), merge_ni_path=True):
    ########################################################################################################################

    phenotype = pd.read_csv(phenotype_path, sep=sep)
    qc = pd.read_csv(qc, sep=sep) if qc is not None else None

    if 'TIV' in phenotype:
        phenotype.rename(columns={'TIV': 'tiv'}, inplace=True)

    keys_required = ['participant_id', 'age', 'sex', 'tiv', 'diagnosis']

    assert set(keys_required) <= set(phenotype.columns), \
        "Missing keys in {} that are required to compute the npy array: {}".format(phenotype_path,
                                                                                set(keys_required)-set(phenotype.columns))

    ## TODO: change this condition according to session and run in phenotype.csv
    #assert len(set(phenotype.participant_id)) == len(phenotype), "Unexpected number of participant_id"

    null_or_nan_mask = [False for _ in range(len(phenotype))]
    for key in keys_required:
        null_or_nan_mask |= getattr(phenotype, key).isnull() | getattr(phenotype, key).isna()
    if null_or_nan_mask.sum() > 0:
        print('Warning: {} participant_id will not be considered because of missing required values:\n{}'. \
              format(null_or_nan_mask.sum(), list(phenotype[null_or_nan_mask].participant_id.values)))

    participants_df = phenotype[~null_or_nan_mask]

    ########################################################################################################################
    #  Neuroimaging niftii and TIV
    #  mwp1 files
      #  excpected image dimensions
    NI_filenames = glob.glob(nii_path)
    ########################################################################################################################
    #  Load images, intersect with pop and do preprocessing and dump 5d npy
    print("###########################################################################################################")
    print("#", dataset_name)

    print("# 1) Read images")
    scaling, harmo = 'raw', 'raw'
    print("## Load images")
    NI_arr, NI_participants_df, ref_img = preproc.load_images(NI_filenames,check=check)
    print('--> {} img loaded'.format(len(NI_participants_df)))
    print("## Merge nii's participant_id with participants.csv")
    NI_arr, NI_participants_df = preproc.merge_ni_df(NI_arr, NI_participants_df, participants_df,
                                                         qc=qc, id_type=id_type)
    print('--> Remaining samples: {} / {}'.format(len(NI_participants_df), len(participants_df)))

    print("## Save the new participants.csv")
    NI_participants_df.to_csv(OUTPUT(dataset_name, output_path, type="participants", ext="csv"),
                              index=False)
    print("## Save the raw npy file (with shape {})".format(NI_arr.shape))
    np.save(OUTPUT(dataset_name, output_path, type="data64", ext="npy"), NI_arr)

    ######################################################################################################################
    # Deallocate the memory
    del NI_arr

if __name__=="__main__":

    parser = argparse.ArgumentParser()

    parser.add_argument('--output_path', type=str, required=True)
    parser.add_argument('--nii_regex_path', type=str, required=True)
    parser.add_argument('--phenotype_path', type=str, required=True)
    parser.add_argument('--dataset', type=str, required=True)
    parser.add_argument('--qc_path', type=str, required=False)
    parser.add_argument('--id_type', type=str, choices=['str', 'int'], default='str',
                        help='Type of <participant_id> and <session> used for casting')
    parser.add_argument('--sep', type=str, choices=[',', '\t'], default='\t', help='Separator used in participants.csv')

    args = parser.parse_args()

    # # General case
    nii2npy(args.nii_regex_path,
            args.phenotype_path,
            args.dataset,
            args.output_path,
            qc=args.qc_path,
            sep=args.sep,
            id_type=eval(args.id_type),
            check=dict(shape=(182, 218, 182),
                       zooms=(1, 1, 1)))

    # !/bin/bash

    # MAIN = ~ / PycharmProjects / neurospin / scripts / 2019
    # _psy_datasets / 201906
    # _schizconnect - vip - prague - bsnip - biodb - icaar - start_assemble - all / generic_quasi_raw_preproc.py
    # MAIN_RESAMPLING = ~ / PycharmProjects / neurospin / scripts / 2019
    # _psy_datasets / 201906
    # _schizconnect - vip - prague - bsnip - biodb - icaar - start_assemble - all / quasi_raw_resample.py
    # OUTPUT_PATH = / neurospin / psy_sbox / analyses / 201906
    # _schizconnect - vip - prague - bsnip - biodb - icaar - start_assemble - all / data / quasi_raw /

    ## .nii to .npy for id-type == int and id-type == str (important to make the distinction, depends on the participant_id
    ## values)

    # for DATASET in  biobd hcp nar rbp  mpi-leipzig cnp abide1 abide2 ixi
    # do
    # PHENOTYPE=/neurospin/psy_sbox/$DATASET/${DATASET^^}_t1mri_mwp1_participants.csv
    # QC=/neurospin/psy_sbox/$DATASET/derivatives/cat12-12.6_vbm_qc/qc.tsv
    # python3 $MAIN --nii_regex_path '/neurospin/psy_sbox/'$DATASET'/derivatives/quasi-raw/sub-*/ses-*/anat/*preproc-linear*.nii.gz' --phenotype_path $PHENOTYPE --output_path $OUTPUT_PATH --qc_path $QC --dataset $DATASET --id_type int &> $DATASET.txt &
    # done

    # for DATASET in oasis3  #icbm localizer candi
    # do
    # PHENOTYPE=/neurospin/psy_sbox/$DATASET/${DATASET^^}_t1mri_mwp1_participants.csv
    # QC=/neurospin/psy_sbox/$DATASET/derivatives/cat12-12.6_vbm_qc/qc.tsv
    # python3 $MAIN --nii_regex_path '/neurospin/psy_sbox/'$DATASET'/derivatives/quasi-raw/sub-*/ses-*/anat/*preproc-linear*.nii.gz' --phenotype_path $PHENOTYPE --output_path $OUTPUT_PATH --qc_path $QC --dataset $DATASET --id_type str &> $DATASET.txt &
    # done

    ## Particular cases

    # DATASET=gsp
    # PHENOTYPE=/neurospin/psy_sbox/${DATASET^^}/${DATASET^^}_t1mri_mwp1_participants.csv
    # QC=/neurospin/psy_sbox/${DATASET^^}/derivatives/cat12-12.6_vbm_qc/qc.tsv
    # python3 $MAIN --nii_regex_path '/neurospin/psy_sbox/'${DATASET^^}'/derivatives/quasi-raw/sub-*/ses-*/anat/*preproc-linear*.nii.gz' --phenotype_path $PHENOTYPE --output_path $OUTPUT_PATH --qc_path $QC --dataset $DATASET --id_type int &> $DATASET.txt &
    #
    # DATASET=corr
    # PHENOTYPE=/neurospin/psy_sbox/CoRR/CoRR_t1mri_mwp1_participants.csv
    # QC=/neurospin/psy_sbox/CoRR/derivatives/cat12-12.6_vbm_qc/qc.tsv
    # python3 $MAIN --nii_regex_path '/neurospin/psy_sbox/CoRR/derivatives/quasi-raw/sub-*/ses-*/anat/*preproc-linear*.nii.gz' --phenotype_path $PHENOTYPE --output_path $OUTPUT_PATH --qc_path $QC --dataset $DATASET --id_type int &> $DATASET.txt &

    # DATASET=bsnip
    # PHENOTYPE=/neurospin/psy_sbox/bsnip1/${DATASET^^}_t1mri_mwp1_participants.csv
    # QC=/neurospin/psy_sbox/bsnip1/derivatives/cat12-12.6_vbm_qc/qc.tsv
    # python3 $MAIN --nii_regex_path '/neurospin/psy_sbox/bsnip1/derivatives/quasi-raw/sub-*/ses-*/anat/*preproc-linear*.nii.gz' --phenotype_path $PHENOTYPE --output_path $OUTPUT_PATH --qc_path $QC --dataset $DATASET --id_type str &> $DATASET.txt &
    #
    # DATASET=schizconnect-vip
    # PHENOTYPE=/neurospin/psy_sbox/schizconnect-vip-prague/${DATASET^^}_t1mri_mwp1_participants.csv
    # QC=/neurospin/psy_sbox/schizconnect-vip-prague/derivatives/cat12-12.6_vbm_qc/qc.tsv
    # python3 $MAIN --nii_regex_path '/neurospin/psy_sbox/schizconnect-vip-prague/derivatives/quasi-raw/sub-*/ses-*/anat/*preproc-linear*.nii.gz' --phenotype_path $PHENOTYPE --output_path $OUTPUT_PATH --qc_path $QC --dataset $DATASET --id_type str &> $DATASET.txt &


# -*- coding: utf-8 -*-
"""
Created on Mon Oct  8 14:32:52 2018

@author: luolei

"""
from rq import Queue
import time
from redis import Redis
from tmp.jobs import func_low, func_high, func_default

redis_conn = Redis()

q_low = Queue('low', connection = redis_conn)
q_high = Queue('high', connection = redis_conn)
q_default = Queue('default', connection = redis_conn)

# 添加任务，注意添加顺序
max_queued_time = 30  # job停留在队列里的最长时间
result_ttl = 100  # 结果保留的最长时间

job_high = q_high.enqueue(
    f = func_high,
    ttl = max_queued_time,
    args = ('http://www.baidu.com',),  # func里的args参数
    result_ttl = result_ttl
)

job_default = q_default.enqueue(
    f = func_default,
    ttl = max_queued_time,
    args = ('http://www.baidu.com',),  # func里的args参数
    result_ttl = result_ttl
)

job_low = q_low.enqueue(
    f = func_low,
    ttl = max_queued_time,
    args = ('http://www.baidu.com',),  # func里的args参数
    result_ttl = result_ttl
)

print('\nstep = 0')
print(job_low.result, job_default.result, job_high.result)

for step in range(1, 200):
    time.sleep(1)
    print('\nstep = {}'.format(step))
    print(job_high.result, job_low.result, job_default.result)  # 即使没有打印也会有后台运行