#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cv2
import torch
import rospy
import numpy as np

from std_msgs.msg import Header
from sensor_msgs.msg import Image
from yolov5_ros_msgs.msg import BoundingBox, BoundingBoxes
from yolo_new.msg import Flag,Serial_RT
IsMoving = 0
SingleSortOK = 1

class Yolo_Dect:
    def __init__(self):

        # load parameters

        yolov5_path = rospy.get_param('/yolov5_path', '')

        weight_path = rospy.get_param('~weight_path', '')
        image_topic = rospy.get_param(
            '~image_topic', '/camera/color/image_raw')
        pub_topic = rospy.get_param('~pub_topic', '/yolov5/BoundingBoxes')
        self.camera_frame = rospy.get_param('~camera_frame', '')
        conf = rospy.get_param('~conf', '0.5')

        # load local repository(YoloV5:v6.0)
        self.model = torch.hub.load(yolov5_path, 'custom',
                                    path=weight_path, source='local')
        self.model.cpu()
        # which device will be used
        #if (rospy.get_param('/use_cpu', 'false')):
        #    self.model.cpu()
        #else:
        #    self.model.cuda()

        self.model.conf = conf
        self.model.iou = 0.1    #待测试~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        self.color_image = Image()
        self.depth_image = Image()
        self.getImageStatus = False

        self.classes_colors = {}

        # image subscribe
        self.color_sub = rospy.Subscriber(image_topic, Image, self.image_callback,
                                          queue_size=1, buff_size=52428800)
        self.flag_sub = rospy.Subscriber("/Flag_pub", Flag, self.flag_callback)#订阅移动状态话题

        # output publishers
        #queue_size 实时收发信息
        self.position_pub = rospy.Publisher(
            pub_topic, BoundingBoxes, queue_size=1)

        self.image_pub = rospy.Publisher(
            '/yolov5/detection_image', Image, queue_size=1)

        # if no image messages
        while (not self.getImageStatus):
            rospy.loginfo("waiting for image.")
            rospy.sleep(2)

    def flag_callback(self,msg):
        global IsMoving
        global SingleSortOK
        IsMoving = msg.isMoving
        SingleSortOK = msg.singleSortOK

    def image_callback(self, image):
        global IsMoving
        global SingleSortOK

        self.boundingBoxes = BoundingBoxes()
        self.boundingBoxes.header = image.header
        self.boundingBoxes.image_header = image.header
        self.getImageStatus = True
        self.color_image = np.frombuffer(image.data, dtype=np.uint8).reshape(
            image.height, image.width, -1)
        self.color_image = cv2.cvtColor(self.color_image, cv2.COLOR_BGR2RGB)
        self.color_image = self.white_balance_1(self.color_image)

        results = self.model(self.color_image)
        # xmin    ymin    xmax   ymax  confidence  class    name

        boxs = results.pandas().xyxy[0].values
        self.dectshow(self.color_image, boxs, image.height, image.width)

        cv2.waitKey(3)

    def white_balance_1(self,img):
        '''
        第一种简单的求均值白平衡法
        :param img: cv2.imread读取的图片数据
        :return: 返回的白平衡结果图片数据
        '''
        # 读取图像
        r, g, b = cv2.split(img)
        r_avg = cv2.mean(r)[0]
        g_avg = cv2.mean(g)[0]
        b_avg = cv2.mean(b)[0]
        # 求各个通道所占增益
        k = (r_avg + g_avg + b_avg) / 3
        kr = k / r_avg #+ 0.1
        kg = k / g_avg #+ 0.1
        kb = k / b_avg
        r = cv2.addWeighted(src1=r, alpha=kr, src2=0, beta=0, gamma=0)
        g = cv2.addWeighted(src1=g, alpha=kg, src2=0, beta=0, gamma=0)
        b = cv2.addWeighted(src1=b, alpha=kb, src2=0, beta=0, gamma=0)
        balance_img = cv2.merge([b, g, r])
        return balance_img

    def dectshow(self, org_img, boxs, height, width):
        img = org_img.copy()

        count = 0
        for i in boxs:
            count += 1

        for box in boxs:

            # tmp_flag = judge_result(box)    # 判断识别结果是否合格
            # if tmp_flag == 0:
            #     count -= 1
            #     continue

            boundingBox = BoundingBox()
            boundingBox.probability = np.float64(box[4])
            boundingBox.xmin = np.int64(box[0])
            boundingBox.ymin = np.int64(box[1])
            boundingBox.xmax = np.int64(box[2])
            boundingBox.ymax = np.int64(box[3])
            boundingBox.xmid = (np.int64(box[0])+np.int64(box[2]))/2
            boundingBox.ymid = (np.int64(box[1])+np.int64(box[3]))/2
            boundingBox.num = np.int16(count)
            boundingBox.Class = box[-1]
            boundingBox.CNum = self.switch_class(boundingBox.Class)   #传入垃圾类别并进行判断分类
            boundingBox.ONum = self.switch_num(boundingBox.Class)

            if box[-1] in self.classes_colors.keys():
                color = self.classes_colors[box[-1]]
            else:
                color = np.random.randint(0, 183, 3)
                self.classes_colors[box[-1]] = color

            cv2.rectangle(img, (int(box[0]), int(box[1])),
                          (int(box[2]), int(box[3])), (int(color[0]), int(color[1]), int(color[2])), 2)

            if box[1] < 20:
                text_pos_y = box[1] + 30
            else:
                text_pos_y = box[1] - 10

            # cv2.putText(img, box[-1] + label,
            #             (int(box[0]), int(text_pos_y) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2,
            #             cv2.LINE_AA)
            cv2.putText(img, box[-1],
                        (int(box[0]), int(text_pos_y) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2,
                        cv2.LINE_AA)

            self.boundingBoxes.bounding_boxes.append(boundingBox)
            self.position_pub.publish(self.boundingBoxes)
        self.publish_image(img, height, width)
        # cv2.imshow('YOLOv5', img)

    def switch_class(self,bclass):# 根据yolo返回类别进行类别分类 CNum
        if bclass == "recycle_can" or bclass == "recycle_bottle" or bclass == "recycle_paper":
            return 1
        elif bclass == "harm_battery" :
            return 2
        elif bclass == "kitchen_potato" or bclass == "kitchen_ternip" or bclass == "kitchen_carrot" :
            return 3
        elif bclass == "others_chip" or bclass == "others_stone":
            return 4
        else :
            return 999

    def switch_num(self,bclass):    #定义垃圾类别 ONum
        if bclass == 'recycle_can':
            return 1
        elif bclass == 'recycle_bottle':
            return 2
        elif bclass == 'recycle_paper':
            return 3
        elif bclass == 'harm_battery':
            return 4
        elif bclass == 'kitchen_ternip':#白萝卜
            return 5
        elif bclass == 'kitchen_carrot':
            return 6
        elif bclass == 'kitchen_potato':
            return 7
        elif bclass == 'others_chip':#瓷片
            return 8
        elif bclass == 'others_stone':
            return 9
        else :
            return 999

    def judge_result(self,box): #判断检测结果是否合格 默认返回1，不合格返回0
        xmin = np.int64(box[0])
        ymin = np.int64(box[1])
        xmax = np.int64(box[2])
        ymax = np.int64(box[3])
        aera = (xmax-xmin)*(ymax-ymin)

        xmid = (np.int64(box[0])+np.int64(box[2]))/2
        ymid = (np.int64(box[1])+np.int64(box[3]))/2
        Class = box[-1]
        CNum = self.switch_class(Class)
        ONum = self.switch_num(Class)

        if boundingBox.ONum == 4:   #电池
            if aera > 100:  # 示例，待测
                return 0

        return 1

    def publish_image(self, imgdata, height, width):
        image_temp = Image()
        header = Header(stamp=rospy.Time.now())
        header.frame_id = self.camera_frame
        image_temp.height = height
        image_temp.width = width
        image_temp.encoding = 'bgr8'
        image_temp.data = np.array(imgdata).tobytes()
        image_temp.header = header
        image_temp.step = width * 3
        self.image_pub.publish(image_temp)

def main():
    rospy.init_node('yolov5_ros', anonymous=True)
    yolo_dect = Yolo_Dect()
    rospy.spin()

if __name__ == "__main__":
    main()


import cv2
import tensorflow as tf
import numpy as np

import mnist
import mnist_m
import svhn
import synthdigits

class DataInput(object):
    def __init__(self, model_params, mnist_type, phase, is_train):
        self.batch_size = model_params["batch_size"]
        max_data_num = model_params["max_data_num"]

        self.is_train = is_train
        if mnist_type == "MNIST":
            self.data_type = mnist.Mnist(is_train, max_data_num)
        elif mnist_type == "MNIST_M":
            self.data_type = mnist_m.MnistM(is_train, max_data_num)
        elif mnist_type == "SVHN":
            self.data_type = svhn.Svhn(is_train, max_data_num)
        elif mnist_type == "SYNTHDIGITS":
            self.data_type = synthdigits.SynthDigits(is_train, max_data_num)

        self.file_size = self.data_type.file_size

    def get_arg_dict(self, model_params):
        arg_dict = dict()

        arg_dict["feature"] = dict()
        arg_dict["label"] = dict()
        arg_dict["mask"] = dict()

        for key in model_params:
            if "data_arg" in key:
                _, domain, field = key.split(".")
                arg_dict[domain][field] = model_params[key]
        arg_dict_list = list()
        arg_dict_list.append(arg_dict["feature"])
        arg_dict_list.append(arg_dict["label"])
        arg_dict_list.append(arg_dict["mask"])
        return arg_dict_list

    def load_data(self):
        image, label = self.data_type.load_data(self.batch_size)

        return image, label

    def center_crop(self, img):
        i_height, i_width, i_cha = img.get_shape().as_list()
        ccrop_size = [30, 30]
        offset_height = int((i_height - ccrop_size[0]) / 2)
        offset_width = int((i_width - ccrop_size[1]) / 2)
        img = tf.image.crop_to_bounding_box(img,
                                            offset_height, offset_width, ccrop_size[0], ccrop_size[1])
        return img

    def add_data_arg(self, imgs):
        if self.is_train:
            imgs = tf.map_fn(
                lambda img: tf.image.random_brightness(img, 0.2),
                imgs)

            imgs = tf.map_fn(lambda img:
                             tf.image.random_contrast(img, 0.5, 1.5),
                             imgs)

            imgs = tf.map_fn(lambda img:
                             tf.random_crop(img, [30, 30, 3]),
                             imgs)
        else:
            imgs = tf.map_fn(lambda img:
                             self.center_crop(img),
                             imgs)
        return imgs

    def get_input(self):
        pass

    def get_label(self):
        pass

if __name__ == "__main__":
    """ example of running the code"""
    model_params = {"batch_size": 10}
    data_input = DataInput(model_params, "SYNTHDIGITS", None, True)

    for i in range(10):
        image, label = data_input.load_data()
        for i in range(10):
            print(label[i])
            cv2.imshow("img", image[i])
            cv2.waitKey(0)


from interfaces.node import Node
from encryptions.ECB import ECB
from encryptions.OFB import OFB
import threading

keys = {
    "K1":"1111111111111111",
    "K2":"2222222222222222",
    "K3":"3333333333333333",
}
key_wanted = None

km = Node("KM")
receive_number = 0

def set_key_wanted(data):
    global key_wanted
    if receive_number == 1:
        key_wanted = data.decode("utf-8")

def receive_counter(data):
    global receive_number
    receive_number+=1
    print(f'[RECEIVE->{receive_number}]{data}')

def send_encrypted_key():
    global receive_number,key_wanted
    if receive_number == 2:
        if key_wanted == "K1":
            crypto = ECB(keys["K3"])
            encrypt = crypto.encrypt(keys[key_wanted])
            km.socket.sendall(encrypt[0])
            print("Sending K1 encrypted with K3 using ECB ->" + str(encrypt[0]))
        else:
            crypto = OFB(keys["K3"],b'0'*16)
            encrypt = crypto.encrypt(keys[key_wanted])
            km.socket.sendall(encrypt[0])
            print("Sending K2 encrypted with K3 using OFB ->" + str(encrypt[0]))

def receive():
    while km.signal:
        try:
            data = km.socket.recv(1024)
            receive_counter(data)
            set_key_wanted(data)
            send_encrypted_key()
        except Exception as e:
            print("You have been disconnected from the server " + str(e))
            km.signal = False

receive_thread = threading.Thread(target=receive)
receive_thread.start()


#!/usr/bin/env python
# coding: utf-8

# - Edge weight is inferred by GNNExplainer and node importance is given by five Ebay annotators. Not every annotator has annotated each node.
# - Seed is the txn to explain.
# - id is the community id.

import math
from tqdm.auto import tqdm
import random
import pandas as pd
import numpy as np
import networkx as nx
import itertools
from collections import Counter
import scipy.stats
import sklearn
from sklearn.metrics import accuracy_score
from sklearn.metrics import roc_auc_score
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
from optparse import OptionParser

parser = OptionParser()
parser.add_option('--random-draw', action = 'store', dest = 'random_draw', type = int, default = 100, help = 'Random draws to break the tie in ranking topk edges.')
parser.add_option('--edge-agg', action = 'store', dest = 'edge_agg', default = 'avg', choices = ['avg', 'min', 'sum'], help = 'Aggregation method to compute edge importance score based on the node importance scores.')
# parser.add_option('--explainer-w', action = 'store', dest = 'explainer_w', default = '0', type = float, help = 'Learned parameter for explainer weights.')
parser.add_option('-c', '--centrality-w', action = 'store', dest = 'centrality_w', default = '0', type = float, help = 'Learned parameter for centrality measures.')

(options, args) = parser.parse_args()
print ("Options:", options)

explainer_w = 1-options.centrality_w
learner = 'grid-{}'.format(options.centrality_w)

# Load in the annotation file, the data seed, the edge weights by explainer, the edges in the communities.
DataNodeImp = pd.read_csv('../05GNNExplainer-eval-hitrate/input/annotation_publish.csv')
DataSeed = pd.read_csv('../05GNNExplainer-eval-hitrate/input/data-seed.txt')
DataEdgeWeight = pd.read_csv('../05GNNExplainer-eval-hitrate/input/data-edge-weight.txt')
df_e = pd.read_csv('../05GNNExplainer-eval-hitrate/input/masked_df_e.csv')

x_y_df = pd.read_csv('x_y_df_learn.csv')

del x_y_df['max_hitrate']

x_y_df['combined_weights'] = explainer_w * x_y_df['explainer'] + options.centrality_w * x_y_df['edge_btw']

print('AUC score of the sample:', roc_auc_score(DataSeed.y, DataSeed['yhat']))

# Communities labeled 0 and 1.
comm0 = DataSeed[DataSeed.y==0].id.unique()
comm1 = DataSeed[DataSeed.y==1].id.unique()

df_node_weight = pd.read_csv('./results/df_node_weight_with_avgimp.csv')

# Preprocess explainer weights: calculate undirectional edge weight by taking the max weight of bidirectional edge weights.
# From node importance scores to edge importance score: "min"/"avg"/"sum".
df_edge_weight = df_e.copy()

df_edge_weight['importance'] = None
df_edge_weight['weight'] = None
df_edge_weight['weight_positive'] = None
df_edge_weight['weight_negative'] = None

for i, row in tqdm(df_edge_weight.iterrows(), total=len(df_edge_weight), ncols=80, mininterval=5):
    src_node_id = row['source']
    dst_node_id = row['target']
    cc_id = row['community_id']

    src_row = df_node_weight[(df_node_weight['node_id']==src_node_id) & (df_node_weight['community_id']==cc_id)].iloc[0]
    dst_row = df_node_weight[(df_node_weight['node_id']==dst_node_id) & (df_node_weight['community_id']==cc_id)].iloc[0]

    if options.edge_agg == 'min':
        edge_imp_annotate = min(src_row['importance_avg'], dst_row['importance_avg'])
    if options.edge_agg == 'avg':
        edge_imp_annotate = np.mean([src_row['importance_avg'], dst_row['importance_avg']])
    if options.edge_agg == 'sum':
        edge_imp_annotate = src_row['importance_avg'] + dst_row['importance_avg']

    edge_weights = DataEdgeWeight[DataEdgeWeight['src'].isin([src_node_id, dst_node_id]) &
                                  DataEdgeWeight['dst'].isin([src_node_id, dst_node_id]) &
                                  DataEdgeWeight['id'].isin([cc_id])]['edge_weight'].max()

    df_edge_weight['importance'].iloc[i] = edge_imp_annotate
    df_edge_weight['weight'].iloc[i] = edge_weights
    df_edge_weight['weight_positive'].iloc[i] = DataEdgeWeight[DataEdgeWeight['src'].isin([src_node_id]) &
                                                               DataEdgeWeight['dst'].isin([dst_node_id]) &
                                                               DataEdgeWeight['id'].isin([cc_id])]['edge_weight'].iloc[0]
    df_edge_weight['weight_negative'].iloc[i] = DataEdgeWeight[DataEdgeWeight['src'].isin([dst_node_id]) &
                                                               DataEdgeWeight['dst'].isin([src_node_id]) &
                                                               DataEdgeWeight['id'].isin([cc_id])]['edge_weight'].iloc[0]

df_edge_weight['combined_weights'] = x_y_df['combined_weights']

# Avg edge/community.
print('Average edges per community:', df_edge_weight.shape[0]/41)

df_edge_weight.rename(columns={'source':'src', 'target': 'dst', 'community_id': 'id',
                       'importance': 'edge_importance', 'combined_weights': 'edge_weight'}, inplace=True)
df_edge_weight.to_csv('./results/df_edge_weight_imp-{}-{}.csv'.format(options.edge_agg, learner))
df_edge_weight.rename(columns={'edge_importance':'importance'}, inplace=True)

df_edge_weight = df_edge_weight.reset_index()

# Topk hit rate
hitrate_df = pd.DataFrame(index=['all', 'comm0', 'comm1'] + list(range(0,41)))

for k in [i*5 for i in range(1,11)]:
    hitrate_list_topk_comm = []
    for cid in df_edge_weight.id.unique():
        df_edge_weight_sub = df_edge_weight[df_edge_weight.id==cid]

        imp_largest = sorted(dict(Counter(df_edge_weight_sub.importance)).items(), reverse=True)[0][0]
        count_largest = sorted(dict(Counter(df_edge_weight_sub.importance)).items(), reverse=True)[0][1]

        hitrate_list_topk = []

        for r in tqdm(range(0,options.random_draw), total=options.random_draw, ncols=80, mininterval=5):
            random.seed(r)
            if count_largest <= k:
                src_id_human_topk = df_edge_weight_sub[['src','dst']].values.tolist()
            else:
                all_human_top_edge_idx = df_edge_weight_sub[df_edge_weight_sub.importance == imp_largest].index
                human_topk_edge_idx = random.sample(list(all_human_top_edge_idx), k)
                src_id_human_topk = df_edge_weight.iloc[human_topk_edge_idx][['src','dst']].values.tolist()

            explainer_topk_edge = df_edge_weight_sub.sort_values(by=['edge_weight'], ascending=False)[['edge_weight', 'src', 'dst']][:k]
            src_id_explainer_topk = explainer_topk_edge[['src','dst']].values.tolist()

            hitrate = len([p for p in src_id_explainer_topk if p in src_id_human_topk or (p[1], p[0]) in src_id_human_topk])/k
            hitrate_list_topk.append(hitrate)
        hitrate_list_topk_comm.append(np.mean(hitrate_list_topk))

    all_hitrate = np.mean(hitrate_list_topk_comm)
    comm0_hitrate = np.mean([h for (i,h) in enumerate(hitrate_list_topk_comm) if i in comm0])
    comm1_hitrate = np.mean([h for (i,h) in enumerate(hitrate_list_topk_comm) if i in comm1])

    hitrate_df['top{}'.format(k)] = [all_hitrate, comm0_hitrate, comm1_hitrate] + hitrate_list_topk_comm

hitrate_df.to_csv('./results/topk-{}-{}-{}.csv'.format(options.random_draw, options.edge_agg, learner), index=True)

ours = hitrate_df.loc[['all', 'comm0', 'comm1']]
print('Our topk hit rate:', ours)

print(ours)

# In[17]:

train = hitrate_df.loc[range(0,21)]
test = hitrate_df.loc[range(21, 41)]
all = hitrate_df.loc[range(0, 41)]
np.mean(train).to_csv('./results/ours_{}_train.csv'.format(learner))
np.mean(test).to_csv('./results/ours_{}_test.csv'.format(learner))
np.mean(all).to_csv('./results/ours_{}_all.csv'.format(learner))


from django.shortcuts import render, redirect
from django.http import JsonResponse
from django.contrib.auth import get_user_model, login, logout
from django.contrib import messages

from . import forms, models
# Create your views here.

User = get_user_model()

def signup_view(request):

    if request.GET.get('validation') == 'true':

        json = {}
        msg = '{} is already taken'
        name = request.GET.get('name')
        print(request.GET)
        if name == 'email':
            email_value = request.GET.get('value')
            json['name'] = name
            try:
                User.objects.get(email = email_value)
                json['taken'] = True
                json['msg'] = msg.format(name)
            except User.DoesNotExist:
                json['taken'] = False
        if name == 'username':
            username_value = request.GET.get('value')
            json['name'] = name
            try:
                User.objects.get(username = username_value)
                json['taken'] = True
                json['msg'] = msg.format(name)
            except User.DoesNotExist:
                json["taken"] = False

        return JsonResponse(json)

    if request.method == 'POST':
        form = forms.CreateUserForm(request.POST)
        if form.is_valid():
            user = form.save()
            if user:

                messages.success(request, 'You may now login to your account')
                print('User saved %r' % (user,))
                return redirect('system_auth:sign-in')

    return render(request, 'system_auth/sign-up.html')

def signin_view(request):
    if request.method == 'POST':
        form = forms.AuthenticationForm(request, request.POST)

        response = None
        if form.is_valid():
            login(request, form.user)
            try:
                groups = form.user.groups.all()
            except Exception as e:
                response = redirect('client:home')
            else:
                group_names = [g.name for g in groups]
                if 'staffs' in group_names:
                    response = redirect('staff:home')

                else:
                    response = redirect('client:home')

            return response
        else:
            messages.error(request, 'The email or username and password are incorrect. Try again')

    return render(request, 'system_auth/sign-in.html')

def logout_view(request):
    logout(request)
    return redirect('system_auth:sign-in')

def unauthorized(request):
    return render(request, 'system_auth/unauthorized.html')


#!/usr/bin/env python3
from pydantic import BaseModel
from pydantic.schema import schema
from typing import Any

class dumClass(BaseModel):

    A : str = 'Hello'
    B : str = None
    C: bool = False

    def __init__(self, **data: Any):
        print("dumClass was called")
        super().__init__(**data)
        print("dumClass was initialized")
        if self.A == "Hello" :
            self.B = "Goodbye"

    def saySomething(self):
        if self.C is False :
            print("Shhhhhh......")
        else :
            print("A is " + self.A + "; B is " + self.B)

def troubleshoot() :

    print("Testing the dumClass!")
    thisJSON={"A":"Hello","C":True}
    try :
        thisproject = dumClass(**thisJSON)
    except ValidationError as e :
        print(e)

    thisproject.saySomething()

def generateSchema():
    import json
    print(dumClass.schema_json(indent=2))

if __name__ == "__main__":
  generateSchema()
  troubleshoot()


from logigraph.logigraph import logigraph
from logigraph.solver import linear_solver, edge_logic_solver, absurd_solver

log = logigraph()
log.set_from_file('logigraph_inputs/nolinear.txt')
l = linear_solver()
e = edge_logic_solver()
a = absurd_solver()

l.solve(log)
print(log)
log.set_from_file('logigraph_inputs/nolinear.txt')
a.solve(log)
print(log)
print(log.is_possible)


'''
Given an arbitrary ransom note string and another string containing letters from all the magazines, write a function that will return true if the ransom note can be constructed from the magazines ; otherwise, it will return false.

Each letter in the magazine string can only be used once in your ransom note.

Example 1:

Input: ransomNote = "a", magazine = "b"
Output: false
Example 2:

Input: ransomNote = "aa", magazine = "ab"
Output: false
Example 3:

Input: ransomNote = "aa", magazine = "aab"
Output: true

'''

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        for i in magazine:
            ransomNote = ransomNote.replace(i, '', 1)
        if len(ransomNote) == 0:
            return True
        else:
            return False


# Libraries
import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import plotly.subplots as sp

# Global Variables
theme_plotly = None  # None or streamlit
week_days = ['Monday', 'Tuesday', 'Wednesday',
             'Thursday', 'Friday', 'Saturday', 'Sunday']

# Layout
st.set_page_config(page_title='Transactions - The Whales of Near',
                   page_icon=':bar_chart:ðŸ“ˆ', layout='wide')
st.title('ðŸŒŒTransactions')

# Style
with open('style.css')as f:
    st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)

