# DO NOT EDIT THIS FILE!
#
# This file is generated from the CDP specification. If you need to make
# changes, edit the generator and regenerate all of the modules.
#
# CDP domain: BluetoothEmulation (experimental)

from __future__ import annotations
import enum
import typing
from dataclasses import dataclass
from .util import event_class, T_JSON_DICT


class CentralState(enum.Enum):
    """
    Indicates the various states of Central.
    """

    ABSENT = "absent"
    POWERED_OFF = "powered-off"
    POWERED_ON = "powered-on"

    def to_json(self) -> str:
        return self.value

    @classmethod
    def from_json(cls, json: str) -> CentralState:
        return cls(json)


class GATTOperationType(enum.Enum):
    """
    Indicates the various types of GATT event.
    """

    CONNECTION = "connection"
    DISCOVERY = "discovery"

    def to_json(self) -> str:
        return self.value

    @classmethod
    def from_json(cls, json: str) -> GATTOperationType:
        return cls(json)


class CharacteristicWriteType(enum.Enum):
    """
    Indicates the various types of characteristic write.
    """

    WRITE_DEFAULT_DEPRECATED = "write-default-deprecated"
    WRITE_WITH_RESPONSE = "write-with-response"
    WRITE_WITHOUT_RESPONSE = "write-without-response"

    def to_json(self) -> str:
        return self.value

    @classmethod
    def from_json(cls, json: str) -> CharacteristicWriteType:
        return cls(json)


class CharacteristicOperationType(enum.Enum):
    """
    Indicates the various types of characteristic operation.
    """

    READ = "read"
    WRITE = "write"
    SUBSCRIBE_TO_NOTIFICATIONS = "subscribe-to-notifications"
    UNSUBSCRIBE_FROM_NOTIFICATIONS = "unsubscribe-from-notifications"

    def to_json(self) -> str:
        return self.value

    @classmethod
    def from_json(cls, json: str) -> CharacteristicOperationType:
        return cls(json)


class DescriptorOperationType(enum.Enum):
    """
    Indicates the various types of descriptor operation.
    """

    READ = "read"
    WRITE = "write"

    def to_json(self) -> str:
        return self.value

    @classmethod
    def from_json(cls, json: str) -> DescriptorOperationType:
        return cls(json)


@dataclass
class ManufacturerData:
    """
    Stores the manufacturer data
    """

    #: Company identifier
    #: https://bitbucket.org/bluetooth-SIG/public/src/main/assigned_numbers/company_identifiers/company_identifiers.yaml
    #: https://usb.org/developers
    key: int

    #: Manufacturer-specific data (Encoded as a base64 string when passed over JSON)
    data: str

    def to_json(self) -> T_JSON_DICT:
        json: T_JSON_DICT = dict()
        json["key"] = self.key
        json["data"] = self.data
        return json

    @classmethod
    def from_json(cls, json: T_JSON_DICT) -> ManufacturerData:
        return cls(
            key=int(json["key"]),
            data=str(json["data"]),
        )


@dataclass
class ScanRecord:
    """
    Stores the byte data of the advertisement packet sent by a Bluetooth device.
    """

    name: typing.Optional[str] = None

    uuids: typing.Optional[typing.List[str]] = None

    #: Stores the external appearance description of the device.
    appearance: typing.Optional[int] = None

    #: Stores the transmission power of a broadcasting device.
    tx_power: typing.Optional[int] = None

    #: Key is the company identifier and the value is an array of bytes of
    #: manufacturer specific data.
    manufacturer_data: typing.Optional[typing.List[ManufacturerData]] = None

    def to_json(self) -> T_JSON_DICT:
        json: T_JSON_DICT = dict()
        if self.name is not None:
            json["name"] = self.name
        if self.uuids is not None:
            json["uuids"] = [i for i in self.uuids]
        if self.appearance is not None:
            json["appearance"] = self.appearance
        if self.tx_power is not None:
            json["txPower"] = self.tx_power
        if self.manufacturer_data is not None:
            json["manufacturerData"] = [i.to_json() for i in self.manufacturer_data]
        return json

    @classmethod
    def from_json(cls, json: T_JSON_DICT) -> ScanRecord:
        return cls(
            name=str(json["name"]) if json.get("name", None) is not None else None,
            uuids=[str(i) for i in json["uuids"]]
            if json.get("uuids", None) is not None
            else None,
            appearance=int(json["appearance"])
            if json.get("appearance", None) is not None
            else None,
            tx_power=int(json["txPower"])
            if json.get("txPower", None) is not None
            else None,
            manufacturer_data=[
                ManufacturerData.from_json(i) for i in json["manufacturerData"]
            ]
            if json.get("manufacturerData", None) is not None
            else None,
        )


