###########################################################################
# boxview.py
#
# Monterey Bay Aquarium Research Institute   2019
# All rights reserved.
#
# GUI for managing ml-tracking bounding boxes and publishing
# combined ext_target messages over LCM
#
#
# Created:  Nov 2019      Paul Roberts
#
###########################################################################

import pyqtgraph as pg
import numpy as np
import os
import logging
import argparse
from pyqtgraph.Qt import QtCore, QtGui
from MLHandler import Handler
import lcm
import cv2
from DataDisplay import DataDisplay
import time


logging.basicConfig(
    format='%(asctime)s %(levelname)-8s %(message)s',
    level=logging.DEBUG,
    datefmt='%Y-%m-%d %H:%M:%S',
)
logger = logging.getLogger(__name__)

pg.mkQApp()

## Stylesheets
styleNormalProg = 'QProgressBar {border: 2px solid grey;border-radius: 5px;text-align: center;font: 75 12pt "MS Shell Dlg 2"; } QProgressBar::chunk { background-color: #adcdff;}"'
styleWarnProg = 'QProgressBar {border: 2px solid grey;border-radius: 5px;text-align: center;font: 75 12pt "MS Shell Dlg 2"; } QProgressBar::chunk { background-color: #f5c842;}"'
styleErrProg = 'QProgressBar {border: 2px solid grey;border-radius: 5px;text-align: center;font: 75 12pt "MS Shell Dlg 2"; } QProgressBar::chunk { background-color: #f54242;}"'

## Define main window class from template
path = os.path.dirname(os.path.abspath(__file__))
uiFile = os.path.join(path, 'boxview.ui')
WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile)

img_channels = 3


def parse_args():
    parser = argparse.ArgumentParser(description="Uses LCM messages to make a video.")
    # parser.add_argument(
    #    'video_path',
    #    type=str,
    #    help="Path to output video.",
    # )
    parser.add_argument(
        'target_class',
        type=str,
        default='none',
        help="class name to target for ext_target_messages, must match exactly"
    )
    parser.add_argument(
        'display_width',
        type=int,
        default=960,
        help="width of the image to display"
    )
    parser.add_argument(
        'display_height',
        type=int,
        default=650,
        help="height of each stereo image to display"
    )
    parser.add_argument(
        'default_score',
        type=int,
        default=25,
        help="The default score threshold to use when starting the UI"
    )
    parser.add_argument(
        'default_box_dev',
        type=int,
        default=10,
        help="The default box deviation in %"
    )
    parser.add_argument(
        '--lcmlogfile',
        type=str,
        default="",
        help="Optional log file input for playback"
    )
    return parser.parse_args()


class LCMManager(QtCore.QThread):

    # signals

    def __init__(self, args):
        QtCore.QThread.__init__(self)
        #self.args = args
        logger.info("Initializing handler...")
        Handler.init_class(args)
        logger.info("Creating handlers")
        self.left_handler = Handler(0)
        self.right_handler = Handler(1)
        self.bb_handler = Handler(None)
        self.ext_handler = Handler(None)



    def __del__(self):
        self.wait()


    def run(self):

        lc = lcm.LCM()

        logger.info("Creating subscriptions...")
        lc.subscribe('DSPL_LEFT', self.left_handler)
        lc.subscribe('DSPL_RIGHT', self.right_handler)
        lc.subscribe('BOUNDING_BOX', self.bb_handler)
        lc.subscribe('EXT_TARGET_2', self.ext_handler)

        while self.isRunning:
            lc.handle()


class LCMReader(QtCore.QThread):

    # signals

    def __init__(self, filepath):
        QtCore.QThread.__init__(self)
        #self.args = args
        logger.info("Initializing reader...")
        self.paused = False
        self.filepath = filepath

    def __del__(self):
        self.wait()

    def set_paused(self, state):
        self.paused = state


    def run(self):

        log = lcm.EventLog(self.filepath, "r")
        lc = lcm.LCM()
        for event in log:
            lc.publish(event.channel, event.data)
            # print(event.channel)
            time.sleep(0.01)
            while self.paused:
                time.sleep(0.5)


