import json
import time
import threading

import base
import rest
from config import cfg
from actuator import Actuator
from video import VideoController


IMAGE_STORE_DIRECTORY = "/mdata"
IMAGE_RECOGNIZE_DIRECTORY = "/mdata"
IMAGE_PRENAME = "capture"
IMAGE_BUFFER_COUNT = cfg.getint("watch", "bufcount")
IMAGE_CAPTURE_INTERVAL = cfg.getfloat("watch", "captureinterval")    #s

VIDEO_FORWARD_R = cfg.getint("watch", "forwardr")
VIDEO_BACKWARD_R = cfg.getint("watch", "backwardr")
VIDEO_LEFT_X = cfg.getint("watch", "leftx")
VIDEO_RIGHT_X = cfg.getint("watch", "rightx")


_watchthreadsinglelock = False   # just one video thread can be run

class _watchthread(threading.Thread):
    def __init__(self, token):
        threading.Thread.__init__(self)
        self.running = False
        self.token = token
        self.currentimg = ""                          # record for show in frontend
        self.currentpos = {"x": 0, "y": 0, "r": 0}    # record for show in frontend

    
    def run(self):
        global _watchthreadsinglelock
        if _watchthreadsinglelock :
            return
        _watchthreadsinglelock = True
        self.running = True

        hr = VideoController.Open(self.token)
        if hr: 
            reccount = 1
            while self.running :
                start_time = time.time()

                imgname = "%s%d.jpg" % (IMAGE_PRENAME, reccount)
                hr = VideoController.Capture(self.token, IMAGE_STORE_DIRECTORY, imgname)
                if hr:
                    self.currentimg = imgname
                    directory = "/%s/%s" % (IMAGE_RECOGNIZE_DIRECTORY, self.currentimg)
                    (hr, resp) = VideoController.Recognize(self.token, directory)
                    if hr:
                        self.currentpos = json.loads(resp)
                        if self.currentpos["r"] > 0 :
                            if self.currentpos["r"] < VIDEO_FORWARD_R :
                                Actuator.TinyForward(self.token)
                            elif self.currentpos["r"] > VIDEO_BACKWARD_R :
                                Actuator.TinyBackward(self.token)
                            elif self.currentpos["x"] < VIDEO_LEFT_X :
                                Actuator.TinyLeft(self.token)
                            elif self.currentpos["x"] > VIDEO_RIGHT_X :
                                Actuator.TinyRight(self.token)
                    else:
                        self.currentpos = {"x": 0, "y": 0, "r": 0}
                
                end_time = time.time()
                jobduration = end_time - start_time
                (quo, rem) = divmod(jobduration, IMAGE_CAPTURE_INTERVAL)
                reccount = (reccount + quo + 1) % IMAGE_BUFFER_COUNT
                if reccount == 0 :
                    reccount = IMAGE_BUFFER_COUNT
                waittime = IMAGE_CAPTURE_INTERVAL - rem
                if waittime > 0 :
                    time.sleep(waittime)

        if not VideoController.Close(self.token):
            print("Zhi Error: Close camera error")

        self.running = False    # for break
        _watchthreadsinglelock = False

    
    def IsRunning(self):
        return _watchthreadsinglelock

    
    def StopThread(self):
        self.running = False
        while(self.is_alive()):
            time.sleep(1)

    
    def GetCurrentImageInfo(self):
        return {"image": self.currentimg, "position": self.currentpos}


     
class _watch:
    def __init__(self):
        self.watchthread = None
        
    def StartWatch(self, token):
        if self.watchthread is not None:
            if self.watchthread.IsRunning() :
                return False

        self.watchthread = _watchthread(token)
        self.watchthread.start()
        return True
        
        
    def StopWatch(self):
        if self.watchthread is not None:
            if self.watchthread.IsRunning():
                self.watchthread.StopThread()
        
        return True

    
    def GetCurrentImageInfo(self):
        if self.watchthread is not None:
            if self.watchthread.IsRunning():
                return self.watchthread.GetCurrentImageInfo()
                
        return None
        

Watch = _watch()
        