@dataclass
class ScanEntry:
    """
    Stores the advertisement packet information that is sent by a Bluetooth device.
    """

    device_address: str

    rssi: int

    scan_record: ScanRecord

    def to_json(self) -> T_JSON_DICT:
        json: T_JSON_DICT = dict()
        json["deviceAddress"] = self.device_address
        json["rssi"] = self.rssi
        json["scanRecord"] = self.scan_record.to_json()
        return json

    @classmethod
    def from_json(cls, json: T_JSON_DICT) -> ScanEntry:
        return cls(
            device_address=str(json["deviceAddress"]),
            rssi=int(json["rssi"]),
            scan_record=ScanRecord.from_json(json["scanRecord"]),
        )


@dataclass
class CharacteristicProperties:
    """
    Describes the properties of a characteristic. This follows Bluetooth Core
    Specification BT 4.2 Vol 3 Part G 3.3.1. Characteristic Properties.
    """

    broadcast: typing.Optional[bool] = None

    read: typing.Optional[bool] = None

    write_without_response: typing.Optional[bool] = None

    write: typing.Optional[bool] = None

    notify: typing.Optional[bool] = None

    indicate: typing.Optional[bool] = None

    authenticated_signed_writes: typing.Optional[bool] = None

    extended_properties: typing.Optional[bool] = None

    def to_json(self) -> T_JSON_DICT:
        json: T_JSON_DICT = dict()
        if self.broadcast is not None:
            json["broadcast"] = self.broadcast
        if self.read is not None:
            json["read"] = self.read
        if self.write_without_response is not None:
            json["writeWithoutResponse"] = self.write_without_response
        if self.write is not None:
            json["write"] = self.write
        if self.notify is not None:
            json["notify"] = self.notify
        if self.indicate is not None:
            json["indicate"] = self.indicate
        if self.authenticated_signed_writes is not None:
            json["authenticatedSignedWrites"] = self.authenticated_signed_writes
        if self.extended_properties is not None:
            json["extendedProperties"] = self.extended_properties
        return json

    @classmethod
    def from_json(cls, json: T_JSON_DICT) -> CharacteristicProperties:
        return cls(
            broadcast=bool(json["broadcast"])
            if json.get("broadcast", None) is not None
            else None,
            read=bool(json["read"]) if json.get("read", None) is not None else None,
            write_without_response=bool(json["writeWithoutResponse"])
            if json.get("writeWithoutResponse", None) is not None
            else None,
            write=bool(json["write"]) if json.get("write", None) is not None else None,
            notify=bool(json["notify"])
            if json.get("notify", None) is not None
            else None,
            indicate=bool(json["indicate"])
            if json.get("indicate", None) is not None
            else None,
            authenticated_signed_writes=bool(json["authenticatedSignedWrites"])
            if json.get("authenticatedSignedWrites", None) is not None
            else None,
            extended_properties=bool(json["extendedProperties"])
            if json.get("extendedProperties", None) is not None
            else None,
        )


def enable(
    state: CentralState, le_supported: bool
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Enable the BluetoothEmulation domain.

    :param state: State of the simulated central.
    :param le_supported: If the simulated central supports low-energy.
    """
    params: T_JSON_DICT = dict()
    params["state"] = state.to_json()
    params["leSupported"] = le_supported
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.enable",
        "params": params,
    }
    json = yield cmd_dict


def set_simulated_central_state(
    state: CentralState,
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Set the state of the simulated central.

    :param state: State of the simulated central.
    """
    params: T_JSON_DICT = dict()
    params["state"] = state.to_json()
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.setSimulatedCentralState",
        "params": params,
    }
    json = yield cmd_dict


