# -*- coding: utf-8 -*-
"""
Created on 2018-03-01
@author: sun
Project:云推送-新增渠道模版（短信）
"""
import sys
import time
from selenium.webdriver.support import expected_conditions as EC
from Constant.Constant_Path import *
from Eslink_Case.Test_etbc_qa_push.Push_Message_Send.etbc_qa_push_message import *
from Utils.Getcsv_readline import csv_search
from Utils.ScreenShot import Screenshot
from Utils.Sys_Prompt import is_Sys_Prompt
from Utils.pull_down_list import is_pull_down_list
from Utils.test_db import MySQL

def is_channel_template(self):
        u"""渠道模板菜单"""
        try:
            puth_title=u"渠道模板"
            locator_title=("id","menuitem-1158-itemEl")
            is_push_message = EC.text_to_be_present_in_element(locator_title,puth_title)(self.browser)
            self.assertTrue(is_push_message)
            logger_message.loginfo(u"%s\t方法名：%s\t渠道模板 %s" % (send_time,sys._getframe().f_code.co_name,is_push_message))
            self.browser.find_element_by_id("menuitem-1158-itemEl").click()
            self.browser.implicitly_wait(10)
        except Exception as is_channel_template_msg:
            Screenshot(self,u'渠道模板异常')
            print(u"%s\t方法名：%s\t渠道模板异常%s" % (send_time,sys._getframe().f_code.co_name,is_channel_template_msg))
            logger_message.logwarning(u"%s\t方法名：%s\t渠道模板异常%s" % (send_time,sys._getframe().f_code.co_name,is_channel_template_msg))

def is_add_channel_template(self):
        u'''添加csv文件新增渠道模版'''
        try:
            template_message=csv_search.csv_test(filename=Push_Template_path().push_template,indexs=3)
            time.sleep(0.5)
            self.browser.implicitly_wait(10)
            self.browser.find_element_by_xpath('.//*[@id="add"]').click()
            self.browser.implicitly_wait(5)
            self.browser._switch_to.default_content()
            self.browser.switch_to.frame(self.browser.find_element_by_tag_name("iframe"))
            time.sleep(0.5)
            self.browser.switch_to.frame(self.browser.find_element_by_id("layui-layer-iframe2"))
            self.browser.find_element_by_xpath('//*[@id="name"]').send_keys(template_message[1])     #模版名称：Name
            self.browser.implicitly_wait(5)
            self.browser.find_element_by_xpath('//*[@id="%s"]'%template_message[2]).click()          #模版状态：State,tmp-disable:禁用,tmp-enable:启用
            self.browser.implicitly_wait(5)
            self.browser.find_element_by_xpath('//*[@data-id="channelId"]').click()
            self.browser.implicitly_wait(5)
            is_pull_down_list(self,template_message[3],".//*[@id='query-form']/div[3]/div/div/div/div/ul/li")  #渠道名称：ChannelId
            self.browser.implicitly_wait(5)
            self.browser.find_element_by_xpath('.//*[@id="code"]').send_keys(template_message[5])     #模版编号:Code
            self.browser.implicitly_wait(5)
            self.browser.find_element_by_xpath('.//*[@id="content"]').send_keys(template_message[6])  #模版内容:Content
            self.browser.implicitly_wait(5)
            # self.browser.find_element_by_xpath('.//*[@id="escapeContent"]').send_keys(template_message[7])  #转义模版:EscapeContent
            # logger_message.loginfo('\n%s\n新增模版名称：%s\n模版状态：%s\n渠道名称：%s\n模版编号:%s\n模版内容：%s\n转义模版：%s'%
            #       (send_time,template_message[1],template_message[2],template_message[3],template_message[5],template_message[6],template_message[7]))

            self.browser.implicitly_wait(5)
            self.browser.find_element_by_xpath('.//*[@id="btn-add"]').click()
            is_Sys_Prompt(self)
        except Exception as is_add_channel_template_error:
            Screenshot(self,u'添加csv文件新增短信渠道模版-异常')
            print(u'%s\t方法名：%s\t添加csv文件新增短信渠道模版-异常：%s' % (send_time,sys._getframe().f_code.co_name,is_add_channel_template_error))
            logger_message.logwarning(u'%s\t方法名：%s\t添加csv文件新增短信渠道模版-异常：%s' % (send_time,sys._getframe().f_code.co_name,is_add_channel_template_error))
            raise

def is_check_messageTemplate(self):
    u'''确认是否存在短信模版'''
    try:
        template_message=csv_search.csv_test(filename=Push_Template_path().push_template,indexs=2)
        time.sleep(0.5)
        database=MySQL()
        template_code = template_message[5]
        template_name=template_message[1]
        sql="Select * FROM push_channelmessagetemplate WHERE `code` = '%s' AND name = '%s';" % (template_code,template_name)
        print(sql)
        logger_message.loginfo(u"%s\t方法名：%s\t模版名称：%s\t模版编号：%s"%(send_time,template_name,template_code))
        result=database.query(sql)
        print(result)
        if len(result) == 1:
            print('存在模版:%s'%template_name)
            logger_message.loginfo(u"%s\t方法名：%s模版信息：%s"%(send_time,sys._getframe().f_code.co_name,result))
            sql="DELETE FROM push_channelmessagetemplate WHERE `code` = '%s';" % template_code
            database.query(sql)
        else:
            print('不存在模版:%s'%template_name)
            logger_message.loginfo(u"%s\t方法名：%s模版信息：%s"%(send_time,sys._getframe().f_code.co_name,result))

    except Exception as is_check_template_Error:
        Screenshot(self,u'模版查询异常')
        logger_message.loginfo(u"%s\t方法名：%s\t模版查询异常：%s"%(send_time,sys._getframe().f_code.co_name,is_check_template_Error))
        logger_message.loginfo(u"%s\t方法名：%s\t模版查询异常：%s"%(send_time,sys._getframe().f_code.co_name,is_check_template_Error))
        raise


