#

import time
import zmq
import json
import threading
import logging
import pyqtgraph as pg
from enum import IntEnum
from pyqtgraph.Qt import QtCore
import pyqtgraph.exporters
import sys
from PlotStyle import Style


class PlotServer():
    '''
    This class implements a server that listens to commands from a remote plot client.
    The commands will initiate plots, curves and recieve data that will be plot.
    '''
    def __init__(self, plotWindow, **kwargs):

        if 'port' not in kwargs:
            print("Missing named parameter port")
            sys.exit(1)

        port = kwargs.get('port')

        self.plotWindow = plotWindow
        self.context = zmq.Context()
        self.socket = self.context.socket(zmq.REP)
        self.socket.setsockopt(zmq.RCVTIMEO, 3)
        print("Binding to port: " + str(port))
        try:
            self.socket.bind("tcp://*:"+str(port))
        except Exception as e:
            print("\n*** Got an exception:", e)
            print("*** Is server already running?")
            print("\n")
            sys.exit(1)

        print("Server started!")
        self.m_shouldStop = False

        self.m_graphs = {}

    def shouldStop(self):
        b = self.m_shouldStop

        return b

    def stop(self):
        self.m_shouldStop = True

    def getPenStyle(self, data):
        style = data['style']

        if (style == Style.SolidLine):
            return QtCore.Qt.SolidLine
        elif (style == Style.DashLine):
            return QtCore.Qt.DashLine
        elif (style == Style.DotLine):
            return QtCore.Qt.DotLine
        else:
            print("Invalid Style")
            return QtCore.Qt.SolidLine

    def addCurve(self, data):
        title = data['title']
        curve = data['curve']
        print("Adding curve: ", title, curve)

        if (title in self.m_graphs):
            graph = self.m_graphs[title]
            color = data['color']
            style = self.getPenStyle(data)
            pen = pg.mkPen(color=(color[0], color[1], color[2]), 
                           style=style, width=data['width'])

            graph.addCurve(curve, pen=pen)

        else:
            print("Cannot add curve to Non existing graph: "+title)

    def reset(self):
        self.plotWindow.reset()
        self.m_graphs.clear()

    def addPlot(self, data):
        title = data['title']
        print("Adding plot: ", title)

        new_row = True if not len(self.m_graphs) % 2 else False
        plot_graph = self.plotWindow.add_graph(title, new_row=new_row, xLabel=data['xLabel'], xUnit=data['xUnit'], yLabel=data['yLabel'], yUnit=data['yUnit'])

        self.m_graphs[data['title']] = plot_graph

    def savePlot(self, data):
        filename = data['title'] + ".png"
        print("Saving to: " + filename)
        self.plotWindow.save(filename)

    def addData(self, data):
        title = data['title']
        if (title in self.m_graphs):
            graph = self.m_graphs[title]
            graph.addData(data['curve'], data['x_data'], data['y_data'])
        else:
            print("Cannot add data to Non existing graph: "+title)

    def commandSwitcher(self, data):
        command = data['command']

        if (command == "stop"):
            self.stop()
        elif(command == "addPlot"):
            self.addPlot(data)
        elif(command == "addCurve"):
            self.addCurve(data)
        elif(command == "reset"):
            self.reset()
        elif(command == "addData"):
            self.addData(data)
        elif(command == "save"):
            self.savePlot(data)
        else:
            return False
        return True

    def checkMessages(self):
        #  Wait for next request from client
        data = None
        try:
            data = self.socket.recv()
        except zmq.error.Again as _e:
            return

        deserialized = json.loads(data)
        status = self.commandSwitcher(deserialized)
        if (not status):
            print("Invalid command recieved: ", deserialized['command'])

        #  Send reply back to client
        self.socket.send(b"Got it")
