###########################################################################
# managers.py
#
# Monterey Bay Aquarium Research Institute   2019
# All rights reserved.
#
# Managers to process lcm events and render images with overlays
# subclass as needed to add more features
#
#
# Created:  Dec 2019      Paul Roberts
#
###########################################################################


import cv2
import numpy as np
from config import CONFIG
from image import image_t
from mbari import ext_target_t
from collections import deque
from tools import FrameTimer, msg_2_frame

"""
A general event hanlder
"""

class EventManager:

    def __init__(self, channel_list=None, debug=False):
        self.channel_list = channel_list
        self.events = {}
        self.debug = debug
        for chan in self.channel_list:
            self.events[chan] = deque()

    def add_event(self, event):

        if self.debug:
            print(event.channel)

        if event.channel in self.channel_list:
            self.events[event.channel].append(event)

        self.render()

    def render(self):
        output = [e.channel for e in self.event_list]
        print(output)


class OverlayManager(EventManager):

    def __init__(self, left_channel, right_channel, aux_channels=[], cfg=None, fps=10, log_rate=1, debug=False):

        # setup member variables and call parent __init__()
        self.all_channels = [left_channel, right_channel] + aux_channels
        super().__init__(self.all_channels, debug=debug)
        self.left_channel = left_channel
        self.right_channel = right_channel
        self.aux_channels = aux_channels

        # pull in default config if none is provided
        if cfg is None:
            self.cfg = CONFIG
        else:
            self.cfg = cfg

        # create frame timer for managing effective FPS and log intervals
        self.timer = FrameTimer(fps=fps, log_rate=log_rate)

    def render_ext_target(self, img, msg):
        # font
        font = cv2.FONT_HERSHEY_SIMPLEX
        # org
        lorg = (20, img.shape[0] - 20)
        rorg = (int(img.shape[1]/2) + 20, img.shape[0] - 20)
        # fontScale
        fontScale = 0.5
        # Green color in BGR
        color = (0, 255, 0)
        # Line thickness of 2 px
        thickness = 1

        ltext = "Classs: " + str(msg.left_class_name) + ", (" + str(msg.left_x) + "," + str(msg.left_y) + ")"
        rtext = "Classs: " + str(msg.right_class_name) + ", (" + str(msg.right_x) + "," + str(msg.right_y) + ")"

        # draw the text on the image, just the class names for now
        cv2.putText(img, ltext, lorg, font, fontScale, color, thickness, cv2.LINE_AA)
        cv2.putText(img, rtext, rorg, font, fontScale, color, thickness, cv2.LINE_AA)

    def render(self):

        # if we have a pair of stereo images, then pop them and overlay
        # the latest aux data
        #
        # NB: This does not check for images timestamps to handle dropped frames.
        # To do so, check the utime for each image
        if len(self.events[self.left_channel]) > 0 and len(self.events[self.right_channel]) > 0:

            # get image data and timestamps
            levent = self.events[self.left_channel].pop()
            revent = self.events[self.right_channel].pop()
            limg, lutime = msg_2_frame(image_t.decode(levent.data))
            rimg, rutime = msg_2_frame(image_t.decode(revent.data))
            combined_pair = np.hstack((limg, rimg))

            # compute time delta between images:
            img_delta = lutime - rutime

            # add data overlays as needed
            for chan in self.aux_channels:
                if len(self.events[chan]) > 0:
                    event = self.events[chan].pop()
                    if event.channel == 'EXT_TARGET_1':
                        self.render_ext_target(combined_pair, ext_target_t.decode(event.data))


            # Draw the image pair
            cv2.imshow('Stereo Images', combined_pair)


            # show the new frame in the window and exit if the user presses esc
            if cv2.waitKey(1) == 27:
                exit()


            if self.debug:
                print('Image delta: ' + str(img_delta) + "," + str(lutime) + "," + str(rutime))

            # delay to match frame rate and log
            self.timer.new_frame()
            self.timer.fps_sleep()
            self.timer.log()
            self.timer.fps_start()