import websockets
import json
import asyncio
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from base64 import b64decode
from multiprocessing import *
from Logger import *
import traceback

clearConsole = lambda: os.system('cls' if os.name in ('nt', 'dos') else 'clear')

def get_key(motoo: bool):
    config = configparser.ConfigParser()
    config.read('config.ini', encoding='utf-8')

    if motoo == True: a = '모투'
    else: a = '실투'
    app_key = config[a]['app_key']
    secret_key = config[a]['secret_key']
    acc_num = config[a]['acc_num']
    id = config[a]['id']

    return app_key, secret_key, acc_num, id

def stockhoka(data):
    recvvalue = data.split('^')  # 수신데이터를 split '^'
    return dict(종목코드 = recvvalue[0], 예상체결가 = int(recvvalue[47]), 예상체결수량 = int(recvvalue[48]), 예상거래량 = int(recvvalue[49]), 매수호가01 = int(recvvalue[13]), 매수호가01잔량 = int(recvvalue[33]), 매도호가01 = int(recvvalue[3]), 매도호가01잔량 = int(recvvalue[23]), TRID = 'H0STASP0')

def stocks_purchase(data):
    menulist = "유가증권단축종목코드|주식체결시간|주식현재가|전일대비부호|전일대비|전일대비율|가중평균주식가격|주식시가|주식최고가|주식최저가|매도호가1|매수호가1|체결거래량|누적거래량|누적거래대금|매도체결건수|매수체결건수|순매수체결건수|체결강도|총매도수량|총매수수량|체결구분|매수비율|전일거래량대비등락율|시가시간|시가대비구분|시가대비|최고가시간|고가대비구분|고가대비|최저가시간|저가대비구분|저가대비|영업일자|신장운영구분코드|거래정지여부|매도호가잔량|매수호가잔량|총매도호가잔량|총매수호가잔량|거래량회전율|전일동시간누적거래량|전일동시간누적거래량비율|시간구분코드|임의종료구분코드|정적VI발동기준가"
    menustr = menulist.split('|')
    pValue = data.split('^')
    data_list = {}
    for i in range(len(menustr)):     # 넘겨받은 체결데이터 개수만큼 print 한다
        data_list.update({menustr[i] : pValue[i]})
    return data_list

def aes_cbc_base64_dec(key, iv, cipher_text):
    """
    :param key:  str type AES256 secret key value
    :param iv: str type AES256 Initialize Vector
    :param cipher_text: Base64 encoded AES256 str
    :return: Base64-AES256 decodec str
    """
    try:
        try:
            cipher = AES.new(key.encode('cp949'), AES.MODE_CBC, iv.encode('cp949'))
            return bytes.decode(unpad(cipher.decrypt(b64decode(cipher_text)), AES.block_size))
        except:
            cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
            result = bytes.decode(unpad(cipher.decrypt(b64decode(cipher_text)), AES.block_size), 'utf-8',
                                  errors='replace')
            result = result.replace('\ufffd', '')
            return result

    except Exception as e:
        print(e)
        print(traceback.format_exc())
        Logger().add_log('', 'error')
        Logger().telegram_bot('복호화 과정에서 에러발생')

def get_approval(key, secret):
    """웹소켓 접속키 발급"""
    url = 'https://openapi.koreainvestment.com:9443'
    headers = {"content-type": "application/json"}
    body = {"grant_type": "client_credentials",
            "appkey": key,
            "secretkey": secret}
    PATH = "oauth2/Approval"
    URL = f"{url}/{PATH}"
    res = requests.post(URL, headers=headers, data=json.dumps(body))
    approval_key = res.json()["approval_key"]
    return approval_key

def OrderExecData(data, key, iv):
    # AES256 처리 단계

    aes_dec_str = aes_cbc_base64_dec(key, iv, data)
    pValue = aes_dec_str.split('^')

    if pValue[13] == '2':  # 체결통보
        print("#### 국내주식 체결 통보 ####")
        menulist = "고객ID|계좌번호|주문번호|원주문번호|매도매수구분|정정구분|주문종류|주문조건|주식단축종목코드|체결수량|체결단가|주식체결시간|거부여부|체결여부|접수여부|지점번호|주문수량|계좌명|체결종목명|신용구분|신용대출일자|체결종목명40|주문가격"
        menustr1 = menulist.split('|')
    else:
        print("#### 국내주식 주문·정정·취소·거부 접수 통보 ####")
        menulist = "고객ID|계좌번호|주문번호|원주문번호|매도매수구분|정정구분|주문종류|주문조건|주식단축종목코드|주문수량|주문가격|주식체결시간|거부여부|체결여부|접수여부|지점번호|주문수량|계좌명|주문종목명|신용구분|신용대출일자|체결종목명40|체결단가"
        menustr1 = menulist.split('|')

    data_list = {}
    min_len = min(len(pValue), len(menustr1))  #### pValue 갯수가 일정하게 들어오지 않음, 어떤때는 22개, 어떤때는 25개가 날라옴
    for i in range(min_len):  ### 그래서 pvalue와 mennustr1 갯수 중에서 작은 값을 for문 돌림
        data_list.update({menustr1[i]: pValue[i]})
    return data_list

