# 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
from .util import event_class, T_JSON_DICT
from dataclasses import dataclass
import enum
import typing

class CentralState(enum.Enum):
    '''
    Indicates the various states of Central.
    '''
    ABSENT = "absent"
    POWERED_OFF = "powered-off"
    POWERED_ON = "powered-on"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


class GATTOperationType(enum.Enum):
    '''
    Indicates the various types of GATT event.
    '''
    CONNECTION = "connection"
    DISCOVERY = "discovery"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        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
    data: str

    def to_json(self):
        json = dict()
        json['key'] = self.key
        json['data'] = self.data
        return json

    @classmethod
    def from_json(cls, json):
        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):
        json = 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):
        return cls(
            name=str(json['name']) if 'name' in json else None,
            uuids=[str(i) for i in json['uuids']] if 'uuids' in json else None,
            appearance=int(json['appearance']) if 'appearance' in json else None,
            tx_power=int(json['txPower']) if 'txPower' in json else None,
            manufacturer_data=[ManufacturerData.from_json(i) for i in json['manufacturerData']] if 'manufacturerData' in json 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):
        json = 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):
        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):
        json = 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):
        return cls(
            broadcast=bool(json['broadcast']) if 'broadcast' in json else None,
            read=bool(json['read']) if 'read' in json else None,
            write_without_response=bool(json['writeWithoutResponse']) if 'writeWithoutResponse' in json else None,
            write=bool(json['write']) if 'write' in json else None,
            notify=bool(json['notify']) if 'notify' in json else None,
            indicate=bool(json['indicate']) if 'indicate' in json else None,
            authenticated_signed_writes=bool(json['authenticatedSignedWrites']) if 'authenticatedSignedWrites' in json else None,
            extended_properties=bool(json['extendedProperties']) if 'extendedProperties' in json 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 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(
        address: str,
        service_id: str
    ) -> typing.Generator[T_JSON_DICT,T_JSON_DICT,None]:
    '''
    Removes the service respresented by ``serviceId`` from the peripheral with
    ``address``.

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


def add_characteristic(
        address: str,
        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`` in the peripheral with ``address``.

    :param address:
    :param service_id:
    :param characteristic_uuid:
    :param properties:
    :returns: An identifier that uniquely represents this characteristic.
    '''
    params: T_JSON_DICT = dict()
    params['address'] = address
    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(
        address: str,
        service_id: str,
        characteristic_id: str
    ) -> typing.Generator[T_JSON_DICT,T_JSON_DICT,None]:
    '''
    Removes the characteristic respresented by ``characteristicId`` from the
    service respresented by ``serviceId`` in the peripheral with ``address``.

    :param address:
    :param service_id:
    :param characteristic_id:
    '''
    params: T_JSON_DICT = dict()
    params['address'] = address
    params['serviceId'] = service_id
    params['characteristicId'] = characteristic_id
    cmd_dict: T_JSON_DICT = {
        'method': 'BluetoothEmulation.removeCharacteristic',
        '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'])
        )
