from threading import Thread
from queue import Queue
from djitellopy import Tello
import signal
import sys
import time
import logging
import cv2
import numpy as np
from control import ManualControl, AutoControl
from utils import Status, DataRecorder




class UAV:
    def __init__(self) -> None:
        self.tello = Tello()
        signal.signal(signal.SIGINT, self.signal_handler)
        self.tello.connect()
        print('Current_battery: ' + str(self.tello.get_battery()))
        self.tello.streamon()
        self.tello.set_video_resolution(Tello.RESOLUTION_480P)
        self.tello.set_video_fps(Tello.FPS_30)
        self.tello.set_video_bitrate(Tello.BITRATE_1MBPS)
        self.tello.set_video_direction(Tello.CAMERA_FORWARD)

        self.frame_read = self.tello.get_frame_read()

        self.left_right_velocity = 0
        self.for_back_velocity = 0
        self.up_down_velocity = 0
        self.yaw_velocity = 0

        self.send_rc_control = False
        self.manual_control = ManualControl(self)
        self.auto_control = AutoControl(self)
        self.status = Status.DETECT

        self.frame_queue = Queue(maxsize=1)  # 用于存放视频帧, 1用于避免帧堆积
        record_name = input("请输入数据备注(英文):")
        if record_name:
            self.recorder = DataRecorder(exp_note=record_name, need_record=True)
        else:
            self.recorder = DataRecorder()

        self.front_cam_shape = (648, 478)  # x, y
    
    def update(self):
        """ Update routine. Send velocities to Tello.

            向Tello发送各方向速度信息
        """
        if self.yaw_velocity > 50:
            self.yaw_velocity = 50
        elif self.yaw_velocity < -50:
            self.yaw_velocity = -50
            
        if self.send_rc_control:
            self.tello.send_rc_control(self.left_right_velocity, self.for_back_velocity,
                self.up_down_velocity, self.yaw_velocity)
            print(self.left_right_velocity, self.for_back_velocity,
                self.up_down_velocity, self.yaw_velocity)
    
    def run(self):
        """ 主程序 """
        # self.init_flight()
        # self.tello.turn_motor_on()

        state_thread = Thread(target=self.video_stream)
        state_thread.start()

        self.manual_control.start()  # 启动手动控制键盘监听

        while True:
            # self.up_down_velocity(10)
            self.auto_track_land()
            self.update()
            # self.video_display()
            time.sleep(0.05)

    def signal_handler(self, signal, frame):
        print ('\nSignal Catched! 执行急停!')
        self.tello.emergency()
        self.tello.streamoff()
        sys.exit(0)

    def init_flight(self):
        self.tello.turn_motor_on()
        time.sleep(5)
        logging.warn('自检完毕,可以起飞')
        self.tello.takeoff()
        self.send_rc_control = True  # 开启发送控制信号
        self.update()

    def video_stream(self):
        height, width, _ = self.frame_read.frame.shape
        while True:
            frame = self.frame_read.frame
            self.frame_queue.put(frame)

            states = self.tello.get_current_state()
            states['timestamp'] = time.time()
            self.recorder.state_record(states)
            self.recorder.frame_record(frame, 'origin')

            time.sleep(1 / 30)

    def video_display(self):
        """ 显示视频 """
        if not self.frame_queue.empty():
            frame = self.frame_queue.get()
            cv2.imshow("Tello Camera", frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                self.keep_recording = False
                cv2.destroyAllWindows()
            if cv2.waitKey(1) & 0xFF == ord('s'):
                cv2.imwrite(str(time.time()) + '.jpg', frame)

    def auto_track_land(self):
        # print(self.status)

        if self.status == Status.TRACK or self.status == Status.DETECT:
            front_img = self.frame_queue.get()
            front_img = cv2.cvtColor(front_img, cv2.COLOR_RGB2BGR)
            if self.status == Status.DETECT:
                self.auto_control.detect(front_img=front_img)
            elif self.status == Status.TRACK:
                self.auto_control.track(front_img=front_img)
        
        elif self.status == Status.LANDING:
            bottom_img = self.frame_queue.get()
            self.auto_control.landing(bottom_img=bottom_img)

        
            
if __name__ == '__main__':
    uav = UAV()
    # while True:
    #     print(uav.tello.get_current_state())
    uav.run()