class Receiver:
    def __init__(self,TotalSubStocks, stg_option, Qlist, managerList, account_data):

        self.app_key = account_data[0]
        self.secret_key = account_data[1]
        self.acc_num = account_data[2]
        self.id = account_data[3]
        self.motoo = account_data[4]

        self.PriceQ = Qlist[0]
        self.OrderQ = Qlist[1]
        self.OrderCheckQ = Qlist[2]
        self.ExecQ = Qlist[3]
        self.WindowQ = Qlist[4]

        self.BuyList = managerList[0]
        self.PriceManger = managerList[1]
        self.OrderManager = managerList[2]
        self.ExecManager = managerList[3]
        self.PositionManager = managerList[4]
        self.BalanceManager = managerList[5]
        self.TradingManager = managerList[6]
        self.subsStocks = TotalSubStocks

        # self.stg_name = stg_option['전략명']
        self.logger = Logger()
        self.PriceExecChecker()

    async def PriceExecWebsocket(self):

        if self.motoo == True:
            url = 'ws://ops.koreainvestment.com:31000'  # 모의계좌
            tr_id = 'H0STCNI9'
        else:
            url = 'ws://ops.koreainvestment.com:21000'  # 실전계좌
            tr_id = 'H0STCNI0'

        approval_key = get_approval(self.app_key, self.secret_key)

        code_list = [['1', 'H0STCNT0', x] for x in self.subsStocks]
        code_list2 = [['1', 'H0STASP0', x] for x in self.subsStocks]

        send_data_list = []
        for i, j, k in code_list:
            temp = '{"header":{"approval_key": "%s","custtype":"%s","tr_type":"%s","content-type":"utf-8"},"body":{"input":{"tr_id":"%s","tr_key":"%s"}}}' % (approval_key, 'P', i, j, k)
            send_data_list.append(temp)

        for i, j, k in code_list2:
            temp = '{"header":{"approval_key": "%s","custtype":"%s","tr_type":"%s","content-type":"utf-8"},"body":{"input":{"tr_id":"%s","tr_key":"%s"}}}' % (approval_key, 'P', i, j, k)
            send_data_list.append(temp)

        code_list = ['1', tr_id, self.id]
        temp = '{"header":{"approval_key": "%s","custtype":"P","tr_type":"%s","content-type":"utf-8"},"body":{"input":{"tr_id":"%s","tr_key":"%s"}}}' % (
            approval_key, code_list[0], code_list[1], code_list[2])
        send_data_list.append(temp)

        async with websockets.connect(url, ping_interval = None) as websocket:
            for send_data in send_data_list:
                await websocket.send(send_data)

            print('\n======================== Receiver Start ========================\n')

            while True:
                if not websocket.open:
                    try:
                        websocket = await websocket.connect(url)
                        for send_data in send_data_list:
                            await websocket.send(send_data)
                    except:
                        print('웹소켓 재연결 시도중 ...')

                data = await websocket.recv()

                if data[0] == '0':
                    recvstr = data.split('|')
                    trid0 = recvstr[1]

                    if trid0 == 'H0STASP0':
                        result = stockhoka(recvstr[3])
                        self.PriceQ.put(result)

                    elif trid0 == 'H0STCNT0':
                        resp = stocks_purchase(recvstr[3])
                        stock_code = resp['유가증권단축종목코드']
                        dayopen = int(resp['주식시가'])
                        dayhigh = int(resp['주식최고가'])
                        daylow = int(resp['주식최저가'])
                        dayclose = int(resp['주식현재가'])
                        dayvolume = int(resp['누적거래량'])
                        dayamount = int(resp['누적거래대금'])
                        buy_hoka1 = int(resp['매수호가1'])
                        sell_hoka1 = int(resp['매도호가1'])

                        result = dict(종목코드 = stock_code, 당일시가 = dayopen, 당일고가 = dayhigh, 당일저가 = daylow, 현재가 = dayclose,
                                  당일누적거래량 = dayvolume, 당일누적거래대금 = dayamount, 매수호가1 = buy_hoka1, 매도호가1 = sell_hoka1, TRID = 'H0STCNT0')

                        self.PriceQ.put(result)

                elif data[0] == '1':
                    recvstr = data.split('|')  # 수신데이터가 실데이터 이전은 '|'로 나뉘어져있어 split
                    trid0 = recvstr[1]
                    if trid0 == "K0STCNI0" or trid0 == "K0STCNI9" or trid0 == "H0STCNI0" or trid0 == "H0STCNI9":
                        resp = OrderExecData(recvstr[3], aes_key, aes_iv)
                        self.ExecQ.put(resp)

                else:
                    jsonObject = json.loads(data)
                    trid = jsonObject["header"]["tr_id"]

                    if trid != "PINGPONG":
                        rt_cd = jsonObject["body"]["rt_cd"]
                        if rt_cd == '1':  # 에러일 경우 처리
                            print("### 현재가 ERROR RETURN CODE [ %s ] MSG [ %s ]" % (rt_cd, jsonObject["body"]["msg1"]))
                            pass
                        elif rt_cd == '0':  # 정상일 경우 처리
                            print("### 현재가 RETURN CODE [ %s ] MSG [ %s ]" % (rt_cd, jsonObject["body"]["msg1"]))
                            # 체결통보 처리를 위한 AES256 KEY, IV 처리 단계
                            if trid == "K0STCNI0" or trid == "K0STCNI9" or trid == "H0STCNI0" or trid == "H0STCNI9":
                                aes_key = jsonObject["body"]["output"]["key"]
                                aes_iv = jsonObject["body"]["output"]["iv"]
                                print("### TRID [%s] KEY[%s] IV[%s]" % (trid, aes_key, aes_iv))

                    elif trid == "PINGPONG":
                        print("### RECV [PINGPONG] [%s]" % (data))
                        await websocket.send(data)
                        print("### SEND [PINGPONG] [%s]" % (data))

    def PriceExecChecker(self):
        my_loop = asyncio.get_event_loop()
        my_loop.run_until_complete(self.PriceExecWebsocket())
        my_loop.close()