class MainWindow(TemplateBaseClass):

    def __init__(self, argv):

        TemplateBaseClass.__init__(self)
        self.setWindowTitle('boxview- Python - Qt')

        args = parse_args()

        if args.lcmlogfile is not "":
            self.lcm_reader = LCMReader(args.lcmlogfile)
            self.lcm_reader.start()

            lcm_log_folder, lcm_log_file = os.path.split(args.lcmlogfile)
        else:
            lcm_log_folder = 'ActiveLCM'
            lcm_log_file = '/home/paul/data/lcm-log-player-' + str(int(time.time())) + '.log'

        Handler.set_lcm_dirs(lcm_log_folder, lcm_log_file)
        Handler.set_data_dirs('/home/paul/data/ml-tracking/boxview-left-', '/home/paul/data/ml-tracking/boxview-right-')

        # Create the main window
        self.ui = WindowTemplate()
        self.ui.setupUi(self)

        # setup and connect the lcm manager
        self.lcm_manager = LCMManager(args)
        self.lcm_manager.left_handler.stereoFrame.connect(self.drawStereoFrames)
        self.lcm_manager.right_handler.stereoFrame.connect(self.drawStereoFrames)
        self.lcm_manager.bb_handler.stereoFrame.connect(self.drawStereoFrames)
        self.lcm_manager.ext_handler.stereoFrame.connect(self.drawStereoFrames)
        self.lcm_manager.start()

        # setup the stereo display
        self.stereoDisplay = DataDisplay(pg.ViewBox(), self.ui.imageView, pg.ImageItem(), event_handler=self.initKCFTracker)

        # set defaults from args
        self.ui.scoreSlider.setValue(args.default_score)
        self.ui.boxMatchSlider.setValue(args.default_box_dev)
        Handler.set_score_threshold(args.default_score)
        Handler.set_match_classes(self.ui.matchClassesCheckBox.isChecked())
        Handler.match_methods = [
            self.ui.matchMethodComboBox.itemText(i) for i in range(self.ui.matchMethodComboBox.count())
        ]
        Handler.match_method = self.ui.matchMethodComboBox.currentText()
        Handler.save_kcf_rois = self.ui.saveKCFROIs.isChecked()
        Handler.save_ml_rois = self.ui.saveMLROIs.isChecked()
        Handler.show_bg_mask = self.ui.showBGMask.isChecked()
        Handler.save_ml_rois = self.ui.showML.isChecked()
        Handler.box_height = self.ui.boxHeightSlider.value()
        Handler.box_width = self.ui.boxWidthSlider.value()


        # connect slots
        self.ui.scoreSpinBox.valueChanged.connect(Handler.set_score_threshold)
        self.ui.matchClassesCheckBox.toggled.connect(Handler.set_match_classes)
        self.ui.matchMethodComboBox.currentTextChanged.connect(Handler.set_match_method)
        self.ui.boxMatchSpinBox.valueChanged.connect(Handler.set_box_deviation)
        self.ui.targetClassComboBox.currentTextChanged.connect(Handler.set_target_class)

        self.ui.saveKCFROIs.toggled.connect(Handler.set_save_kcf)
        self.ui.saveMLROIs.toggled.connect(Handler.set_save_ml)
        self.ui.showBGMask.toggled.connect(Handler.set_show_bg_mask)
        self.ui.showML.toggled.connect(Handler.set_show_ml)
        self.ui.boxWidthSlider.valueChanged.connect(Handler.set_box_width)
        self.ui.boxHeightSlider.valueChanged.connect(Handler.set_box_height)

        # Show the main window
        self.show()

    def initKCFTracker(self, coords):
        self.lcm_manager.left_handler.initKCF(coords)

    def drawStereoFrames(self, image):
        # split image horz assuming a vstack
        height = int(image.shape[0] / 2)
        image = np.hstack((np.flipud(image[:height, :, :]), np.flipud(image[height:, :, :])))

        #swap_index_1 = 1
        #swap_index_2 = 0
        #tmp = image[:, :, swap_index_1]
        #image[:, :, swap_index_1] = image[:, :, swap_index_2]
        #image[:, :, swap_index_2] = tmp

        image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)

        self.stereoDisplay.draw(image)



###########################################################################
#  Main entry point
###########################################################################
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
    import sys

    win = MainWindow(sys.argv)

    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()