def disable() -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Disable the BluetoothEmulation domain.
    """
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.disable",
    }
    json = yield cmd_dict


def simulate_preconnected_peripheral(
    address: str,
    name: str,
    manufacturer_data: typing.List[ManufacturerData],
    known_service_uuids: typing.List[str],
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Simulates a peripheral with ``address``, ``name`` and ``knownServiceUuids``
    that has already been connected to the system.

    :param address:
    :param name:
    :param manufacturer_data:
    :param known_service_uuids:
    """
    params: T_JSON_DICT = dict()
    params["address"] = address
    params["name"] = name
    params["manufacturerData"] = [i.to_json() for i in manufacturer_data]
    params["knownServiceUuids"] = [i for i in known_service_uuids]
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.simulatePreconnectedPeripheral",
        "params": params,
    }
    json = yield cmd_dict


def simulate_advertisement(
    entry: ScanEntry,
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Simulates an advertisement packet described in ``entry`` being received by
    the central.

    :param entry:
    """
    params: T_JSON_DICT = dict()
    params["entry"] = entry.to_json()
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.simulateAdvertisement",
        "params": params,
    }
    json = yield cmd_dict


def simulate_gatt_operation_response(
    address: str, type_: GATTOperationType, code: int
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Simulates the response code from the peripheral with ``address`` for a
    GATT operation of ``type``. The ``code`` value follows the HCI Error Codes from
    Bluetooth Core Specification Vol 2 Part D 1.3 List Of Error Codes.

    :param address:
    :param type_:
    :param code:
    """
    params: T_JSON_DICT = dict()
    params["address"] = address
    params["type"] = type_.to_json()
    params["code"] = code
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.simulateGATTOperationResponse",
        "params": params,
    }
    json = yield cmd_dict


def simulate_characteristic_operation_response(
    characteristic_id: str,
    type_: CharacteristicOperationType,
    code: int,
    data: typing.Optional[str] = None,
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Simulates the response from the characteristic with ``characteristicId`` for a
    characteristic operation of ``type``. The ``code`` value follows the Error
    Codes from Bluetooth Core Specification Vol 3 Part F 3.4.1.1 Error Response.
    The ``data`` is expected to exist when simulating a successful read operation
    response.

    :param characteristic_id:
    :param type_:
    :param code:
    :param data: *(Optional)*
    """
    params: T_JSON_DICT = dict()
    params["characteristicId"] = characteristic_id
    params["type"] = type_.to_json()
    params["code"] = code
    if data is not None:
        params["data"] = data
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.simulateCharacteristicOperationResponse",
        "params": params,
    }
    json = yield cmd_dict


def simulate_descriptor_operation_response(
    descriptor_id: str,
    type_: DescriptorOperationType,
    code: int,
    data: typing.Optional[str] = None,
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Simulates the response from the descriptor with ``descriptorId`` for a
    descriptor operation of ``type``. The ``code`` value follows the Error
    Codes from Bluetooth Core Specification Vol 3 Part F 3.4.1.1 Error Response.
    The ``data`` is expected to exist when simulating a successful read operation
    response.

    :param descriptor_id:
    :param type_:
    :param code:
    :param data: *(Optional)*
    """
    params: T_JSON_DICT = dict()
    params["descriptorId"] = descriptor_id
    params["type"] = type_.to_json()
    params["code"] = code
    if data is not None:
        params["data"] = data
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.simulateDescriptorOperationResponse",
        "params": params,
    }
    json = yield cmd_dict


def add_service(
    address: str, service_uuid: str
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, str]:
    """
    Adds a service with ``serviceUuid`` to the peripheral with ``address``.

    :param address:
    :param service_uuid:
    :returns: An identifier that uniquely represents this service.
    """
    params: T_JSON_DICT = dict()
    params["address"] = address
    params["serviceUuid"] = service_uuid
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.addService",
        "params": params,
    }
    json = yield cmd_dict
    return str(json["serviceId"])