if __name__ == '__main__':
    PriceQ, OrderQ, OrderCheckQ, ExecCheckQ, WindowQ = \
        Queue(), Queue(), Queue(), Queue(), Queue()

    BuyList, PriceManger, OrderManager, ExecManager, PositionManager, BalanceManager, TradingManager = \
        Manager().list(), Manager().dict(), Manager().dict(), Manager().dict(), Manager().dict(), Manager().dict(), Manager().dict()

    qlist = [PriceQ, OrderQ, OrderCheckQ, ExecCheckQ, WindowQ]
    managerlist = [BuyList, PriceManger, OrderManager, ExecManager, PositionManager, BalanceManager, TradingManager]

    motoo = True
    app_key, secret_key, acc_num, id = get_key(motoo)
    print(app_key)
    print(secret_key)
    account_data = [app_key, secret_key, acc_num, id, motoo]
    strategy_name = '테스트'

    subStocks = ['122630', '233740']
    stg_option = None
    Receiver(subStocks, stg_option, qlist, managerlist, account_data)


from .db import db, environment, SCHEMA, add_prefix_for_prod
from sqlalchemy.sql import func
from sqlalchemy.orm import validates

class WorkspaceInvitation(db.Model):
    __tablename__ = 'workspace_invitations'

    if environment == "production":
        __table_args__ = {'schema': SCHEMA}

    id = db.Column(
      db.Integer,
      primary_key=True
    )
    sender_id = db.Column(
      db.Integer,
      db.ForeignKey(add_prefix_for_prod("users.id")),
      nullable=False
    )
    recipient_id = db.Column(
      db.Integer,
      db.ForeignKey(add_prefix_for_prod("users.id")),
      nullable=False
    )
    workspace_id = db.Column(
      db.Integer,
      db.ForeignKey(add_prefix_for_prod("workspaces.id")),
      nullable=False
    )
    status = db.Column(
      db.String(30),
      default="pending",
      nullable=False
    )
    created_at = db.Column(
      db.DateTime,
      nullable=False,
      default=func.now()
    )

    sender = db.relationship(
      "User",
      foreign_keys="WorkspaceInvitation.sender_id",
      back_populates="sent_workspace_invitations"
    )
    recipient = db.relationship(
      "User",
      foreign_keys="WorkspaceInvitation.recipient_id",
      back_populates="received_workspace_invitations"
    )
    workspace = db.relationship(
      "Workspace",
      foreign_keys="WorkspaceInvitation.workspace_id",
      back_populates="associated_invitations"
    )

    recipient_id_index = db.Index(
      'ix_workspace_invitations_recipient_id',
      recipient_id
    )
    sender_id_index = db.Index(
      'ix_workspace_invitations_sender_id',
      sender_id
    )
    created_at_index = db.Index(
      'ix_workspace_invitations_created_at',
      created_at
    )

    @validates("status")
    def validate_role(self, key, value):
      if value != "pending" and value != "accepted" and value != "ignored":
        raise ValueError("Status must be 'pending', 'accepted', or 'ignored'")
      return value

    def to_dict(self):
      return {
        'id': self.id,
        'senderEmail': self.sender.email,
        'recipientEmail': self.recipient.email,
        'workspaceId': self.workspace_id,
        'workspaceName': self.workspace.name,
        'status': self.status,
        'createdAt': self.created_at
      }


import pyaudio
import keyboard
import tempfile
import wave
from openai import OpenAI
from dotenv import load_dotenv
import os

# Parameters for recording
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
CHUNK = 1024
HOTKEY_START = "ctrl+alt+l"
HOTKEY_STOP = "ctrl+alt+s"
load_dotenv()
client = OpenAI()

def start_recording():
    audio = pyaudio.PyAudio()

    recorded_data = None  # This will store the audio data

    while True:
        if keyboard.is_pressed(HOTKEY_START):
            print("Recording started...")
            stream = audio.open(format=FORMAT, channels=CHANNELS,
                                rate=RATE, input=True,
                                frames_per_buffer=CHUNK)
            frames = []

            # Keep recording until 's' is pressed
            while not keyboard.is_pressed(HOTKEY_STOP):
                data = stream.read(CHUNK)
                frames.append(data)

            print("Recording stopped.")

            # Stop and close the stream
            stream.stop_stream()
            stream.close()
            # Terminate the PortAudio interface
            audio.terminate()

            # Store the audio data in the recorded_data variable
            recorded_data = b''.join(frames)
            break

    # Generate a unique filename for the temporary WAV file
    temp_filename = tempfile.mktemp(suffix=".wav")

    # Save the audio data to the temporary WAV file
    with wave.open(temp_filename, 'wb') as wf:
        wf.setnchannels(CHANNELS)
        wf.setsampwidth(pyaudio.get_sample_size(FORMAT))
        wf.setframerate(RATE)
        wf.writeframes(recorded_data)

    # Re-open the temporary file in binary read mode for transcription
    with open(temp_filename, 'rb') as f:
        response = client.audio.transcriptions.create(
            model="whisper-1",
            file=f,
            response_format='json'
        )

    # Clean up by removing the temporary file
    os.remove(temp_filename)

    return response.text


'''
Created on 08.11.2012

@author: himikof
'''
import unittest
import struct

from nfw.protocol import StatefulProtocol

from twisted.internet.defer import inlineCallbacks

class MockProtocol(StatefulProtocol):
    @inlineCallbacks
    def stateMachine(self):
        self.cmd = yield self.readInt32()
        self.str = yield self.readString()

    def protocolError(self, failure):
        raise failure

class TestProtocol(unittest.TestCase):

    def setUp(self):
        self.p = MockProtocol()

    def tearDown(self):
        del self.p

    def testRead(self):
        d1 = self.p.readBytes(4)
        d2 = self.p.readUnpacked('3s')
        self.assertFalse(d1.called)
        self.assertFalse(d2.called)
        self.p.dataReceived(b'1234567')
        self.assertTrue(d1.called)
        self.assertEqual(d1.result, b'1234')
        self.assertTrue(d2.called)
        self.assertEqual(d2.result, ('567',))

    def testSM(self):
        teststr = u'\u041f\u0440\u0438\u0432\u0435\u0442!'
        encoded = teststr.encode('utf8')
        self.p.dataReceived(struct.pack('!I', 42))
        self.p.dataReceived(struct.pack('!I', len(encoded)) + encoded)
        self.assertEqual(self.p.cmd, 42)
        self.assertEqual(self.p.str, teststr)

