class Aruco_tracker():
    def __init__(self, distance):
        """
        Inicialização dos drivers, parâmetros do controle PID e decolagem do drone.
        """
        self.distance = distance
        self.pid_foward = PID(distance, 0.01, 0.0001, 0.01, 500, -500, 0.7,
                              -0.7)
        self.pid_yaw = PID(0, 0.33, 0.0, 0.33, 500, -500, 100, -100)
        self.pid_angle = PID(0.0, 0.01, 0.0, 0.01, 500, -500, 0.3, -0.3)
        self.pid_height = PID(0.0, 0.002, 0.0002, 0.002, 500, -500, 0.3, -0.2)
        cflib.crtp.init_drivers(enable_debug_driver=False)
        self.factory = CachedCfFactory(rw_cache='./cache')
        self.URI4 = 'radio://0/40/2M/E7E7E7E7E4'
        self.cf = Crazyflie(rw_cache='./cache')
        self.sync = SyncCrazyflie(self.URI4, cf=self.cf)
        self.sync.open_link()
        self.mc = MotionCommander(self.sync)
        self.cont = 0
        self.notFoundCount = 0
        self.calculator = DistanceCalculator()
        self.cap = cv2.VideoCapture(1)
        self.mc.take_off()
        time.sleep(1)

    def search_marker(self):
        """
        Interrompe o movimento se nao encontrar o marcador por tres frames
        consecutivos. Após 4 segundos, inicia movimento de rotação para
        procurar pelo marcador.
        """
        if ((3 <= self.notFoundCount <= 20) and self.mc.isRunning):
            self.mc.stop()
            self.mc.setIsRunning(False)
        elif (self.notFoundCount > 20):
            self.mc._set_vel_setpoint(0.0, 0.0, 0.0, 80)
            self.mc.setIsRunning(True)
        return

    def update_motion(self):
        """
        Atualiza as velocidades utilizando controlador PID.
        """
        horizontal_distance = self.calculator.horizontal_distance
        vertical_distance = self.calculator.vertical_distance
        x_distance = self.calculator.distance_x
        alpha = self.calculator.alpha
        velocity_x = self.pid_foward.update(x_distance)
        Velocity_z = self.pid_height.update(vertical_distance)
        if (x_distance < (self.distance + 10)):
            velocity_y = self.pid_angle.update(alpha)
        else:
            velocity_y = 0
            velocity_z = 0
        yaw = self.pid_yaw.update(horizontal_distance)
        self.mc._set_vel_setpoint(velocity_x, velocity_y, 0, yaw)
        self.mc.setIsRunning(True)
        return

    def track_marker(self):
        """
        Programa principal, drone segue um marcador aruco.
        """
        while (self.cap.isOpened()):
            ret, frame = self.cap.read()

            if (frame is None):
                break

            if (self.cont % 6 == 0):
                thread = threading.Thread(
                    target=self.calculator.calculateDistance, args=(frame, ))
                thread.setDaemon(True)
                thread.start()

                if (self.calculator.markerFound):
                    self.notFoundCount = 0
                    self.update_motion()
                else:
                    self.notFoundCount += 1
                    self.search_marker()

                self.calculator.writeDistance(frame)
                cv2.imshow('frame', frame)

            self.cont += 1
            if cv2.waitKey(10) & 0xFF == ord('q'):
                self.mc.land()
                cv2.destroyAllWindows()
                break

        cv2.waitKey()

        self.sync.close_link()
        thread.join()
        e2 = cv2.getTickCount()
        t = (e2 - e1) / cv2.getTickFrequency()
        exeTime.append(t)

    calculator.writeDistance(frame)
    cv2.imshow('frame', frame)

    # print(calculator.distance_x)
    if (calculator.distance_x == 0):
        print("zero")
    elif (calculator.distance_x > 30):
        if (mc.isRunning):
            mc.stop()
        mc.start_linear_motion(0.1, 0.0, 0.0)
        mc.setIsRunning(True)
        print("para frente")
    elif (calculator.distance_x < 25):
        if (mc.isRunning):
            mc.stop()
        mc.start_linear_motion(-0.1, 0.0, 0.0)
        mc.setIsRunning(True)
        print("para tras")
    else:
        if (mc.isRunning):
            mc.stop()

    cont += 1
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break
                velocity_x = -0.5

            # velocity_z = pid_height.update(vertical_distance)
            if (x_distance < 50):
                if calculator.alpha > 0:
                    velocity_y = 0.3
                else:
                    velocity_y = -0.3

            if (calculator.horizontal_distance > 0):
                yaw = 30
            else:
                yaw = -30

            mc._set_vel_setpoint(velocity_x, velocity_y, 0, yaw)
            mc.setIsRunning(True)
        else:
            # Drone interrompe o movimento somente se não encontrar o marcador
            # em 3 frames consecutivos
            notFoundCount += 1
            if ((3 <= notFoundCount <= 20) and mc.isRunning):
                mc.stop()
                mc.setIsRunning(False)
            elif (notFoundCount > 20):
                mc._set_vel_setpoint(0.0, 0.0, 0.0, 100)
                mc.setIsRunning(True)

        calculator.writeDistance(frame)
        cv2.imshow('frame', frame)

    cont += 1