# Data Sources
@st.cache()
def get_data(query):
    if query == 'TransactionType_each_Wallet':
        return pd.read_json('https://node-api.flipsidecrypto.com/api/v2/queries/a89edfff-1085-4954-a859-6f2abd0b639f/data/latest')
    elif query == 'Daily_TX_Type':
        return pd.read_json('https://api.flipsidecrypto.com/api/v2/queries/999b8676-c867-4638-8a0b-6833dbef705c/data/latest')
    elif query == 'Daily_TX_FEE_Type':
        return pd.read_json('https://node-api.flipsidecrypto.com/api/v2/queries/7232fce4-57e1-41e9-a356-2a3b857e4687/data/latest')
    elif query == 'Total_Transaction_Comparison':
        return pd.read_json('https://node-api.flipsidecrypto.com/api/v2/queries/fb5217ce-4ab7-44ce-83e5-8aa7b9a79e96/data/latest')
    elif query == 'Top10_Platforms':
        return pd.read_json('https://api.flipsidecrypto.com/api/v2/queries/934aaafb-dde1-41b4-ad66-eb7a15f30e5c/data/latest')
    elif query == 'Top10_TransactionType':
        return pd.read_json('https://api.flipsidecrypto.com/api/v2/queries/e54eaa63-ab14-4313-af7a-fdff2d8abecc/data/latest')
    elif query == 'TX_SUCC_Fail':
        return pd.read_json('https://api.flipsidecrypto.com/api/v2/queries/a21367b3-6df5-447c-996e-919d2f89b6e7/data/latest')
    elif query == 'D_TX_type':
        return pd.read_json('https://api.flipsidecrypto.com/api/v2/queries/645f8b4c-f300-49a5-b37a-dc3a5ab7da59/data/latest')
    elif query == 'D_Fee_Type':
        return pd.read_json('https://api.flipsidecrypto.com/api/v2/queries/4b0ac171-828a-4afa-ae66-0758801aa3d4/data/latest')
    return None