if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()


'''
Agent behavior tied to an ExtensiveGameModel and plays the subgame-perfect
equilibrium.
'''
from consul.event_log import EventLog
import random

class SPESolver(object):
    '''
    Find the subgame-perfect equilibrium for a given extensive-form game.
    '''

    node_payoffs = {}
    best_moves = {}
    node_to_agent = {}

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

    def find_spe(self, model, current_node=None, player_index=0):
        '''
        Recursively identify the SPE of a given game tree.

        Args:
            model: The ExtensiveGameModel being played.
            current_node: The name of the current node.
            player_index: The index of the player playing the current node.
        '''
        next_moves = model.tree[current_node].children
        move_payoffs = {}
        for move, child in next_moves.items():
            if model.tree[child].final:
                self.node_payoffs[child] = model.utilities[child]
            else:
                next_player = (player_index + 1) % len(model.agents)
                self.find_spe(model, child, next_player)
            move_payoffs[move] = self.node_payoffs[child]

        agent_name = model.agents[player_index].name
        self.node_to_agent[current_node] = agent_name
        best_move = max(move_payoffs,
            key=lambda x: move_payoffs[x][agent_name])
        self.best_moves[current_node] = best_move
        self.node_payoffs[current_node] = move_payoffs[best_move]

    def make_log(self, model, log=None, current_node=None, step=0):
        '''
        Generate a notional event log for all possible SPE moves.
        '''
        top_level = False
        if log is None:
            log = EventLog()
            top_level = True
        if current_node is None:
            current_node = model.tree.root_node
        if self.best_moves == {}:
            self.find_spe(model, current_node, 0)

        current_player = self.node_to_agent[current_node]
        best_move = self.best_moves[current_node]
        log.add_event(current_player, None, step, best_move)

        for child in model.tree[current_node].children.values():
            if not model.tree[child].final:
                self.make_log(model, log, child, step+1)

        if top_level:
            return log

class SPEAgent(SPESolver):
    '''
    Given an extensive-form game, play the subgame-perfect equilibrium.

    Specifically, given an ExtensiveGameModel, plays the subgame-perfect
    equilibrium.

    Like other ConSUL behaviors, it needs to be extended with another model
    to work.
    '''

    def __init__(self, *args, **kwargs):
        self.best_moves = {}
        self.node_payoffs = {}
        super().__init__(*args, **kwargs)

    def step(self, model):
        '''
        Choose the SPE next move.
        '''
        if not model.current_node in self.best_moves:
            index = model.agents.index(self)
            self.find_spe(model, model.current_node, index)
        return self.best_moves[model.current_node]

class NashEquilibriumAgent(object):
    '''
    Given a normal-form game, play the Nash Equilibrium.
    '''

    def step(self, model):
        '''
        Choose the equilibrium move from a NormalGameModel object.
        '''
        # Get my index
        for i, agent in enumerate(model.agents):
            if agent == self:
                break

        equilibria = model.find_equilibria()
        equilibrium = random.choice(equilibria)
        return equilibrium[i]

    def add_utility(self, utility):
        pass


from __future__ import print_function
from __future__ import absolute_import
from __future__ import division

from compas.geometry import distance_point_point_xy
from compas.geometry import distance_point_line_xy
from compas.geometry import closest_point_on_segment_xy

def is_ccw_xy(a, b, c, colinear=False):
    """Determine if c is on the left of ab when looking from a to b,
    and assuming that all points lie in the XY plane.

    Parameters
    ----------
    a : [float, float, float] | :class:`~compas.geometry.Point`
        Base point defined by XY(Z) coordinates.
    b : [float, float, float] | :class:`~compas.geometry.Point`
        First end point defined by XY(Z) coordinates.
    c : [float, float, float] | :class:`~compas.geometry.Point`
        Second end point defined by XY(Z) coordinates.
    colinear : bool, optional
        If True, colinear points will return a positive result.

    Returns
    -------
    bool
        True if ccw.
        False otherwise.

    References
    ----------
    For more info, see [1]_.

    .. [1] Marsh, C. *Computational Geometry in Python: From Theory to Application*.
           Available at: https://www.toptal.com/python/computational-geometry-in-python-from-theory-to-implementation

    Examples
    --------
    >>> print(is_ccw_xy([0,0,0], [0,1,0], [-1, 0, 0]))
    True

    >>> print(is_ccw_xy([0,0,0], [0,1,0], [+1, 0, 0]))
    False

    >>> print(is_ccw_xy([0,0,0], [1,0,0], [2,0,0]))
    False

    >>> print(is_ccw_xy([0,0,0], [1,0,0], [2,0,0], True))
    True

    """
    ab_x = b[0] - a[0]
    ab_y = b[1] - a[1]
    ac_x = c[0] - a[0]
    ac_y = c[1] - a[1]
    if colinear:
        return ab_x * ac_y - ab_y * ac_x >= 0
    return ab_x * ac_y - ab_y * ac_x > 0

def is_colinear_xy(a, b, c):
    """Determine if three points are colinear on the XY-plane.

    Parameters
    ----------
    a : [float, float, float] | :class:`~compas.geometry.Point`
        Point 1 defined by XY(Z) coordinates.
    b : [float, float, float] | :class:`~compas.geometry.Point`
        Point 2 defined by XY(Z) coordinates.
    c : [float, float, float] | :class:`~compas.geometry.Point`
        Point 3 defined by XY(Z) coordinates.

    Returns
    -------
    bool
        True if the points are colinear.
        False otherwise.

    """
    ab_x = b[0] - a[0]
    ab_y = b[1] - a[1]
    ac_x = c[0] - a[0]
    ac_y = c[1] - a[1]
    return ab_x * ac_y == ab_y * ac_x

