#coding: utf-8
import json
import os
import sys
import threading
import time
import traceback
import platform
import cv2
import subprocess

import requests
import wx
import yaml

from lib.service.StreamH264Flv import StreamH264Flv


class CameraArea():
    def __init__(self, frame):
        self.frame = frame
        self.mainPanel = None
        self.devId = "010000000000"
        self.channel = 1
        self.getGetPlayUrl = "http://10.100.11.110:9999/video/streamInfo"         # 获取推流播放地址的url
        self.pushObj = None                                                       # 推流对象
        with open("config/config.yaml", 'r', encoding="utf-8") as fi:
            fi_data = fi.read()
            data = yaml.load(fi_data,Loader=yaml.FullLoader)
            self.getGetPlayUrl = data["globalCon"]["getPlayUrl"]

        self.videoPathText = None                                                 # 推流路劲text
        self.pushHostText = None                                                  # host 文本框
        self.pushPortText = None                                                  # port 文本框
        self.devIdText = None                                                     # 设备Id文本框
        self.channelText = None                                                   # 频道文本框
        self.pushStatusText = None                                                # 状态显示区域
        self.logTextCtr = None                                                    # 日志显示区域
        self.msgSendDurText = None                                                # 发送间隔文本框
        self.audioCombox = None                                                   # 音频开关按钮
        self.videoPlayText = None                                                 # 获取播放地址文本框
        self.isShowFrame = 0                                                      # 是否展示帧预览画面 0：不显示  1：显示

    def setDevId(self,data):
        self.devId = data
    def setChannel(self,data):
        self.channel = data

    #################################################
    #       创建一个顶级pannel
    #################################################
    def create(self):
        self.mainPanel = wx.Panel(self.frame)
        boxSizer = wx.BoxSizer(wx.VERTICAL)
        topPanel = self.getTopPanel(boxSizer)
        bottomPanel = self.getBottomPanel(boxSizer)
        boxSizer.Add(topPanel,1,flag=wx.EXPAND | wx.ALL)
        boxSizer.Add(bottomPanel,2, flag=wx.EXPAND | wx.TOP , border=5)
        self.mainPanel.SetSizer(boxSizer)
        return self.mainPanel

    #################################################
    #       获取顶部pannel的内容
    #################################################
    def getTopPanel(self,boxSizer):
        topPanel = wx.Panel(self.mainPanel)
        preView = wx.Panel(topPanel)
        boxSizer_preView = wx.BoxSizer(wx.VERTICAL)
        preView_staticText = wx.StaticText(preView, label='预览区域（未实现）：', pos=(10, 10))
        preView_content = wx.Panel(topPanel, style=wx.BORDER_SIMPLE)
        boxSizer_preView.Add(preView_staticText, 1, flag=wx.EXPAND | wx.ALL)
        boxSizer_preView.Add(preView_content, 11, flag=wx.EXPAND | wx.ALL)
        preView.SetSizer(boxSizer_preView)

        paramView = wx.Panel(topPanel)
        wx.StaticText(paramView, label='本地视频：', pos=(10, 10))
        fiPath = os.getcwd() + "/flv/aaa3.flv"
        self.videoPathText = wx.TextCtrl(paramView, pos=(70, 5), size=wx.Size(300, -1),value=fiPath)                                      # 要推流的视频地址
        selectPathButton = wx.Button(paramView, label="选择视频文件", pos=(375, 5))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt, textCtr=self.videoPathText: self.selectVideoFile(evt, textCtr),
                        selectPathButton)
        wx.StaticText(paramView, label='推流地址：', pos=(10, 40))
        self.pushHostText = wx.TextCtrl(paramView, pos=(70, 35), size=wx.Size(150, -1), value="10.100.11.125")               # 推流地址
        wx.StaticText(paramView, label='推流端口：', pos=(235, 40))
        self.pushPortText = wx.TextCtrl(paramView, pos=(300, 35), size=wx.Size(80, -1), value="1078")                        # 推流端口
        wx.StaticText(paramView, label='设 备号：', pos=(10, 70))
        self.devIdText = wx.TextCtrl(paramView, pos=(70, 65), size=wx.Size(150, -1), value=self.devId)                    # 设备号
        wx.StaticText(paramView, label='频 道号：', pos=(235, 70))
        self.channelText = wx.TextCtrl(paramView, pos=(300, 65), size=wx.Size(80, -1), value=str(self.channel))             # 频道号
        wx.StaticText(paramView, label='当前状态：', pos=(10, 100))
        self.pushStatusText = wx.TextCtrl(paramView, pos=(70, 95), size=wx.Size(80, -1), value="未连网",
                                     style=wx.TE_READONLY)  # 推流状态显示
        self.pushStatusText.SetForegroundColour(wx.RED)
        wx.StaticText(paramView, label='消息发送间隔（毫秒）：', pos=(10, 130))
        self.msgSendDurText = wx.TextCtrl(paramView, pos=(150, 125), size=wx.Size(40, -1), value="7")                        # 消息发送间隔
        wx.StaticText(paramView, label='音频：', pos=(200, 130))
        self.audioCombox = wx.ComboBox(paramView, pos=(240,125), choices=['开', '关'],value="开",size=wx.Size(50,-1))
        wx.StaticText(paramView, label='播放地址：', pos=(10, 190))
        self.videoPlayText = wx.TextCtrl(paramView, pos=(70, 185), size=wx.Size(350, -1))                                    # 视频播放地址
        getPlayUrlButton = wx.Button(paramView, label="获取播放地址", pos=(425, 185))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt, textCtr=self.videoPlayText: self.getPlayUrl(evt, textCtr),
                        getPlayUrlButton)

        ctrView = wx.Panel(topPanel, style=wx.BORDER_SIMPLE)
        connectButton = wx.Button(ctrView, label="1、连网", pos=(5, 5))

        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.connect(evt),
                        connectButton)
        startPushButton = wx.Button(ctrView, label="2、开始推流", pos=(120, 5))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.startPush(evt),
                        startPushButton)
        pausePushButton = wx.Button(ctrView, label="3、停止推流", pos=(5, 35))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.pausePush(evt),pausePushButton)
        rePushButton = wx.Button(ctrView, label="4、继续推流", pos=(120, 35))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.continuePush(evt), rePushButton)
        stopPushButton = wx.Button(ctrView, label="5、结束推流", pos=(5, 65))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.stopPush(evt), stopPushButton)
        disConnectButton = wx.Button(ctrView, label="6、断网", pos=(120, 65))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.disConnect(evt),
                        disConnectButton)
        playStreamVideoButton = wx.Button(ctrView, label="播放流地址", pos=(5, 95))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.playFrame(evt),
                        playStreamVideoButton)
        showFrameButton = wx.Button(ctrView, label="实时显示帧画面", pos=(120, 95))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.showFrame(evt), showFrameButton)
        # StopPlayStreamVideoButton = wx.Button(ctrView, label="停止播放", pos=(5, 125))
        stopShowFrameButton = wx.Button(ctrView, label="停止显示帧画面", pos=(120, 125))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.stopShowFrame(evt), stopShowFrameButton)

        boxSizer_1 = wx.BoxSizer(wx.HORIZONTAL)
        boxSizer_1.Add(preView, 1, flag=wx.EXPAND | wx.ALL)
        boxSizer_1.Add(paramView, 2, flag=wx.EXPAND | wx.ALL)
        boxSizer_1.Add(ctrView, 1, flag=wx.EXPAND | wx.ALL)
        topPanel.SetSizer(boxSizer_1)
        return topPanel

    #################################################
    #       获取底部pannel的内容
    #################################################
    def getBottomPanel(self,boxSizer):
        bottomPanel = wx.Panel(self.mainPanel)
        boxSizer_bottom = wx.BoxSizer(wx.HORIZONTAL)
        logArea = wx.Panel(bottomPanel)
        logStaticText = wx.StaticText(logArea, label='日志：')
        self.logTextCtr = wx.TextCtrl(logArea, size=wx.Size(40, -1),style=wx.TE_MULTILINE)
        boxSizer_logArea = wx.BoxSizer(wx.VERTICAL)
        boxSizer_logArea.Add(logStaticText, 2, flag=wx.EXPAND | wx.TOP ,border=10)
        boxSizer_logArea.Add(self.logTextCtr, 100, flag=wx.EXPAND | wx.ALL)
        logArea.SetSizer(boxSizer_logArea)

        ctrArea = wx.Panel(bottomPanel)
        # ctrArea.SetBackgroundColour("RED")
        ctrText = wx.StaticText(ctrArea, label='控制：')
        ctrPanel = wx.Panel(ctrArea, style=wx.BORDER_SIMPLE)
        connectButton = wx.Button(ctrPanel, label="清空日志", pos=(5, 5))
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.clearLog(evt),
                        connectButton)
        boxSizer_ctrArea = wx.BoxSizer(wx.VERTICAL)
        boxSizer_ctrArea.Add(ctrText,2, flag=wx.EXPAND | wx.TOP ,border=10)
        boxSizer_ctrArea.Add(ctrPanel,100, flag=wx.EXPAND | wx.ALL)
        ctrArea.SetSizer(boxSizer_ctrArea)

        boxSizer_bottom.Add(logArea,60,flag=wx.EXPAND | wx.ALL)
        boxSizer_bottom.Add(ctrArea, 40, flag=wx.EXPAND | wx.LEFT,border=10)
        bottomPanel.SetSizer(boxSizer_bottom)
        return  bottomPanel

    #################################################
    #       打开文件选择对话框
    #################################################
    def selectVideoFile(self,evt,textCtr):
        wildcard = "Video file (*.flv)|*.flv"
        dlg = wx.FileDialog(
            self.frame, message="选择flv视频文件",
            defaultDir=os.getcwd(),
            defaultFile="",
            wildcard=wildcard,
            style=wx.FD_OPEN |
                  wx.FD_CHANGE_DIR | wx.FD_FILE_MUST_EXIST |
                  wx.FD_PREVIEW
        )
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            textCtr.SetValue(path)
        dlg.Destroy()

    ####################################################
    #      获取视频播放地址
    ####################################################
    def doGetPlayUrl(self,textCtr):
        devId = self.devIdText.GetValue()
        channel = self.channelText.GetValue()
        res = requests.post(self.getGetPlayUrl, data=json.dumps({'devId': devId, 'chan': str(channel)})).text
        res = json.loads(res)
        url = res["data"]["url"]
        textCtr.SetValue(url)
    def getPlayUrl(self,evt,textCtr):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        threadObj = threading.Thread(target=self.doGetPlayUrl,args=(textCtr,))
        threadObj.start()

    ####################################################
    #      获取音频状态
    ####################################################
    def getAudioStatus(self):
        audioStatusTxt = self.audioCombox.GetValue()
        if audioStatusTxt == "开":
            audioStatus = 1
        else:
            audioStatus = 0
        return audioStatus

    ####################################################
    #      连网
    ####################################################
    def connect(self,evt):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        isSendAudio = self.getAudioStatus()
        if self.pushObj == None:
            threadObj = threading.Thread(target=self.doConnect,args=())
            threadObj.start()
        else:
            timeCur = self.getCurTime()
            self.logTextCtr.WriteText(timeCur + "已连网！\n")
    def doConnect(self):
        host = self.pushHostText.GetValue()
        port = self.pushPortText.GetValue()
        devId = self.devIdText.GetValue()
        channel = self.channelText.GetValue()
        sendDur = self.msgSendDurText.GetValue()
        isSendAudio = self.getAudioStatus()
        flvPath = self.videoPathText.GetValue()
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        obj = StreamH264Flv()
        obj.setHost(host)
        obj.setPort(int(port))
        obj.setSendDur(int(sendDur) / 1000)
        obj.setIsSendAudio(isSendAudio)
        obj.setMobile(devId)
        obj.setChannel(int(channel))
        obj.setVideoPath(flvPath)

        obj.setMainFrame(self.mainPanel)
        obj.setLogTextCtr(self.logTextCtr)
        obj.setPushStatusText(self.pushStatusText)
        self.pushObj = obj
        self.pushObj.connectServer()
        timeCur = self.getCurTime()
        self.logTextCtr.WriteText(timeCur + "连网成功！\n")
        self.pushStatusText.SetValue("已连网")

    ####################################################
    #      获取当前时间
    ####################################################
    def getCurTime(self):
        timeCur = int(time.time() * 1000)
        timeArray = time.localtime(timeCur / 1000)
        timeCur = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
        timeCur = "[" + timeCur + "]  "
        return timeCur

    ####################################################
    #      断网
    ####################################################
    def disConnect(self,evt):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        self.pushObj.disConnectServer()
        self.pushObj = None
        self.pushStatusText.SetValue("未连网")
        timeCur = self.getCurTime()
        self.logTextCtr.WriteText(timeCur + "连接已经断开！\n")

    ####################################################
    #      开始推流
    ####################################################
    def startPush(self,evt):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        try:
            timeCur = self.getCurTime()
            if self.pushObj != None:
                threadObj = threading.Thread(target=self.pushStream)
                threadObj.start()
                self.logTextCtr.WriteText(timeCur + "推流成功！\n")
                self.pushStatusText.SetValue("推流中")
            else:
                self.logTextCtr.WriteText(timeCur + "未连网！\n")
        except:
            traceback.print_exc()
    def pushStream(self):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        try:
            self.pushObj.readFlvAndSend()
        except:
            traceback.print_exc()

    ####################################################
    #      暂停推流
    ####################################################
    def pausePush(self,evt):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        threadObj = threading.Thread(target=self.doPausePush)
        threadObj.start()
    def doPausePush(self):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        timeCur = self.getCurTime()
        self.logTextCtr.WriteText(timeCur + "暂停推流！\n")
        self.pushStatusText.SetValue("推流暂停")
        self.pushObj.setIsSend(0)

    ####################################################
    #      继续推流
    ####################################################
    def continuePush(self,evt):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        threadObj = threading.Thread(target=self.doContinuePush)
        threadObj.start()
    def doContinuePush(self):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        timeCur = self.getCurTime()
        self.logTextCtr.WriteText(timeCur + "继续推流！\n")
        self.pushStatusText.SetValue("推流中")
        self.pushObj.setIsSend(1)

    ####################################################
    #      停止推流
    ####################################################
    def stopPush(self,evt):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        threadObj = threading.Thread(target=self.doStopPush)
        threadObj.start()
    def doStopPush(self):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        timeCur = self.getCurTime()
        self.logTextCtr.WriteText(timeCur + "推流停止！\n")
        self.pushStatusText.SetValue("连网")
        self.pushObj.setIsEndPush(1)
        # self.pushObj = None


    ####################################################
    #      清空日志
    ####################################################
    def clearLog(self,evt):
        self.logTextCtr.SetValue("")

    ####################################################
    #      获取操作系统名字
    ####################################################
    def getOsName(self):
        osName = platform.system()
        return osName

    ####################################################
    #      实时显示帧画面
    ####################################################
    def showFrame(self,evt):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        if self.getOsName() == "Windows":
            threadObj = threading.Thread(target=self.doShowFrame)
        else:
            threadObj = threading.Thread(target=self.doShowFrame())
        threadObj.start()
    def doShowFrame(self):
        self.isShowFrame = 1
        devId = self.devIdText.GetValue()
        channel = self.channelText.GetValue()
        res = requests.post(self.getGetPlayUrl, data=json.dumps({'devId': devId, 'chan': str(channel)})).text
        res = json.loads(res)
        pullUrl = res["data"]["url"]
        try:
            cap = cv2.VideoCapture(pullUrl)
            timeCur = self.getCurTime()
            self.logTextCtr.WriteText(timeCur + "帧预览开始！\n")
            while (cap.isOpened()):
                if self.isShowFrame == 1:
                    ret, frame = cap.read()
                    if ret == False:
                        break
                    cv2.imshow("video", frame)
                    if cv2.waitKey(1) & 0xFF == ord('q'):
                        break
                else:
                    timeCur = self.getCurTime()
                    self.logTextCtr.WriteText(timeCur + "帧预览停止！\n")
                    break
            cap.release()
            cv2.destroyAllWindows()
        except:
            traceback.print_exc()
    ####################################################
    #      停止显示帧画面
    ####################################################
    def stopShowFrame(self,evt):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        threadObj = threading.Thread(target=self.stopDoShowFrame)
        threadObj.start()
    def stopDoShowFrame(self):
        self.isShowFrame = 0

    ####################################################
    #      播放视频地址
    ###################################################
    def playFrame(self,evt):
        sys.stdout = self.logTextCtr
        sys.stderr = self.logTextCtr
        threadObj = threading.Thread(target=self.doPlayFrame)
        threadObj.start()
        timeCur = self.getCurTime()
        self.logTextCtr.WriteText(timeCur + "开始播放视频！\n")
    def doPlayFrame(self):
        devId = self.devIdText.GetValue()
        channel = self.channelText.GetValue()
        res = requests.post(self.getGetPlayUrl, data=json.dumps({'devId': devId, 'chan': str(channel)})).text
        res = json.loads(res)
        url = res["data"]["url"]
        if self.getOsName() == "Windows":
            m_command = ["ffplay.exe", url]
            CREATE_NO_WINDOW = 0x08000000
            subprocess.run(m_command, creationflags=CREATE_NO_WINDOW)
        else:
            m_command = ["ffplay", url]
            subprocess.run(m_command)


