import json
import logging
import time
import websocket


class WebsocketComm:
    """
    Websocket communicator class
    """
    def __init__(self, addr):
        self.addr = addr
        self.response = None

    def connect(self):
        return True

    def disconnect(self):
        return True

    def request(self, data, timeout=1):
        ws = websocket.create_connection(self.addr)
        ws.send(data)
        response = ws.recv()
        ws.close(timeout=timeout)
        return response


class GripperAgent:
    """
    Gripper agent class, interact with RA about gripper.
    """
    def __init__(self, resource):
        self.device_info = self.adapt_resource(resource)
        ra_addr = resource.get("raAddress") if resource.get("raAddress") else "ws://127.0.0.1:61720"
        self.communicator = WebsocketComm(ra_addr)

    def __enter__(self):
        self.connect()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.disconnect()

    def adapt_resource(self, resource):
        """
        adapt resource data as the id and type from workflow canvas start with "_", but RA is not.
        """
        device_info = {
            "id": resource.get("_id"),
            "type": resource.get("_type"),
            "parameters": resource
        }
        return device_info

    def connect(self):
        self.communicator.connect()

    def calibration(self):
        request = {
            "device_uuid": "",
            "device_info": self.device_info,
            "cmd_id": 2,
            "cmd_param": {}
        }
        response = self.communicator.request(json.dumps(request))
        if not response:
            return False
        rsp = json.loads(response)
        logging.info("active response: {}".format(rsp))
        return rsp.get("error_code").get("value") == 0

    def grasp(self, position, speed, force):
        request = {
            "device_uuid": "",
            "device_info": self.device_info,
            "cmd_id": 3,
            "cmd_param": {
                "position": position,
                "speed": speed,
                "force": force
            }
        }
        response = self.communicator.request(json.dumps(request))
        if not response:
            return False
        rsp = json.loads(response)
        logging.info("grasp response: {}".format(rsp))
        return rsp.get("error_code").get("value") == 0

    def release(self, position, speed, force):
        request = {
            "device_uuid": "",
            "device_info": self.device_info,
            "cmd_id": 4,
            "cmd_param": {
                "position": position,
                "speed": speed,
                "force": force
            }
        }
        response = self.communicator.request(json.dumps(request))
        if not response:
            return False
        rsp = json.loads(response)
        logging.info("release response: {}".format(rsp))
        return rsp.get("error_code").get("value") == 0

    def get_width(self):
        request = {
            "device_uuid": "",
            "device_info": self.device_info,
            "cmd_id": 5,
            "cmd_param": {}
        }
        response = self.communicator.request(json.dumps(request))
        if not response:
            return None
        rsp = json.loads(response)
        logging.info("release response: {}".format(rsp))
        if rsp.get("error_code").get("value") != 0:
            return None
        return rsp.get("data").get("width")

    def disconnect(self):
        self.communicator.disconnect()