def is_polygon_convex_xy(polygon, colinear=False):
    """Determine if the polygon is convex on the XY-plane.

    Parameters
    ----------
    polygon : sequence[point] | :class:`~compas.geometry.Polygon`
        The XY(Z) coordinates of the corners of a polygon.
        The vertices are assumed to be in order.
        The polygon is assumed to be closed: the first and last vertex in the sequence should not be the same.
    colinear : bool, optional
        Are points allowed to be colinear?

    Returns
    -------
    bool
        True if the polygon is convex.
        False otherwise.

    """
    a = polygon[-2]
    b = polygon[-1]
    c = polygon[0]
    direction = is_ccw_xy(a, b, c, colinear)
    for i in range(-1, len(polygon) - 2):
        a = b
        b = c
        c = polygon[i + 2]
        if direction != is_ccw_xy(a, b, c, colinear):
            return False
    return True

def is_point_on_line_xy(point, line, tol=1e-6):
    """Determine if a point lies on a line on the XY-plane.

    Parameters
    ----------
    point : [float, float, float] | :class:`~compas.geometry.Point`
        XY(Z) coordinates of a point.
    line : [point, point] | :class:`~compas.geometry.Line`
        XY(Z) coordinates of two points defining a line.
    tol : float, optional
        A tolerance for membership verification.

    Returns
    -------
    bool
        True if the point is in on the line.
        False otherwise.

    """
    return distance_point_line_xy(point, line) <= tol

def is_point_on_segment_xy(point, segment, tol=1e-6):
    """Determine if a point lies on a given line segment on the XY-plane.

    Parameters
    ----------
    point : [float, float, float] | :class:`~compas.geometry.Point`
        XY(Z) coordinates of a point.
    segment : [point, point] | :class:`~compas.geometry.Line`
        XY(Z) coordinates of two points defining a segment.
    tol : float, optional
        A tolerance for membership verification.

    Returns
    -------
    bool
        True if the point is on the line segment.
        False otherwise.

    """
    a, b = segment

    if not is_point_on_line_xy(point, segment, tol=tol):
        return False

    d_ab = distance_point_point_xy(a, b)

    if d_ab == 0:
        return False

    d_pa = distance_point_point_xy(a, point)
    d_pb = distance_point_point_xy(b, point)

    if d_pa + d_pb <= d_ab + tol:
        return True

    return False

def is_point_on_polyline_xy(point, polyline, tol=1e-6):
    """Determine if a point is on a polyline on the XY-plane.

    Parameters
    ----------
    point : [float, float, float] | :class:`~compas.geometry.Point`
        XY(Z) coordinates.
    polyline : sequence[point] | :class:`~compas.geometry.Polyline`
        XY(Z) coordinates of the points of the polyline.
    tol : float, optional
        The tolerance for membership verification.

    Returns
    -------
    bool
        True if the point is on the polyline.
        False otherwise.

    """
    for i in range(len(polyline) - 1):
        a = polyline[i]
        b = polyline[i + 1]
        c = closest_point_on_segment_xy(point, (a, b))

        if distance_point_point_xy(point, c) <= tol:
            return True

    return False

def is_point_in_triangle_xy(point, triangle, colinear=False):
    """Determine if a point is in the interior of a triangle lying on the XY-plane.

    Parameters
    ----------
    point : [float, float, float] | :class:`~compas.geometry.Point`
        XY(Z) coordinates of a point.
    triangle : [point, point, point]
        XY(Z) coordinates of the corners of the triangle.
    colinear : bool, optional
        Allow points to be colinear.

    Returns
    -------
    bool
        True if the point is in the convex polygon.
        False otherwise.

    """
    a, b, c = triangle
    ccw = is_ccw_xy(c, a, point, colinear)

    if ccw != is_ccw_xy(a, b, point, colinear):
        return False

    if ccw != is_ccw_xy(b, c, point, colinear):
        return False

    return True

def is_point_in_convex_polygon_xy(point, polygon):
    """Determine if a point is in the interior of a convex polygon lying on the XY-plane.

    Parameters
    ----------
    point : [float, float, float] | :class:`~compas.geometry.Point`
        XY(Z) coordinates of a point (Z will be ignored).
    polygon : sequence[point] | :class:`~compas.geometry.Polygon`
        A sequence of XY(Z) coordinates of points representing the locations of the corners of a polygon (Z will be ignored).
        The vertices are assumed to be in order. The polygon is assumed to be closed:
        the first and last vertex in the sequence should not be the same.

    Returns
    -------
    bool
        True if the point is in the convex polygon
        False otherwise.

    Warnings
    --------
    Does not work for concave polygons.

    """
    ccw = None
    for i in range(-1, len(polygon) - 1):
        a = polygon[i]
        b = polygon[i + 1]
        if ccw is None:
            ccw = is_ccw_xy(a, b, point, True)
        else:
            if ccw != is_ccw_xy(a, b, point, True):
                return False
    return True