TransactionType_each_Wallet = get_data('TransactionType_each_Wallet')
Daily_TX_Type = get_data('Daily_TX_Type')
Daily_TX_FEE_Type = get_data('Daily_TX_FEE_Type')
Total_Transaction_Comparison = get_data('Total_Transaction_Comparison')
Top10_Platforms = get_data('Top10_Platforms')
Top10_TransactionType = get_data('Top10_TransactionType')
TX_SUCC_Fail = get_data('TX_SUCC_Fail')
D_TX_type = get_data('D_TX_type')
D_Fee_Type = get_data('D_Fee_Type')

df = TransactionType_each_Wallet
df2 = Daily_TX_Type
df3 = Daily_TX_FEE_Type
df4 = Total_Transaction_Comparison
df5 = Top10_Platforms
df6 = Top10_TransactionType
df6 = TX_SUCC_Fail
df7 = D_TX_type
df8 = D_Fee_Type
######################################################################################################################

st.write(""" ### Transaction Concept ##  """)

st.write("""
A Simply put, cryptocurrency transaction is a transfer of information made between blockchain addresses. These transfers have to be signed with a private key that corresponds to its address. Signed transactions are broadcast to the network of nodes, active computers that follow a specific set of rules to validate transactions and blocks. Valid transactions need to be confirmed by being included in blocks through the process of mining.[[4]](https://www.bitstamp.net/learn/crypto-101/how-do-cryptocurrency-transactions-work/)   """)

st.info(""" ##### In This Transaction Section you can find: ####

 * Whales Different Type of Transactions Activity
 * Whales Transactions Compare to other Users
 * Whales Weekly Transaction Prespective view (Last 12 Month)
 * Whales Daily Transaction Zoom in (Last 3 Month)

""")

#####################################################################################
st.text(" \n")
st.text(" \n")
st.write(""" ## Whales Transaction Activity """)

st.write(""" 95.1% percent of whale transactions were transferring, while Staking was ranked second-to-last before deleted accounts. What is really shocking here is that there was no NFT trading or mint transaction during the 12-month period (Checked with another query), and the number of swap transactions was relatively low. While four of the top twenty whales had no transaction during the last 12 months, "5c33c6218d47e00ef229f60da78d0897e1ee9665312550b8afd5f9c7bc6957d2" ranked first with 147,334 transactions which all of them is transferring. The user seems to be a bot due to its more than ten transactions per minute performance.  "d73888a2619c7761735f23c798536145dfa87f9306b5f21275eb4b1a7ba971b9" Ranked third with 20,284 number of transactions we discuss these two whales more in CEX exchange section. "token.sweat" stood first among platforms with a significant difference from others (with 20,834 whale usage in one year). """)

# Transaction Type In Each Wallet
fig = px.bar(df.sort_values(["TRADER", "Number of Action Type"], ascending=[
    True, False]), x="TRADER", y="Number of Action Type", color="Action Type", title='Whales Type of Transactions [Log Scale]', log_y=True)
fig.update_layout(legend_title=None, xaxis_title=None,
                  yaxis_title='Whales Transaction')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

c1, c2 = st.columns(2)

with c1:
    fig = px.pie(df6, values="Number of Action Type",
                 names="Action Type", title='Share of each Transaction Type Used by Whales [Percentage]', hole=0.4)
    fig.update_layout(legend_title=None, legend_y=0.5)
    fig.update_traces(textinfo='percent+value', textposition='inside')
    st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

with c2:
    # Top Transaction Type Used Whales [Log Value]
    fig = px.bar(df6, x="Action Type", y="Number of Action Type",
                 color="Action Type", title='Top Transaction Type Used by Whales [Log Scale]', log_y=True)
    fig.update_layout(showlegend=True, xaxis_title=None,
                      yaxis_title='Number of Transaction')
    st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

# Top 10 Platforms Whales Used
fig = px.bar(df5, x="PLATFORM", y="Platforms usage",
             color="PLATFORM", title='Top 10 Platforms Whales Used in Number of Transactions')
fig.update_layout(showlegend=True, xaxis_title=None,
                  yaxis_title='Platform Usage')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)
########################################################################################################################

st.text(" \n")
st.text(" \n")
st.write(""" ## Whale Compare to Other Users  """)

st.write(""" Although the share of the top 20 whales in the number of total transactions was less than 1 percent, the average transaction per user among whales was 473.125 during 12 months, which was more than 13 times as high as this average among other users. In contrast, the average transaction fees paid by whales were lower than by regular users (0.0603 and 0.06564 Near, respectively). """)

c1, c2, c3 = st.columns(3)
with c1:

    # Whales Compare to Other Users Total Transactions
    fig = px.bar(df4, x="STATUS", y="Number of Transactions",
                 color="STATUS", title='Whales Compare to Other Users Total Transactions [Log Scale]', log_y=True)
    fig.update_layout(showlegend=True, xaxis_title=None,
                      yaxis_title='Number of Transactions')
    st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