def remove_service(service_id: str) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Removes the service respresented by ``serviceId`` from the simulated central.

    :param service_id:
    """
    params: T_JSON_DICT = dict()
    params["serviceId"] = service_id
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.removeService",
        "params": params,
    }
    json = yield cmd_dict


def add_characteristic(
    service_id: str, characteristic_uuid: str, properties: CharacteristicProperties
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, str]:
    """
    Adds a characteristic with ``characteristicUuid`` and ``properties`` to the
    service represented by ``serviceId``.

    :param service_id:
    :param characteristic_uuid:
    :param properties:
    :returns: An identifier that uniquely represents this characteristic.
    """
    params: T_JSON_DICT = dict()
    params["serviceId"] = service_id
    params["characteristicUuid"] = characteristic_uuid
    params["properties"] = properties.to_json()
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.addCharacteristic",
        "params": params,
    }
    json = yield cmd_dict
    return str(json["characteristicId"])


def remove_characteristic(
    characteristic_id: str,
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Removes the characteristic respresented by ``characteristicId`` from the
    simulated central.

    :param characteristic_id:
    """
    params: T_JSON_DICT = dict()
    params["characteristicId"] = characteristic_id
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.removeCharacteristic",
        "params": params,
    }
    json = yield cmd_dict


def add_descriptor(
    characteristic_id: str, descriptor_uuid: str
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, str]:
    """
    Adds a descriptor with ``descriptorUuid`` to the characteristic respresented
    by ``characteristicId``.

    :param characteristic_id:
    :param descriptor_uuid:
    :returns: An identifier that uniquely represents this descriptor.
    """
    params: T_JSON_DICT = dict()
    params["characteristicId"] = characteristic_id
    params["descriptorUuid"] = descriptor_uuid
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.addDescriptor",
        "params": params,
    }
    json = yield cmd_dict
    return str(json["descriptorId"])


def remove_descriptor(
    descriptor_id: str,
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Removes the descriptor with ``descriptorId`` from the simulated central.

    :param descriptor_id:
    """
    params: T_JSON_DICT = dict()
    params["descriptorId"] = descriptor_id
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.removeDescriptor",
        "params": params,
    }
    json = yield cmd_dict


def simulate_gatt_disconnection(
    address: str,
) -> typing.Generator[T_JSON_DICT, T_JSON_DICT, None]:
    """
    Simulates a GATT disconnection from the peripheral with ``address``.

    :param address:
    """
    params: T_JSON_DICT = dict()
    params["address"] = address
    cmd_dict: T_JSON_DICT = {
        "method": "BluetoothEmulation.simulateGATTDisconnection",
        "params": params,
    }
    json = yield cmd_dict


@event_class("BluetoothEmulation.gattOperationReceived")
@dataclass
class GattOperationReceived:
    """
    Event for when a GATT operation of ``type`` to the peripheral with ``address``
    happened.
    """

    address: str
    type_: GATTOperationType

    @classmethod
    def from_json(cls, json: T_JSON_DICT) -> GattOperationReceived:
        return cls(
            address=str(json["address"]),
            type_=GATTOperationType.from_json(json["type"]),
        )


@event_class("BluetoothEmulation.characteristicOperationReceived")
@dataclass
class CharacteristicOperationReceived:
    """
    Event for when a characteristic operation of ``type`` to the characteristic
    respresented by ``characteristicId`` happened. ``data`` and ``writeType`` is
    expected to exist when ``type`` is write.
    """

    characteristic_id: str
    type_: CharacteristicOperationType
    data: typing.Optional[str]
    write_type: typing.Optional[CharacteristicWriteType]

    @classmethod
    def from_json(cls, json: T_JSON_DICT) -> CharacteristicOperationReceived:
        return cls(
            characteristic_id=str(json["characteristicId"]),
            type_=CharacteristicOperationType.from_json(json["type"]),
            data=str(json["data"]) if json.get("data", None) is not None else None,
            write_type=CharacteristicWriteType.from_json(json["writeType"])
            if json.get("writeType", None) is not None
            else None,
        )


@event_class("BluetoothEmulation.descriptorOperationReceived")
@dataclass
class DescriptorOperationReceived:
    """
    Event for when a descriptor operation of ``type`` to the descriptor
    respresented by ``descriptorId`` happened. ``data`` is expected to exist when
    ``type`` is write.
    """

    descriptor_id: str
    type_: CharacteristicOperationType
    data: typing.Optional[str]

    @classmethod
    def from_json(cls, json: T_JSON_DICT) -> DescriptorOperationReceived:
        return cls(
            descriptor_id=str(json["descriptorId"]),
            type_=CharacteristicOperationType.from_json(json["type"]),
            data=str(json["data"]) if json.get("data", None) is not None else None,
        )