def is_point_in_polygon_xy(point, polygon):
    """Determine if a point is in the interior of a polygon lying on the XY-plane.

    Parameters
    ----------
    point : [float, float, float] | :class:`~compas.geometry.Point`
        XY(Z) coordinates of a point (Z will be ignored).
    polygon : sequence[point] | :class:`~compas.geometry.Polygon`
        A sequence of XY(Z) coordinates of points representing the locations of the corners of a polygon (Z will be ignored).
        The vertices are assumed to be in order.
        The polygon is assumed to be closed.
        The first and last vertex in the sequence should not be the same.

    Returns
    -------
    bool
        True if the point is in the polygon.
        False otherwise.

    Warnings
    --------
    A boundary check is not yet implemented. This should include a tolerance value.

    """
    x, y = point[0], point[1]
    polygon = [(p[0], p[1]) for p in polygon]  # make 2D
    inside = False
    for i in range(-1, len(polygon) - 1):
        x1, y1 = polygon[i]
        x2, y2 = polygon[i + 1]
        if y1 != y2:
            xinters = (y - y1) * (x2 - x1) / (y2 - y1) + x1
        else:
            xinters = None
        if y > min(y1, y2):
            if y <= max(y1, y2):
                if x <= max(x1, x2):
                    if x1 == x2 or (xinters is not None and x <= xinters):
                        inside = not inside
    return inside

def is_point_in_circle_xy(point, circle):
    """Determine if a point lies in a circle lying on the XY-plane.

    Parameters
    ----------
    point : [float, float, float] | :class:`~compas.geometry.Point`
        XY(Z) coordinates of a point (Z will be ignored).
    circle : [[point, vector], float] | :class:`~compas.geometry.Circle`
        Center and radius of the circle on the XY plane.

    Returns
    -------
    bool
        True if the point lies in the circle.
        False otherwise.

    """
    dis = distance_point_point_xy(point, circle[0][0])
    if dis <= circle[1]:
        return True
    return False

def is_polygon_in_polygon_xy(polygon1, polygon2):
    """Determine if a polygon is in the interior of another polygon on the XY-plane.

    Parameters
    ----------
    polygon1 : sequence[point] | :class:`~compas.geometry.Polygon`
        List of XY(Z) coordinates of points representing the locations of the corners of the exterior polygon (Z will be ignored).
        The vertices are assumed to be in order. The polygon is assumed to be closed:
        the first and last vertex in the sequence should not be the same.
    polygon2 : sequence[point] | :class:`~compas.geometry.Polygon`
        List of XY(Z) coordinates of points representing the locations of the corners of the interior polygon (Z will be ignored).
        The vertices are assumed to be in order. The polygon is assumed to be closed:
        the first and last vertex in the sequence should not be the same.

    Returns
    -------
    bool
        True if polygon2 is inside polygon1.
        False otherwise.

    """
    if is_polygon_convex_xy(polygon1) and is_polygon_convex_xy(polygon2):
        for pt in polygon2:
            if not is_point_in_convex_polygon_xy(pt, polygon1):
                return False
        return True
    else:
        for i in range(len(polygon1)):
            line = [polygon1[-i], polygon1[-i - 1]]
            for j in range(len(polygon2)):
                line_ = [polygon2[-j], polygon2[-j - 1]]
                if is_intersection_segment_segment_xy(line, line_):
                    return False
        for pt in polygon2:
            if is_point_in_polygon_xy(pt, polygon1):
                return True
        return False

def is_intersection_line_line_xy(l1, l2, tol=1e-6):
    """Verifies if two lines intersect on the XY-plane.

    Parameters
    ----------
    l1 : [point, point] | :class:`~compas.geometry.Line`
        XY(Z) coordinates of two points defining a line.
    l2 : [point, point] | :class:`~compas.geometry.Line`
        XY(Z) coordinates of two points defining a line.
    tol : float, optional
        A tolerance for intersection verification.

    Returns
    -------
    bool
        True if the lines intersect in one point
        False if the lines are skew, parallel or lie on top of each other.

    """
    raise NotImplementedError

def is_intersection_segment_segment_xy(ab, cd):
    """Determines if two segments, ab and cd, intersect.

    Parameters
    ----------
    ab : [point, point] | :class:`~compas.geometry.Line`
        Two points representing the start and end points of a segment.
        Z coordinates will be ignored.
    cd : [point, point] | :class:`~compas.geometry.Line`
        Two points representing the start and end points of a segment.
        Z coordinates will be ignored.

    Returns
    -------
    bool
        True if the segments intersect.
        False otherwise.

    Notes
    -----
    The segments intersect if both of the following conditions are true:

    * `c` is on the left of `ab`, and `d` is on the right, or vice versa.
    * `d` is on the left of `ac`, and on the right of `bc`, or vice versa.

    """
    a, b = ab
    c, d = cd
    return is_ccw_xy(a, c, d) != is_ccw_xy(b, c, d) and is_ccw_xy(a, b, c) != is_ccw_xy(a, b, d)


import numpy as np

from .base_graph import Graph
from riotwatcher import RiotWatcher
import matplotlib.pyplot as plt
from matplotlib import rcParams

class ChampionWinsGraph(Graph):
    def __init__(self, api_watcher, region, champion_json):
        super(ChampionWinsGraph, self).__init__(api_watcher, region)
        self.champion_json = champion_json

    def render(self, summoner_name="SamuelTheRandom", filepath="cw-summoner.png"):
        summoner = self.api_watcher.summoner.by_name(self.region, summoner_name)
        history = self.api_watcher.match.matchlist_by_account(self.region, summoner["accountId"], end_index=20) # Get the most recent 20 games played

        champ_match_dict = dict()
        for match in history["matches"]:
            champion_id_dict = self.champion_json["keys"]
            champion_name = champion_id_dict[str(match["champion"])] # Uses the champion id and retrieves the champions name

            if champion_name not in champ_match_dict:
                match_list = list()
            else:
                match_list = champ_match_dict[champion_name]

            match_list.append(match["gameId"])
            champ_match_dict[champion_name] = match_list

        dataset = dict()
        for champion in champ_match_dict:
            games_played = len(champ_match_dict[champion])
            games_won = 0

            for match_id in champ_match_dict[champion]:
                match = self.api_watcher.match.by_id(self.region, match_id)

                for participant in match["participants"]:
                    if self.champion_json["keys"][str(participant["championId"])] == champion:
                        team_id = participant["teamId"]

                for team in match["teams"]:
                    if team["teamId"] == team_id:
                        if team["win"] == "Win":
                            games_won+= 1

            dataset[champion] = (games_played, games_won)

        x = dataset.keys() # The x axis of champion names
        y1,y2 = zip(*dataset.values()) #Unpack the total games played, and games won

        ind = np.arange(len(x))
        width = 0.35

        fig, ax = plt.subplots(1)

        p1 = ax.bar(ind, y1, width, color='#d62728')
        p2 = ax.bar(ind, y2, width)

        plt.ylabel('Number of Games')
        plt.title('Champion wins over the past 20 games played for ' + summoner["name"])
        plt.xticks(ind, x)
        plt.yticks(np.arange(0, 21, 1))
        plt.legend((p1[0], p2[0]), ('Number of Games Played', 'Number of Games Won'))
        fig.autofmt_xdate()
        plt.savefig(filepath, bbox_inches='tight')