with c2:
    # Whales Compare to Other Users Percentage of Transactions
    fig = px.pie(df4, values="Number of Transactions",
                 names="STATUS", title='Whales Compare to Other Users Percentage of Transactions', hole=0.4)
    fig.update_layout(legend_title=None, legend_y=0.5)
    fig.update_traces(textinfo='percent', textposition='inside')
    st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

with c3:
    # Whales Compare to Other Users Average Transactions per User
    fig = px.bar(df4, x="STATUS", y="Average Transaction Per User",
                 color="STATUS", title='Whales Compare to Other Users Average Transactions per User [Log Scale]', log_y=True)
    fig.update_layout(showlegend=True, xaxis_title=None,
                      yaxis_title='Average Number of Transactions')
    st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

c1, c2, c3 = st.columns(3)
with c1:

    # Whales Compare to Other Users Total Transactions Fees
    fig = px.bar(df4, x="STATUS", y="TOTAL_TX_FEE",
                 color="STATUS", title='Whales Compare to Other Users Total Transactions Fees [Near-Log Scale]', log_y=True)
    fig.update_layout(showlegend=True, xaxis_title=None,
                      yaxis_title='Total Transaction Fees')
    st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)
with c2:
    # Whales Compare to Other Users Percentage of Transactions Fees
    fig = px.pie(df4, values="TOTAL_TX_FEE",
                 names="STATUS", title='Whales Compare to Other Users Percentage of Transactions Fees', hole=0.4)
    fig.update_layout(legend_title=None, legend_y=0.5)
    fig.update_traces(textinfo='percent', textposition='inside')
    st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

with c3:
    # Whales Compare to Other Users Average Transaction Fees paid per Users
    fig = px.bar(df4, x="STATUS", y="Average Transaction Fee Per Users",
                 color="STATUS", title='Whales Compare to Other Users Average Transaction Fees paid per Users [Near-Log Scale ]', log_y=True)
    fig.update_layout(showlegend=True, xaxis_title=None,
                      yaxis_title='Average Transaction Fees')
    st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

##################################################################################################################
st.text(" \n")
st.text(" \n")
st.write(""" ## Whale Weekly Transaction and Transaction Fees  """)

st.write(""" While the first six months of 2022 experienced fluctuation of around 2k transactions per week, the second half showed a significant rise and stood at 8000 transactions in a week. The first week of November 2022 had the highest transaction, with more than 14K. As previously mentioned, most of these
 transactions were transferring, but the share of function-call rose significantly in the second half of 2022.   """)

#  Weekly Transactions Classified By Users
fig = px.bar(df2.sort_values(["DATE", "Number of Action Type"], ascending=[
    True, False]), x="DATE", y="Number of Action Type", color="TRADER", title='Weekly Whales Transactions Classified By Users')
fig.update_layout(legend_title=None, xaxis_title=None,
                  yaxis_title='Weekly Transaction')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

# Weekly Transactions Classified By Transaction Type
fig = px.bar(df2.sort_values(["DATE", "Number of Action Type"], ascending=[
    True, False]), x="DATE", y="Number of Action Type", color="Action Type", title='Weekly Whales Transactions Classified By Transaction Type')
fig.update_layout(legend_title=None, xaxis_title=None,
                  yaxis_title='Weekly Transaction')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

#  Weekly Transactions Success and Fails
fig = px.bar(df6.sort_values(["DATE", "Number of Action Type"], ascending=[
    True, False]), x="DATE", y="Number of Action Type", color="TX_STATUS", title='Weekly Whales Transactions Success and Fails')
fig.update_layout(legend_title=None, xaxis_title=None,
                  yaxis_title='Weekly Transaction')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

#############################################################################################################

# Weekly Transaction Fee Classified by Transaction Type
fig = px.bar(df3.sort_values(["DATE", "Weekly Transaction Fee"], ascending=[
    True, False]), x="DATE", y="Weekly Transaction Fee", color="Action Type", title='Weekly Transaction Fee Classified by Transaction Type')
fig.update_layout(legend_title=None, xaxis_title=None,
                  yaxis_title='Weekly Transaction Fees')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

# Weekly Transaction Fee Classified by Users
fig = px.bar(df3.sort_values(["DATE", "Weekly Transaction Fee"], ascending=[
    True, False]), x="DATE", y="Weekly Transaction Fee", color="TRADER", title='Weekly Transaction Fee Classified by Users')
fig.update_layout(legend_title=None, xaxis_title=None,
                  yaxis_title='Weekly Transaction Fees')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

##########################################################################################################
st.text(" \n")
st.text(" \n")
st.write(""" ## Whale Daily Transaction and Transaction Fees  """)

st.write(""" Whale's daily transactions remained relatively unchanged in the last three months until Feb 14, 2023, which became more than three times as high as its average. While most of these transactions were committed by one user(2800 out of a total of 3300), half of these transactions were transferring, and almost half of it was function-call. It is interesting to know what happened on that day ?!.  """)

#  Daily Transactions Classified By Users
fig = px.bar(df7.sort_values(["DATE", "Number of Action Type"], ascending=[
    True, False]), x="DATE", y="Number of Action Type", color="TRADER", title='Daily Whales Transactions Classified By Users')
fig.update_layout(legend_title=None, xaxis_title=None,
                  yaxis_title='Daily Transaction')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

# Daily Transactions Classified By Transaction Type
fig = px.bar(df7.sort_values(["DATE", "Number of Action Type"], ascending=[
    True, False]), x="DATE", y="Number of Action Type", color="Action Type", title='Daily Whales Transactions Classified By Transaction Type')
fig.update_layout(legend_title=None, xaxis_title=None,
                  yaxis_title='Daily Transaction')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

# Daily Transaction Fee Classified by Transaction Type
fig = px.bar(df8.sort_values(["DATE", "Daily Transaction Fee"], ascending=[
    True, False]), x="DATE", y="Daily Transaction Fee", color="Action Type", title='Daily Transaction Fee Classified by Transaction Type')
fig.update_layout(legend_title=None, xaxis_title=None,
                  yaxis_title='Daily Transaction Fees')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

# Daily Transaction Fee Classified by Users
fig = px.bar(df8.sort_values(["DATE", "Daily Transaction Fee"], ascending=[
    True, False]), x="DATE", y="Daily Transaction Fee", color="TRADER", title='Daily Transaction Fee Classified by Users')
fig.update_layout(legend_title=None, xaxis_title=None,
                  yaxis_title='Daily Transaction Fees')
st.plotly_chart(fig, use_container_width=True, theme=theme_plotly)

############################################################################################
st.text(" \n")

st.info(""" #### Coclusion: ####

 * 95 percent of whale transactions were transferring- No NFT traded- relatively low stake and swaps
 * Although whales accounted for less than 1 percent of Total transactions, they had average transaction figures 12 times higher than regular users
 * Number of Whales Transactions rose significantly in the second half of 2022
 * on 14 Feb 2022, the number of transactions rose more than three times its average

""")


from rad.rest.client.api.zonemgr_1 import RAD_NAMESPACE
from rad.rest.client.api.rad_interface import RADInterface
from rad.rest.client.api.zonemgr_1.zone_resources import AnetResource, ZoneResourceFactory

class Zone(RADInterface):
    RAD_COLLECTION = 'Zone'

    def __init__(self, *args, **kwargs):
        super().__init__(RAD_NAMESPACE, Zone.RAD_COLLECTION, *args, **kwargs)

    def init(self):
        if self.json is None:
            self.id = None
            self.name = None
            self.brand = None
            self.uuid = None
            self.auxstate = None
            self.state = None
        else:
            self.id = self.json.get('id')
            self.name = self.json.get('name')
            self.brand = self.json.get('brand')
            self.uuid = self.json.get('uuid')
            self.auxstate = self.json.get('auxstate')
            self.state = self.json.get('state')

    def getResourceProperties(self, filter, properties=None):
        json_body = {}
        if filter is not None:
            json_body['filter'] = {"type": filter.type}
        if properties is not None:
            json_body['properties'] = properties
        properties = self.rad_method('getResourceProperties', json_body)
        return [filter.load_property(property) for property in properties]

    def getResources(self, filter=None, scope=None):
        json_body = {}
        if filter is not None:
            json_body['filter'] = {"type": filter.type}
        if scope is not None:
            json_body['scope'] = {"type": scope.type}
        return self.rad_method('getResources', json_body)

    def get_properties(self):
        payload = self.getResources(scope=AnetResource())
        subresources = {}
        for resource_instance in payload:
            subresources.setdefault(resource_instance['parent'], []).append(
                ZoneResourceFactory.from_json(resource_instance))
        resource_instances = self.getResources()
        global_resource = None
        resources = []
        for resource_instance in resource_instances:
            resource = ZoneResourceFactory.from_json(resource_instance)
            if resource.type == 'anet':
                key = '%s,tmp-id=%s' % (
                    resource.type, str(resource.get('tmp-id').value))
                if key in subresources:
                    resource.resources = subresources[key]
            if resource.type == 'global':
                global_resource = resource
            else:
                resources.append(resource)
        global_resource.resources = resources
        return global_resource


import itertools

input = """
Sugar: capacity 3, durability 0, flavor 0, texture -3, calories 2
Sprinkles: capacity -3, durability 3, flavor 0, texture 0, calories 9
Candy: capacity -1, durability 0, flavor 4, texture 0, calories 1
Chocolate: capacity 0, durability 0, flavor -2, texture 2, calories 8
"""

ingredients = dict()

for line in input.strip().split("\n"):
  ingredient_name, _, capacity, _, durability, _, flavor, _, texture, _, calories = line.split(" ")
  ingredient_name = ingredient_name.rstrip(":")
  ingredients[ingredient_name] = dict()
  ingredients[ingredient_name]["capacity"] = int(capacity.rstrip(','))
  ingredients[ingredient_name]["durability"] = int(durability.rstrip(','))
  ingredients[ingredient_name]["flavor"] = int(flavor.rstrip(','))
  ingredients[ingredient_name]["texture"] = int(texture.rstrip(','))
  ingredients[ingredient_name]["calories"] = int(calories)

star1 = 0
star2 = 0

total_capacity = 0
total_durability = 0
total_flavor = 0
total_texture = 0

total_ingredients = 100

total_scores = []
total_scores_calorie_limited = []

