"""This module provides an instance of the centralised, distributed voter"""

from queue import Queue
import json
import argparse

import numpy as np
import cv2

import MyRaft.node as raft
import MyRaft.leader as leader
import DecisionSystem.CentralisedDecision.commander as commander
import DecisionSystem.CentralisedDecision.messenger as messenger
import DecisionSystem.CentralisedDecision.ballotvoter as voter
import DecisionSystem.CentralisedDecision.videoget as videoget
import GestureRecognition.simplehandrecogniser as shr
import GestureRecognition.starkaleid as sk

class Instance:
    """An instance of the centralised, distributed approach to voting.
    """
    def __init__(self, node_config='config.json', video_file=0):
        with open(node_config) as f:
            self.cfg= json.load(f)
        self.mqtt = messenger.MqttMessenger(self.cfg)
        self.we_lead = False
        self.node = raft.RaftGrpcNode(node_config)
        print("Node initialised")
        self.node.add_state_change(self.on_state_changed)

        self.voter = voter.BallotVoter(self.on_vote, self.handle_agreement, self.mqtt)
        self.commander = commander.Commander(self.mqtt)
        self.recogniser = shr.SimpleHandRecogniser(None)

        self.last_vote = -1

        self.q = Queue(5)
        self.frame = None
        self.vd = videoget.VideoGet(self.q, video_file)

        self.kaleid = False
        print("Initialised the instance")

    def on_state_changed(self):
        """Callback method for state of the raft node changing"""
        if isinstance(self.node._current_state, leader.Leader):
            # We are now the commander (or leader)
            self.commander = commander.Commander(self.mqtt)
        else:
            # No longer or never were a leader.
            try:
                del(self.commander)
            except SyntaxError:
                pass

    def start(self):
        self.vd.start()
        self.mqtt.connect()
        go = True
        while go:
            if self.kaleid:
                go = self.show_kaleidoscope
            else:
                go = self.show_normal

    def show_normal(self):
        self.frame = np.copy(self.q.get())
        cv2.imshow('Frame', self.frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            return False
        elif cv2.waitKey(1) & 0xFF == ord('g'):
            self.voter.request_vote()

    def show_kaleidoscope(self):
        self.frame = sk.make_kaleidoscope(np.copy(self.q.get()), 12)
        cv2.imshow('Frame', self.frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            return False
        elif cv2.waitKey(1) & 0xFF == ord('g'):
            self.voter.request_vote()

    def on_vote(self):
        # Get the current frame of the camera and process what hand 
        # is currently being seen. 
        print('getting frame')
        # Need to copy rather than just take a reference, as frame will
        # constantly be changing.
        self.recogniser.set_frame(np.copy(self.frame))
        print('Got frame, voting with recogniser')
        gesture = self.recogniser.get_gesture()
        self.last_vote = gesture
        return gesture

    def handle_agreement(self, vote):
        if vote == 5:
            self.kaleid = True
        else:
            self.kaleid = False


parser = argparse.ArgumentParser(description="An instance of CAIDE")

if __name__ == "__main__":
    instance = Instance(video_file="/Users/piv/Documents/Projects/Experiments/Camera1/video.mp4")
    instance.start()
        