import cv2 as cv
import numpy as np

capture = cv.VideoCapture(1, cv.CAP_DSHOW)
capture.set(cv.CAP_PROP_FPS, 30)

lowerVal = np.array([20,150,50])
upperVal = np.array([40,255,255])

while True:
    isTrue, frame = capture.read()

    if isTrue:
        cv.imshow('Video', frame)
        frameHSV = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
        cv.imshow('VideoHSV', frameHSV)

        mask = cv.inRange(frameHSV, lowerVal, upperVal)
        cv.imshow('masked_video', mask)

    else:
        break

    if cv.waitKey(20) & 0xFF == ord('q'):
        break


import openai
from django.shortcuts import render
from django.http import JsonResponse
from django.utils import timezone
from chatbot.settings import open_ai_api_key

from chat.models import Chat, Conversation

# Create your views here.

openai_api_key = open_ai_api_key
openai.api_key = openai_api_key

def home(request):
    return render(request, 'chat/home.html')

def ask_openai(message):
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "You are an helpful assistant."},
            {"role": "user", "content": message},
        ]
    )

    answer = response.choices[0].message.content.strip()
    return answer

def chatbot(request):
    chats = Chat.objects.all()

    if request.method == 'POST':
        message = request.POST.get('message')
        response = ask_openai(message)

        chat = Chat(user=request.user, message=message,
                    response=response, created_at=timezone.now())
        chat.save()
        return JsonResponse({'message': message, 'response': response})
    return render(request, 'chat/chatbot.html', {'chats': chats})


# consul event -http-addr=consul.service.nl.consul:8500 -name "run-chef"
# print(event['ID'])
# print(event['Node'])
# print(event['ServiceMeta']['event'])
# print(event['ServiceMeta']['status'])

from cProfile import label
import requests
import time
import sys

datacenter = "us-central1"
token = ""
pollingduration = 10
maxnodestoshow = 10

cmd = "consul event -http-addr=consul.service.{ds}.consul:8500 -name \"run-chef\""
url = "http://consul.service.{ds}.consul:8500/v1/catalog/service/consul-event-chef"

def GetEvents():
  ds_url = url.format(ds = datacenter)
  response = requests.get(ds_url)
  return (response.json())

def PrintResults(nodelist, sectionlabel):
  if len(nodelist) > 0:
    c = 1
    if len(nodelist) >= maxnodestoshow:
      print ("\n---- {label} [showing {max} out of {count} Nodes] ----".format(label = sectionlabel, max = maxnodestoshow, count = len(nodelist)))
    else:
      print ("\n---- {label} [{count} Nodes] ----".format(label = sectionlabel, count = len(nodelist)))

    for event in nodelist:
      print ("{0} {1}".format(event['ID'], event['Node']))
      if c >= maxnodestoshow:
        break
      c = c + 1

def EventUpdates():
  events = GetEvents()

  for event in events:
    # print (event['ID'])
    if event['ID'] == token or token == "":
      if event['ServiceMeta']['status'] == "error":
        errornodes.append(event)
      elif event['ServiceMeta']['status'] == "success":
        successnodes.append(event)
      else:
        inprogressnodes.append(event)

  PrintResults(successnodes, "Success")
  PrintResults(inprogressnodes, "In-Progress")
  PrintResults(errornodes, "Error")

# python3 consul_event_status.py [datacenter] [token]
n = len(sys.argv)
if n>1:
  datacenter = sys.argv[1]
if n>2:
  token = sys.argv[2]

# poll consul server for event status
count = 1
errornodes=[]
successnodes=[]
inprogressnodes=[]

try:
  while 1:
    EventUpdates()
    # if len(inprogressnodes) == 0 or count == pollingduration:
    if len(inprogressnodes) == 0:
      break
    print ("----- waiting ... {0} seconds-----\n".format(count))
    # sleep for 1 sec
    time.sleep(1)
    # clean lists
    count = count + 1
    errornodes.clear()
    successnodes.clear()
    inprogressnodes.clear()
except KeyboardInterrupt:
    pass

print(cmd.format(ds = datacenter))


from lib2to3.pgen2 import driver
from loguru import logger

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options

def base_driver(drv_url, service_type, options):
    if options:
        options = options.split(",")
        chr_opt = Options()

        for opt in options:
            chr_opt.add_argument("--"+opt)
    else:
        chr_opt = None

    if service_type == "local":
        service = Service(drv_url)
        service.start()
        service_param = service.service_url

    elif service_type == "remote":
        service_param = drv_url

    else:
        pass

    try:
        driver = webdriver.Remote(service_param, options=chr_opt)
    except Exception as e:
        logger.error(e)

    return driver

def kill_driver(session_id, tg_url):
    driver = webdriver.Remote(command_executor=tg_url, desired_capabilities={})
    driver.session_id = session_id
    driver.quit()