for i1 in range(total_ingredients):
  for i2 in range(total_ingredients - i1):
    for i3 in range(total_ingredients - i1 - i2):
      i4 = total_ingredients - i1 - i2 - i3
      total_capacity = i1 * ingredients["Sugar"]["capacity"] + i2 * ingredients["Sprinkles"]["capacity"] + i3 * ingredients["Candy"]["capacity"] + i4 * ingredients["Chocolate"]["capacity"]
      total_durability = i1 * ingredients["Sugar"]["durability"] + i2 * ingredients["Sprinkles"]["durability"] + i3 * ingredients["Candy"]["durability"] + i4 * ingredients["Chocolate"]["durability"]
      total_flavor = i1 * ingredients["Sugar"]["flavor"] + i2 * ingredients["Sprinkles"]["flavor"] + i3 * ingredients["Candy"]["flavor"] + i4 * ingredients["Chocolate"]["flavor"]
      total_texture = i1 * ingredients["Sugar"]["texture"] + i2 * ingredients["Sprinkles"]["texture"] + i3 * ingredients["Candy"]["texture"] + i4 * ingredients["Chocolate"]["texture"]
      total_calories = i1 * ingredients["Sugar"]["calories"] + i2 * ingredients["Sprinkles"]["calories"] + i3 * ingredients["Candy"]["calories"] + i4 * ingredients["Chocolate"]["calories"]

      if total_capacity < 0:
        total_capacity = 0
      if total_durability < 0:
        total_durability = 0
      if total_flavor < 0:
        total_flavor = 0
      if total_texture < 0:
        total_texture = 0

      total_score = total_capacity * total_durability * total_flavor * total_texture
      total_scores.append(total_score)

      if total_calories == 500:
        total_scores_calorie_limited.append(total_score)

star1 = max(total_scores)
star2 = max(total_scores_calorie_limited)

print("star 1", star1)
print("star 1", star2)


import os
import argparse
from os.path import join
import cv2
import dlib
from PIL import Image as pil_image
from tqdm import tqdm
import numpy as np
from pathlib import Path
from dataset import image_paths, _find_images

