import zmq
import msgpack as serializer

print('Opening ports')
class ZMQsocket:

    def __init__(self, remote_ip, port):
        """
        Setup zmq socket, context, and remote helper.

        Parameters:
        port (float): Specified port to connect to. Defaults to 50020.
        """
        self.ip = remote_ip 
        self.port = port
        self.ctx = zmq.Context()
        self.socket = zmq.Socket(self.ctx, zmq.REQ) # this is pub socket

    def connect(self):
        """
        Connects to defined zmq socket.
        """
        self.socket.connect(f'tcp://{self.ip}:{self.port}')
        self.socket.send_string('PUB_PORT')
        self.pub_port = self.socket.recv_string()
        self.pub_socket = zmq.Socket(self.ctx, zmq.PUB)
        self.pub_socket.connect(f"tcp://{self.ip}:{self.pub_port}")

    def start_calibration(self):
        """
        Starts pupil calibration procedure.
        """
        self.socket.send_string('C')
        return self.socket.recv_string()

    def stop_calibration(self):
        """
        Stops pupil calibration procedure.
        """
        self.socket.send_string('c')
        return self.socket.recv_string()

    def start_recording(self, dir_name=None):
        """
        Starts pupil recording.
        Parameters:
        dir_name (str): Optional name for directory
        """
        if dir_name:
            self.socket.send_string(f'R {dir_name}')
        else:
            self.socket.send_string('R')       
        return self.socket.recv_string()

    def stop_recording(self):
        """
        Stops pupil recording.
        """
        self.socket.send_string('r')
        return self.socket.recv_string()

    def set_time(self, time_fn):
        """
        Sets the time in pupil.

        Parameters:
        time (float): Time to set to. 
        """
        self.time_fn = time_fn
        self.socket.send_string(f'T {time_fn()}')
        return self.socket.recv_string()
    
    # send notification:
    def notify(self, notification):
        """Sends ``notification`` to Pupil Remote"""
        topic = 'notify.' + notification['subject']
        payload = serializer.dumps(notification, use_bin_type=True)
        self.socket.send_string(topic, flags=zmq.SNDMORE)
        self.socket.send(payload)
        return self.socket.recv_string()

    #test notification, note that you need to listen on the IPC to receive notifications!
    #notify({'subject':"calibration.should_start"})
    #notify({'subject':"calibration.should_stop"})

    # TODO fix sending annotations
    def send_trigger(self, trigger):
        """
        Sends a trigger object pub_socket
        """
        payload = serializer.dumps(trigger, use_bin_type=True)
        self.pub_socket.send_string(trigger['topic'], flags=zmq.SNDMORE)
        self.pub_socket.send(payload)

    def new_trigger(self, topic, label, duration):
        """
        Creates a trigger dictionary object (make sure set_time() has been invoked)
        """
        return {
            "topic": topic,
            "label": label,
            "timestamp": self.time_fn(),
            "duration": duration,
        }

    def annotation(self, label, duration):
        """
        Shortcut to sending an annotation to pupil remote (make sure set_time() has been invoked)
        """
        self.send_trigger(self.new_trigger('annotation', label, duration))


    print('Done!')