def get_boundingbox(face, width, height, scale=1.3, minsize=None):
    x1 = face.left()
    y1 = face.top()
    x2 = face.right()
    y2 = face.bottom()
    size_bb = int(max(x2 - x1, y2 - y1) * scale)
    if minsize:
        if size_bb < minsize:
            size_bb = minsize
    center_x, center_y = (x1 + x2) // 2, (y1 + y2) // 2

    x1 = max(int(center_x - size_bb // 2), 0)
    y1 = max(int(center_y - size_bb // 2), 0)

    size_bb = min(width - x1, size_bb)
    size_bb = min(height - y1, size_bb)

    return x1, y1, size_bb

def processVideos(video_path, output_path,
                            start_frame=0, end_frame=None, cuda=True, video_name=None):
    print('Starting: {}'.format(video_path))
    reader = cv2.VideoCapture(video_path)

    video_fn = video_path.split('/')[-1].split('.')[0] + '.avi'
    fps = reader.get(cv2.CAP_PROP_FPS)
    num_frames = int(reader.get(cv2.CAP_PROP_FRAME_COUNT))
    print("Number of frames", num_frames)

    # face detector
    face_detector = dlib.get_frontal_face_detector()

    font_face = cv2.FONT_HERSHEY_SIMPLEX
    thickness = 2
    font_scale = 1

    frame_num = 0
    if(start_frame >= num_frames - 1):
        return
    end_frame = end_frame if end_frame else num_frames

    while reader.isOpened():
        _, image = reader.read()
        if image is None:
            break
        frame_num += 1

        if frame_num < start_frame:
            continue

        height, width = image.shape[:2]

        # 2. Detect with dlib
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        faces = face_detector(gray, 1)
        if len(faces):
            # Largest face is taken
            face = faces[0]

            x, y, size = get_boundingbox(face, width, height)
            cropped_face = image[y:y + size, x:x + size]
            cropped_face = pil_image.fromarray(cropped_face)
            cropped_face = cropped_face.resize((299, 299))
            cropped_face = np.array(cropped_face)
            cv2.imwrite(join(output_path, video_name + '_{:04d}.png'.format(frame_num)),
                        cropped_face)
        if frame_num >= end_frame:
            break

def resizeFrames(args):
    directory = args.video_path
    directories = sorted(map(str, filter(
        lambda x: x.is_dir(), Path(directory).iterdir())))
    for i, directory in enumerate(directories):
        images = list(sorted(image_paths(directory)))
        for image in images:
            print("Directory Name", directory)
            print("No of images", len(images))
            x = pil_image.open(image)
            x = x.resize((299, 299))
            x.save(image, 'PNG')

def countFrames(video_path):
    print('Starting: {}'.format(video_path))
    reader = cv2.VideoCapture(video_path)

    video_fn = video_path.split('/')[-1].split('.')[0]+'.avi'
    fourcc = cv2.VideoWriter_fourcc(*'MJPG')
    fps = reader.get(cv2.CAP_PROP_FPS)
    num_frames = int(reader.get(cv2.CAP_PROP_FRAME_COUNT))
    print("Number of frames", num_frames)

if __name__ == '__main__':
    p = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    p.add_argument('--video_path', '-i', type=str)
    p.add_argument('--output_path', '-o', type=str,
                   default='.')
    p.add_argument('--start_frame', type=int, default=0)
    p.add_argument('--end_frame', type=int, default=None)
    #p.add_argument('--cuda', action='store_true')

    args = p.parse_args()

    video_path = args.video_path
    if video_path.endswith('.mp4') or video_path.endswith('.avi'):
       processVideos(**vars(args), video_name="fake")
    else:
       videos = os.listdir(video_path)
       for video in videos:
           video_name = video.split('.mp4')
           args.video_path = join(video_path, video)
           #countFrames(args.video_path)
           processVideos(**vars(args), video_name=video_name[0])


errors = {
    "out":"Вы вышли из системы",
    "noaccess":"У вас нет доступа в раздел",
    "unknown":"Неизвестная ошибка",
    "timeout":"Система долго не отвечает",
    "robot":"Ваши действия похожи на робота"
}

def get_error(*args):
    err_list = []
    for k in args:
        err_list.append(errors[k])

    return print(err_list)

def main():
    get_error("robot", "timeout")

if __name__ == "__main__":
    main()


from __future__ import absolute_import
from __future__ import division
import re
from functools import reduce

import wx
import wx.stc
from six.moves import xrange

from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD
from plcopen.structures import ST_BLOCK_START_KEYWORDS, IEC_BLOCK_START_KEYWORDS, LOCATIONDATATYPES
from editors.EditorPanel import EditorPanel
from controls.CustomStyledTextCtrl import CustomStyledTextCtrl, faces, GetCursorPos

# -------------------------------------------------------------------------------
#                         Textual programs Viewer class
# -------------------------------------------------------------------------------

NEWLINE = "\n"
NUMBERS = [str(i) for i in xrange(10)]
LETTERS = ['_']
for i in xrange(26):
    LETTERS.append(chr(ord('a') + i))
    LETTERS.append(chr(ord('A') + i))

[STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_STRING,
 STC_PLC_VARIABLE, STC_PLC_PARAMETER, STC_PLC_FUNCTION, STC_PLC_JUMP,
 STC_PLC_ERROR, STC_PLC_SEARCH_RESULT,
 STC_PLC_EMPTY] = range(11)
[SPACE, WORD, NUMBER, STRING, WSTRING, COMMENT, PRAGMA, DPRAGMA] = range(8)

re_texts = {}
re_texts["letter"] = "[A-Za-z]"
re_texts["digit"] = "[0-9]"
re_texts["identifier"] = "((?:%(letter)s|(?:_(?:%(letter)s|%(digit)s)))(?:_?(?:%(letter)s|%(digit)s))*)" % re_texts
IDENTIFIER_MODEL = re.compile(re_texts["identifier"])
LABEL_MODEL = re.compile("[ \t\n]%(identifier)s:[ \t\n]" % re_texts)
EXTENSIBLE_PARAMETER = re.compile("IN[1-9][0-9]*$")

HIGHLIGHT_TYPES = {
    ERROR_HIGHLIGHT: STC_PLC_ERROR,
    SEARCH_RESULT_HIGHLIGHT: STC_PLC_SEARCH_RESULT,
}

def LineStartswith(line, symbols):
    return reduce(lambda x, y: x or y, map(line.startswith, symbols), False)

class TextViewer(EditorPanel):

    def _init_Editor(self, prnt):
        self.Editor = CustomStyledTextCtrl(parent=prnt, name="TextViewer", size=wx.Size(0, 0), style=0)
        self.Editor.ParentWindow = self

        self.Editor.CmdKeyAssign(ord('+'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN)
        self.Editor.CmdKeyAssign(ord('-'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT)

        self.Editor.SetViewWhiteSpace(False)

        self.Editor.SetLexer(wx.stc.STC_LEX_CONTAINER)

        # Global default styles for all languages
        self.Editor.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
        self.Editor.StyleClearAll()  # Reset all to be like the default

        self.Editor.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,  "back:#C0C0C0,size:%(size)d" % faces)
        self.Editor.SetSelBackground(1, "#E0E0E0")

        # Highlighting styles
        self.Editor.StyleSetSpec(STC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
        self.Editor.StyleSetSpec(STC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces)
        self.Editor.StyleSetSpec(STC_PLC_PARAMETER, "fore:#7F007F,size:%(size)d" % faces)
        self.Editor.StyleSetSpec(STC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces)
        self.Editor.StyleSetSpec(STC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces)
        self.Editor.StyleSetSpec(STC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
        self.Editor.StyleSetSpec(STC_PLC_STRING, "fore:#007F00,size:%(size)d" % faces)
        self.Editor.StyleSetSpec(STC_PLC_JUMP, "fore:#FF7FFF,size:%(size)d" % faces)
        self.Editor.StyleSetSpec(STC_PLC_ERROR, "fore:#FF0000,back:#FFFF00,size:%(size)d" % faces)
        self.Editor.StyleSetSpec(STC_PLC_SEARCH_RESULT, "fore:#FFFFFF,back:#FFA500,size:%(size)d" % faces)

        # Indicators styles
        self.Editor.IndicatorSetStyle(0, wx.stc.STC_INDIC_SQUIGGLE)
        if self.ParentWindow is not None and self.Controler is not None:
            self.Editor.IndicatorSetForeground(0, wx.RED)
        else:
            self.Editor.IndicatorSetForeground(0, wx.WHITE)

        # Line numbers in the margin
        self.Editor.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
        self.Editor.SetMarginWidth(1, 50)

        # Folding
        self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN,    wx.stc.STC_MARK_BOXMINUS,          "white", "#808080")
        self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER,        wx.stc.STC_MARK_BOXPLUS,           "white", "#808080")
        self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB,     wx.stc.STC_MARK_VLINE,             "white", "#808080")
        self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL,    wx.stc.STC_MARK_LCORNER,           "white", "#808080")
        self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND,     wx.stc.STC_MARK_BOXPLUSCONNECTED,  "white", "#808080")
        self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
        self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_TCORNER,           "white", "#808080")

        # Indentation size
        self.Editor.SetTabWidth(2)
        self.Editor.SetUseTabs(0)

        self.Editor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT |
                                    wx.stc.STC_MOD_BEFOREDELETE |
                                    wx.stc.STC_PERFORMED_USER)

        self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyleNeeded, self.Editor)
        self.Editor.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
        self.Editor.Bind(wx.stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
        self.Editor.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        if self.Controler is not None:
            self.Editor.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
            self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, self.Editor)
            self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, self.Editor)

    def __init__(self, parent, tagname, window, controler, debug=False, instancepath=""):
        if tagname != "" and controler is not None:
            self.VARIABLE_PANEL_TYPE = controler.GetPouType(tagname.split("::")[1])

        EditorPanel.__init__(self, parent, tagname, window, controler, debug)

        self.Keywords = []
        self.Variables = {}
        self.Functions = {}
        self.TypeNames = []
        self.Jumps = []
        self.EnumeratedValues = []
        self.DisableEvents = True
        self.TextSyntax = None
        self.CurrentAction = None

        self.InstancePath = instancepath
        self.ContextStack = []
        self.CallStack = []

        self.ResetSearchResults()

        self.RefreshHighlightsTimer = wx.Timer(self, -1)
        self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer)

    def __del__(self):
        self.RefreshHighlightsTimer.Stop()

    def GetTitle(self):
        if self.Debug or self.TagName == "":
            if len(self.InstancePath) > 15:
                return "..." + self.InstancePath[-12:]
            return self.InstancePath
        return EditorPanel.GetTitle(self)

    def GetInstancePath(self):
        return self.InstancePath

    def IsViewing(self, tagname):
        if self.Debug or self.TagName == "":
            return self.InstancePath == tagname
        else:
            return self.TagName == tagname

    def GetText(self):
        return self.Editor.GetText()

    def SetText(self, text):
        self.Editor.SetText(text)

    def SelectAll(self):
        self.Editor.SelectAll()

    def Colourise(self, start, end):
        self.Editor.Colourise(start, end)

    def StartStyling(self, pos, mask):
        self.Editor.StartStyling(pos, mask)

    def SetStyling(self, length, style):
        self.Editor.SetStyling(length, style)

    def GetCurrentPos(self):
        return self.Editor.GetCurrentPos()

    def ResetSearchResults(self):
        self.Highlights = []
        self.SearchParams = None
        self.SearchResults = None
        self.CurrentFindHighlight = None

    def OnModification(self, event):
        if not self.DisableEvents:
            mod_type = event.GetModificationType()
            if mod_type & wx.stc.STC_MOD_BEFOREINSERT:
                if self.CurrentAction is None:
                    self.StartBuffering()
                elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1:
                    self.Controler.EndBuffering()
                    self.StartBuffering()
                self.CurrentAction = ("Add", event.GetPosition())
                wx.CallAfter(self.RefreshModel)
            elif mod_type & wx.stc.STC_MOD_BEFOREDELETE:
                if self.CurrentAction is None:
                    self.StartBuffering()
                elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1:
                    self.Controler.EndBuffering()
                    self.StartBuffering()
                self.CurrentAction = ("Delete", event.GetPosition())
                wx.CallAfter(self.RefreshModel)
        event.Skip()

    def OnDoDrop(self, event):
        try:
            values = eval(event.GetDragText())
        except Exception:
            values = event.GetDragText()
        if isinstance(values, tuple):
            message = None
            if values[1] in ["program", "debug"]:
                event.SetDragText("")
            elif values[1] in ["functionBlock", "function"]:
                blocktype = values[0]
                blockname = values[2]
                if len(values) > 3:
                    blockinputs = values[3]
                else:
                    blockinputs = None
                if values[1] != "function":
                    if blockname == "":
                        dialog = wx.TextEntryDialog(self.ParentWindow, _("Block name"), _("Please enter a block name"), "", wx.OK | wx.CANCEL | wx.CENTRE)
                        if dialog.ShowModal() == wx.ID_OK:
                            blockname = dialog.GetValue()
                        else:
                            event.SetDragText("")
                            return
                        dialog.Destroy()
                    if blockname.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
                        message = _("\"%s\" pou already exists!") % blockname
                    elif blockname.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
                        message = _("\"%s\" element for this pou already exists!") % blockname
                    else:
                        self.Controler.AddEditedElementPouVar(self.TagName, values[0], blockname)
                        self.RefreshVariablePanel()
                        self.RefreshVariableTree()
                blockinfo = self.Controler.GetBlockType(blocktype, blockinputs, self.Debug)
                hint = ',\n    '.join(
                    [" " + fctdecl[0]+" := (*"+fctdecl[1]+"*)" for fctdecl in blockinfo["inputs"]] +
                    [" " + fctdecl[0]+" => (*"+fctdecl[1]+"*)" for fctdecl in blockinfo["outputs"]])
                if values[1] == "function":
                    event.SetDragText(blocktype+"(\n    "+hint+")")
                else:
                    event.SetDragText(blockname+"(\n    "+hint+")")
            elif values[1] == "location":
                _pou_name, pou_type = self.Controler.GetEditedElementType(self.TagName, self.Debug)
                if len(values) > 2 and pou_type == "program":
                    var_name = values[3]
                    dlg = wx.TextEntryDialog(
                        self.ParentWindow,
                        _("Confirm or change variable name"),
                        _('Variable Drop'), var_name)
                    dlg.SetValue(var_name)
                    var_name = dlg.GetValue() if dlg.ShowModal() == wx.ID_OK else None
                    dlg.Destroy()
                    if var_name is None:
                        return
                    elif var_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
                        message = _("\"%s\" pou already exists!") % var_name
                    elif var_name.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
                        message = _("\"%s\" element for this pou already exists!") % var_name
                    else:
                        location = values[0]
                        if not location.startswith("%"):
                            dialog = wx.SingleChoiceDialog(
                                self.ParentWindow,
                                _("Select a variable class:"),
                                _("Variable class"),
                                [_("Input"), _("Output"), _("Memory")],
                                wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
                            if dialog.ShowModal() == wx.ID_OK:
                                selected = dialog.GetSelection()
                            else:
                                selected = None
                            dialog.Destroy()
                            if selected is None:
                                event.SetDragText("")
                                return
                            if selected == 0:
                                location = "%I" + location
                            elif selected == 1:
                                location = "%Q" + location
                            else:
                                location = "%M" + location
                        if values[2] is not None:
                            var_type = values[2]
                        else:
                            var_type = LOCATIONDATATYPES.get(location[2], ["BOOL"])[0]
                        self.Controler.AddEditedElementPouVar(
                            self.TagName,
                            var_type, var_name,
                            location=location, description=values[4])
                        self.RefreshVariablePanel()
                        self.RefreshVariableTree()
                        event.SetDragText(var_name)
                else:
                    event.SetDragText("")
            elif values[1] == "NamedConstant":
                _pou_name, pou_type = self.Controler.GetEditedElementType(self.TagName, self.Debug)
                if pou_type == "program":
                    initval = values[0]
                    var_name = values[3]
                    dlg = wx.TextEntryDialog(
                        self.ParentWindow,
                        _("Confirm or change variable name"),
                        _('Variable Drop'), var_name)
                    dlg.SetValue(var_name)
                    var_name = dlg.GetValue() if dlg.ShowModal() == wx.ID_OK else None
                    dlg.Destroy()
                    if var_name is None:
                        return
                    elif var_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
                        message = _("\"%s\" pou already exists!") % var_name
                    else:
                        var_type = values[2]
                        if not var_name.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
                            self.Controler.AddEditedElementPouVar(self.TagName,
                                                                  var_type,
                                                                  var_name,
                                                                  description=values[4], initval=initval)
                            self.RefreshVariablePanel()
                            self.RefreshVariableTree()
                        event.SetDragText(var_name)
            elif values[1] == "Global":
                var_name = values[0]
                dlg = wx.TextEntryDialog(
                    self.ParentWindow,
                    _("Confirm or change variable name"),
                    _('Variable Drop'), var_name)
                dlg.SetValue(var_name)
                var_name = dlg.GetValue() if dlg.ShowModal() == wx.ID_OK else None
                dlg.Destroy()
                if var_name is None:
                    return
                elif var_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
                    message = _("\"%s\" pou already exists!") % var_name
                else:
                    if not var_name.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
                        kwargs = dict(description=values[4]) if len(values)>4 else {}
                        self.Controler.AddEditedElementPouExternalVar(self.TagName, values[2], var_name, **kwargs)
                        self.RefreshVariablePanel()
                        self.RefreshVariableTree()
                    event.SetDragText(var_name)
            elif values[1] == "Constant":
                event.SetDragText(values[0])
            elif values[3] == self.TagName:
                self.ResetBuffer()
                event.SetDragText(values[0])
                wx.CallAfter(self.RefreshModel)
            else:
                message = _("Variable don't belong to this POU!")
            if message is not None:
                dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
                dialog.ShowModal()
                dialog.Destroy()
                event.SetDragText("")
        event.Skip()

    def SetTextSyntax(self, syntax):
        self.TextSyntax = syntax
        if syntax in ["ST", "ALL"]:
            self.Editor.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL)
            self.Editor.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS)
            self.Editor.SetMarginSensitive(2, 1)
            self.Editor.SetMarginWidth(2, 12)
            if syntax == "ST":
                self.BlockStartKeywords = ST_BLOCK_START_KEYWORDS
                self.BlockEndKeywords = ST_BLOCK_START_KEYWORDS
            else:
                self.BlockStartKeywords = IEC_BLOCK_START_KEYWORDS
                self.BlockEndKeywords = IEC_BLOCK_START_KEYWORDS
        else:
            self.BlockStartKeywords = []
            self.BlockEndKeywords = []

    def SetKeywords(self, keywords):
        self.Keywords = [keyword.upper() for keyword in keywords]
        self.Colourise(0, -1)

    def RefreshJumpList(self):
        if self.TextSyntax == "IL":
            self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())]

    # Buffer the last model state
    def RefreshBuffer(self):
        self.Controler.BufferProject()
        if self.ParentWindow:
            self.ParentWindow.RefreshTitle()
            self.ParentWindow.RefreshFileMenu()
            self.ParentWindow.RefreshEditMenu()

    def StartBuffering(self):
        self.Controler.StartBuffering()
        if self.ParentWindow:
            self.ParentWindow.RefreshTitle()
            self.ParentWindow.RefreshFileMenu()
            self.ParentWindow.RefreshEditMenu()

    def ResetBuffer(self):
        if self.CurrentAction is not None:
            self.Controler.EndBuffering()
            self.CurrentAction = None

    def GetBufferState(self):
        if not self.Debug and self.TextSyntax != "ALL":
            return self.Controler.GetBufferState()
        return False, False

    def Undo(self):
        if not self.Debug and self.TextSyntax != "ALL":
            self.Controler.LoadPrevious()
            self.ParentWindow.CloseTabsWithoutModel()

    def Redo(self):
        if not self.Debug and self.TextSyntax != "ALL":
            self.Controler.LoadNext()
            self.ParentWindow.CloseTabsWithoutModel()

    def HasNoModel(self):
        if not self.Debug and self.TextSyntax != "ALL":
            return self.Controler.GetEditedElement(self.TagName) is None
        return False

    def RefreshView(self, variablepanel=True):
        EditorPanel.RefreshView(self, variablepanel)

        if self.Controler is not None:
            self.ResetBuffer()
            self.DisableEvents = True
            old_cursor_pos = self.GetCurrentPos()
            line = self.Editor.GetFirstVisibleLine()
            column = self.Editor.GetXOffset()
            old_text = self.GetText()
            new_text = self.Controler.GetEditedElementText(self.TagName, self.Debug)
            if old_text != new_text:
                self.SetText(new_text)
                new_cursor_pos = GetCursorPos(old_text, new_text)
                self.Editor.LineScroll(column, line)
                if new_cursor_pos is not None:
                    self.Editor.GotoPos(new_cursor_pos)
                else:
                    self.Editor.GotoPos(old_cursor_pos)
                self.RefreshJumpList()
                self.Editor.EmptyUndoBuffer()
            self.DisableEvents = False

            self.RefreshVariableTree()

            self.TypeNames = [typename.upper() for typename in self.Controler.GetDataTypes(self.TagName, True, self.Debug)]
            self.EnumeratedValues = [value.upper() for value in self.Controler.GetEnumeratedDataValues()]

            self.Functions = {}
            for category in self.Controler.GetBlockTypes(self.TagName, self.Debug):
                for blocktype in category["list"]:
                    blockname = blocktype["name"].upper()
                    if blocktype["type"] == "function" and blockname not in self.Keywords and blockname not in self.Variables.keys():
                        interface = dict([(name, {}) for name, _type, _modifier in blocktype["inputs"] + blocktype["outputs"] if name != ''])
                        for param in ["EN", "ENO"]:
                            if param not in interface:
                                interface[param] = {}
                        if blockname in self.Functions:
                            self.Functions[blockname]["interface"].update(interface)
                            self.Functions[blockname]["extensible"] |= blocktype["extensible"]
                        else:
                            self.Functions[blockname] = {"interface": interface,
                                                         "extensible": blocktype["extensible"]}

        self.Colourise(0, -1)

    def RefreshVariableTree(self):
        words = self.TagName.split("::")
        self.Variables = self.GenerateVariableTree([
            (variable.Name, variable.Type, variable.Tree)
            for variable in
            self.Controler.GetEditedElementInterfaceVars(
                self.TagName, True, self.Debug)
        ])
        if self.Controler.GetEditedElementType(self.TagName, self.Debug)[1] == "function" or words[0] == "T" and self.TextSyntax == "IL":
            return_type, (var_tree, _var_dimension) = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, True, self.Debug)
            if return_type is not None:
                self.Variables[words[-1].upper()] = self.GenerateVariableTree(var_tree)
            else:
                self.Variables[words[-1].upper()] = {}

    def GenerateVariableTree(self, list):
        tree = {}
        for var_name, _var_type, (var_tree, _var_dimension) in list:
            tree[var_name.upper()] = self.GenerateVariableTree(var_tree)
        return tree

    def IsValidVariable(self, name, context):
        return context is not None and context.get(name, None) is not None

    def IsCallParameter(self, name, call):
        if call is not None:
            return (call["interface"].get(name.upper(), None) is not None or
                    call["extensible"] and EXTENSIBLE_PARAMETER.match(name.upper()) is not None)
        return False

    def RefreshLineFolding(self, line_number):
        if self.TextSyntax in ["ST", "ALL"]:
            level = wx.stc.STC_FOLDLEVELBASE + self.Editor.GetLineIndentation(line_number)
            line = self.Editor.GetLine(line_number).strip()
            if line == "":
                if line_number > 0:
                    if LineStartswith(self.Editor.GetLine(line_number - 1).strip(), self.BlockEndKeywords):
                        level = self.Editor.GetFoldLevel(self.Editor.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK
                    else:
                        level = self.Editor.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK
                if level != wx.stc.STC_FOLDLEVELBASE:
                    level |= wx.stc.STC_FOLDLEVELWHITEFLAG
            elif LineStartswith(line, self.BlockStartKeywords):
                level |= wx.stc.STC_FOLDLEVELHEADERFLAG
            elif LineStartswith(line, self.BlockEndKeywords):
                if LineStartswith(self.Editor.GetLine(line_number - 1).strip(), self.BlockEndKeywords):
                    level = self.Editor.GetFoldLevel(self.Editor.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK
                else:
                    level = self.Editor.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK
            self.Editor.SetFoldLevel(line_number, level)

    def OnStyleNeeded(self, event):
        self.TextChanged = True
        line_number = self.Editor.LineFromPosition(self.Editor.GetEndStyled())
        if line_number == 0:
            start_pos = last_styled_pos = 0
        else:
            start_pos = last_styled_pos = self.Editor.GetLineEndPosition(line_number - 1) + 1
        self.RefreshLineFolding(line_number)
        end_pos = event.GetPosition()
        self.StartStyling(start_pos, 0xff)

        current_context = self.Variables
        current_call = None

        current_pos = last_styled_pos
        state = SPACE
        line = ""
        word = ""
        while current_pos < end_pos:
            char = chr(self.Editor.GetCharAt(current_pos)).upper()
            line += char
            if char == NEWLINE:
                self.ContextStack = []
                current_context = self.Variables
                if state == COMMENT:
                    self.SetStyling(current_pos - last_styled_pos, STC_PLC_COMMENT)
                elif state == NUMBER:
                    self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
                elif state == WORD:
                    if word in self.Keywords or word in self.TypeNames:
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
                    elif self.IsValidVariable(word, current_context):
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
                    elif self.IsCallParameter(word, current_call):
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_PARAMETER)
                    elif word in self.Functions:
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)
                    elif self.TextSyntax == "IL" and word in self.Jumps:
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP)
                    elif word in self.EnumeratedValues:
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
                    else:
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
                        if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos):
                            self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK)
                            self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK)
                            self.StartStyling(current_pos, 0xff)
                else:
                    self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
                last_styled_pos = current_pos
                if (state != DPRAGMA) and (state != COMMENT):
                    state = SPACE
                line = ""
                line_number += 1
                self.RefreshLineFolding(line_number)
            elif line.endswith("(*") and state != COMMENT:
                self.SetStyling(current_pos - last_styled_pos - 1, STC_PLC_EMPTY)
                last_styled_pos = current_pos
                if state == WORD:
                    current_context = self.Variables
                state = COMMENT
            elif line.endswith("{") and state not in [PRAGMA, DPRAGMA]:
                self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
                last_styled_pos = current_pos
                if state == WORD:
                    current_context = self.Variables
                state = PRAGMA
            elif line.endswith("{{") and state == PRAGMA:
                self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
                last_styled_pos = current_pos
                state = DPRAGMA
            elif state == COMMENT:
                if line.endswith("*)"):
                    self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT)
                    last_styled_pos = current_pos + 1
                    state = SPACE
                    if len(self.CallStack) > 0:
                        current_call = self.CallStack.pop()
                    else:
                        current_call = None
            elif state == PRAGMA:
                if line.endswith("}"):
                    self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
                    last_styled_pos = current_pos
                    state = SPACE
            elif state == DPRAGMA:
                if line.endswith("}}"):
                    self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_EMPTY)
                    last_styled_pos = current_pos + 1
                    state = SPACE
            elif (line.endswith("'") or line.endswith('"')) and state not in [STRING, WSTRING]:
                self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
                last_styled_pos = current_pos
                if state == WORD:
                    current_context = self.Variables
                if line.endswith("'"):
                    state = STRING
                else:
                    state = WSTRING
            elif state == STRING:
                if line.endswith("'") and not line.endswith("$'"):
                    self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_STRING)
                    last_styled_pos = current_pos + 1
                    state = SPACE
            elif state == WSTRING:
                if line.endswith('"') and not line.endswith('$"'):
                    self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_STRING)
                    last_styled_pos = current_pos + 1
                    state = SPACE
            elif char in LETTERS:
                if state == NUMBER:
                    word = "#"
                    state = WORD
                elif state == SPACE:
                    self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
                    word = char
                    last_styled_pos = current_pos
                    state = WORD
                else:
                    word += char
            elif char in NUMBERS or char == '.' and state != WORD:
                if state == SPACE:
                    self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
                    last_styled_pos = current_pos
                    state = NUMBER
                elif state == WORD and char != '.':
                    word += char
            elif char == '(' and state == SPACE:
                self.CallStack.append(current_call)
                current_call = None
            else:
                if state == WORD:
                    if word in self.Keywords or word in self.TypeNames:
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
                    elif self.IsValidVariable(word, current_context):
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
                    elif self.IsCallParameter(word, current_call):
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_PARAMETER)
                    elif word in self.Functions:
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)
                    elif self.TextSyntax == "IL" and word in self.Jumps:
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP)
                    elif word in self.EnumeratedValues:
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
                    else:
                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
                        if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos):
                            self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK)
                            self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK)
                            self.StartStyling(current_pos, 0xff)
                    if char == '.':
                        if word != "]":
                            if current_context is not None:
                                current_context = current_context.get(word, None)
                            else:
                                current_context = None
                    elif char == '(':
                        self.CallStack.append(current_call)
                        current_call = self.Functions.get(word, None)
                        if current_call is None and self.IsValidVariable(word, current_context):
                            current_call = {"interface": current_context.get(word, {}),
                                            "extensible": False}
                        current_context = self.Variables
                    else:
                        if char == '[' and current_context is not None:
                            self.ContextStack.append(current_context.get(word, None))
                        current_context = self.Variables

                    word = ""
                    last_styled_pos = current_pos
                    state = SPACE
                elif state == NUMBER:
                    self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
                    last_styled_pos = current_pos
                    state = SPACE
                if char == ']':
                    if len(self.ContextStack) > 0:
                        current_context = self.ContextStack.pop()
                    else:
                        current_context = self.Variables
                    word = char
                    state = WORD
                elif char == ')':
                    current_context = self.Variables
                    if len(self.CallStack) > 0:
                        current_call = self.CallStack.pop()
                    else:
                        current_call = None
                    word = char
                    state = WORD
            current_pos += 1
        if state == COMMENT:
            self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT)
        elif state == NUMBER:
            self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
        elif state == WORD:
            if word in self.Keywords or word in self.TypeNames:
                self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
            elif self.IsValidVariable(word, current_context):
                self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
            elif self.IsCallParameter(word, current_call):
                self.SetStyling(current_pos - last_styled_pos, STC_PLC_PARAMETER)
            elif self.TextSyntax == "IL" and word in self.Functions:
                self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)
            elif word in self.Jumps:
                self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP)
            elif word in self.EnumeratedValues:
                self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
            else:
                self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
        else:
            self.SetStyling(current_pos - start_pos, STC_PLC_EMPTY)
        self.ShowHighlights(start_pos, end_pos)
        event.Skip()

    def OnMarginClick(self, event):
        if event.GetMargin() == 2:
            line = self.Editor.LineFromPosition(event.GetPosition())
            if self.Editor.GetFoldLevel(line) & wx.stc.STC_FOLDLEVELHEADERFLAG:
                self.Editor.ToggleFold(line)
        event.Skip()

    def OnUpdateUI(self, event):
        selected = self.Editor.GetSelectedText()
        if self.ParentWindow and selected != "":
            self.ParentWindow.SetCopyBuffer(selected, True)
        event.Skip()

    def Cut(self):
        self.ResetBuffer()
        self.DisableEvents = True
        self.Editor.CmdKeyExecute(wx.stc.STC_CMD_CUT)
        self.DisableEvents = False
        self.RefreshModel()
        self.RefreshBuffer()

    def Copy(self):
        self.Editor.CmdKeyExecute(wx.stc.STC_CMD_COPY)
        if self.ParentWindow:
            self.ParentWindow.RefreshEditMenu()

    def Paste(self):
        self.ResetBuffer()
        self.DisableEvents = True
        self.Editor.CmdKeyExecute(wx.stc.STC_CMD_PASTE)
        self.DisableEvents = False
        self.RefreshModel()
        self.RefreshBuffer()

    def Search(self, criteria):
        return self.Controler.SearchInPou(self.TagName, criteria, self.Debug)

    def Find(self, direction, search_params):
        if self.SearchParams != search_params:
            self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT)

            self.SearchParams = search_params
            self.SearchResults = [
                (infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT)
                for infos, start, end, _text in
                self.Search(search_params)]
            self.CurrentFindHighlight = None

        if len(self.SearchResults) > 0:
            if self.CurrentFindHighlight is not None:
                old_idx = self.SearchResults.index(self.CurrentFindHighlight)
                if self.SearchParams["wrap"]:
                    idx = (old_idx + direction) % len(self.SearchResults)
                else:
                    idx = max(0, min(old_idx + direction, len(self.SearchResults) - 1))
                if idx != old_idx:
                    self.RemoveHighlight(*self.CurrentFindHighlight)
                    self.CurrentFindHighlight = self.SearchResults[idx]
                    self.AddHighlight(*self.CurrentFindHighlight)
            else:
                self.CurrentFindHighlight = self.SearchResults[0]
                self.AddHighlight(*self.CurrentFindHighlight)

        else:
            if self.CurrentFindHighlight is not None:
                self.RemoveHighlight(*self.CurrentFindHighlight)
            self.CurrentFindHighlight = None

    def RefreshModel(self):
        self.RefreshJumpList()
        self.Colourise(0, -1)
        self.Controler.SetEditedElementText(self.TagName, self.GetText())
        self.ResetSearchResults()

    def OnKeyDown(self, event):
        key = event.GetKeyCode()
        if self.Controler is not None:

            if self.Editor.CallTipActive():
                self.Editor.CallTipCancel()

            key_handled = False

            line = self.Editor.GetCurrentLine()
            if line == 0:
                start_pos = 0
            else:
                start_pos = self.Editor.GetLineEndPosition(line - 1) + 1
            end_pos = self.GetCurrentPos()
            lineText = self.Editor.GetTextRange(start_pos, end_pos).replace("\t", " ")

            # Code completion
            if key == wx.WXK_SPACE and event.ControlDown():

                words = lineText.split(" ")
                words = [word for i, word in enumerate(words) if word != '' or i == len(words) - 1]

                kw = []

                if self.TextSyntax == "IL":
                    if len(words) == 1:
                        kw = self.Keywords
                    elif len(words) == 2:
                        if words[0].upper() in ["CAL", "CALC", "CALNC"]:
                            kw = self.Functions
                        elif words[0].upper() in ["JMP", "JMPC", "JMPNC"]:
                            kw = self.Jumps
                        else:
                            kw = self.Variables.keys()
                else:
                    kw = self.Keywords + self.Variables.keys() + self.Functions.keys()
                if len(kw) > 0:
                    if len(words[-1]) > 0:
                        kw = [keyword for keyword in kw if keyword.startswith(words[-1])]
                    kw.sort()
                    self.Editor.AutoCompSetIgnoreCase(True)
                    self.Editor.AutoCompShow(len(words[-1]), " ".join(kw))
                key_handled = True
            elif key == wx.WXK_RETURN or key == wx.WXK_NUMPAD_ENTER:
                if self.TextSyntax in ["ST", "ALL"]:
                    indent = self.Editor.GetLineIndentation(line)
                    if LineStartswith(lineText.strip(), self.BlockStartKeywords):
                        indent = (indent // 2 + 1) * 2
                    self.Editor.AddText("\n" + " " * indent)
                    key_handled = True
            elif key == wx.WXK_BACK:
                if self.TextSyntax in ["ST", "ALL"]:
                    if not self.Editor.GetSelectedText():
                        indent = self.Editor.GetColumn(self.Editor.GetCurrentPos())
                        if lineText.strip() == "" and len(lineText) > 0 and indent > 0:
                            self.Editor.DelLineLeft()
                            self.Editor.AddText(" " * ((max(0, indent - 1) // 2) * 2))
                            key_handled = True
            if not key_handled:
                event.Skip()
        else:
            event.Skip()

    def OnKillFocus(self, event):
        self.Editor.AutoCompCancel()
        event.Skip()

    # -------------------------------------------------------------------------------
    #                        Highlights showing functions
    # -------------------------------------------------------------------------------

    def OnRefreshHighlightsTimer(self, event):
        self.RefreshView()
        event.Skip()

    def ClearHighlights(self, highlight_type=None):
        EditorPanel.ClearHighlights(self, highlight_type)

        if highlight_type is None:
            self.Highlights = []
        else:
            highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None)
            if highlight_type is not None:
                self.Highlights = [(infos, start, end, highlight) for (infos, start, end, highlight) in self.Highlights if highlight != highlight_type]
        self.RefreshView()

    def AddHighlight(self, infos, start, end, highlight_type):
        EditorPanel.AddHighlight(self, infos, start, end, highlight_type)

        highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None)
        if infos[0] == "body" and highlight_type is not None:
            self.Highlights.append((infos[1], start, end, highlight_type))
            self.Editor.GotoPos(self.Editor.PositionFromLine(start[0]) + start[1])
            self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)

    def RemoveHighlight(self, infos, start, end, highlight_type):
        EditorPanel.RemoveHighlight(self, infos, start, end, highlight_type)

        highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None)
        if infos[0] == "body" and highlight_type is not None and \
           (infos[1], start, end, highlight_type) in self.Highlights:
            self.Highlights.remove((infos[1], start, end, highlight_type))
            self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)

    def ShowHighlights(self, start_pos, end_pos):
        for indent, start, end, highlight_type in self.Highlights:
            if start[0] == 0:
                highlight_start_pos = start[1] - indent
            else:
                highlight_start_pos = self.Editor.GetLineEndPosition(start[0] - 1) + start[1] - indent + 1
            if end[0] == 0:
                highlight_end_pos = end[1] - indent + 1
            else:
                highlight_end_pos = self.Editor.GetLineEndPosition(end[0] - 1) + end[1] - indent + 2
            if highlight_start_pos < end_pos and highlight_end_pos > start_pos:
                self.StartStyling(highlight_start_pos, 0xff)
                self.SetStyling(highlight_end_pos - highlight_start_pos, highlight_type)
                self.StartStyling(highlight_start_pos, 0x00)
                until_end = max(0, len(self.Editor.GetText()) - highlight_end_pos)
                self.SetStyling(until_end, wx.stc.STC_STYLE_DEFAULT)


import logging
from ..conversions.types import decode_dict
from . import messages
from .. import settings

logger = logging.getLogger(__name__)

READS_QUEUES = ("os2ds_representations",)
WRITES_QUEUES = (
    "os2ds_handles",
    "os2ds_matches",
    "os2ds_checkups",
    "os2ds_conversions",)
PROMETHEUS_DESCRIPTION = "Representations examined"
PREFETCH_COUNT = 8

def message_received_raw(body, channel, source_manager):  # noqa: CCR001,E501 too high cognitive complexity
    message = messages.RepresentationMessage.from_json_object(body)
    representations = decode_dict(message.representations)
    rule = message.progress.rule
    logger.debug(f"{message.handle} with rules [{rule.presentation}] "
                 f"and representation [{list(representations.keys())}]")

    try:
        # Keep executing rules for as long as we can with the representations
        # we have
        conclusion, new_matches = rule.try_match(
                representations,
                obj_limit=max(1, settings.pipeline["matcher"]["obj_limit"]))
    except Exception as e:
        exception_message = "Matching error"
        exception_message += ". {0}: ".format(type(e).__name__)
        exception_message += ", ".join([str(a) for a in e.args])
        logger.warning(exception_message)
        for problems_q in ("os2ds_problems", "os2ds_checkups",):
            yield (problems_q, messages.ProblemMessage(
                    scan_tag=message.scan_spec.scan_tag,
                    source=None, handle=message.handle,
                    message=exception_message).to_json_object())
        return

    final_matches = message.progress.matches + [
            messages.MatchFragment(rule, matches or None)
            for rule, matches in new_matches]

    if isinstance(conclusion, bool):
        # We've come to a conclusion!

        logger.info(
                f"{message.handle} done."
                f" Matched status: {conclusion}")

        for matches_q in ("os2ds_matches", "os2ds_checkups",):
            yield (matches_q,
                   messages.MatchesMessage(
                       message.scan_spec, message.handle,
                       matched=conclusion,
                       matches=final_matches).to_json_object())

        # Only trigger metadata scanning if the match succeeded
        if conclusion:
            yield ("os2ds_handles",
                   messages.HandleMessage(
                            message.scan_spec.scan_tag,
                            message.handle).to_json_object())
    else:
        new_rep = conclusion.split()[0].operates_on
        # We need a new representation to continue
        logger.debug(
                f"{message.handle} needs"
                f" new representation: [{new_rep}].")
        yield ("os2ds_conversions",
               messages.ConversionMessage(
                            message.scan_spec, message.handle,
                            message.progress._replace(
                                    rule=conclusion,
                                    matches=final_matches)).to_json_object())

if __name__ == "__main__":
    from .run_stage import _compatibility_main  # noqa
    _compatibility_main("matcher")