class Token(object):
    """Token class."""

    AUTH_HEADER_NAME = 'Authorization'
    AUTH_HEADER_VALUE_PREFIX = 'Bearer '

    def __init__(self, api, auth):
        self._api = api
        self._login = auth.get('login')
        self._password = auth.get('password')
        self._refresh_token = auth.get('refresh_token')
        self._access_token = auth.get('access_token')

    def _auth(self):
        api_request = ApiRequest(self._api)
        if not api_request.websocket_transport:
            return
        api_request.action('authenticate')
        api_request.set('token', self._access_token)
        api_request.execute('Authentication failure.')

    def _tokens(self):
        api_request = ApiRequest(self._api)
        api_request.method('POST')
        api_request.url('token')
        api_request.action('token')
        api_request.set('login', self._login)
        api_request.set('password', self._password)
        tokens = api_request.execute('Login failure.')
        self._refresh_token = tokens['refreshToken']
        self._access_token = tokens['accessToken']

    @property
    def access_token(self):
        return self._access_token

    @property
    def auth_header(self):
        auth_header_name = self.AUTH_HEADER_NAME
        auth_header_value = self.AUTH_HEADER_VALUE_PREFIX + self._access_token
        return auth_header_name, auth_header_value

    def refresh(self):
        if not self._refresh_token:
            raise TokenError('Can\'t refresh token without "refresh_token"')
        api_request = ApiRequest(self._api)
        api_request.method('POST')
        api_request.url('token/refresh')
        api_request.action('token/refresh')
        api_request.set('refreshToken', self._refresh_token)
        tokens = api_request.execute('Token refresh failure.')
        self._access_token = tokens['accessToken']

    def auth(self):
        if self._refresh_token:
            self.refresh()
            self._auth()
            return
        if self._access_token:
            self._auth()
            return
        if self._login and self._password:
            self._tokens()
            self._auth()
            return
        if self._login:
            raise TokenError('Password required.')
        if self._password:
            raise TokenError('Login required.') class ApiRequest(object):
    """Api request class."""

    def __init__(self, api):
        self._api = api
        self._action = None
        self._request = {}
        self._params = {'subscription_request': {},
                        'response_subscription_id_key': 'subscriptionId',
                        'remove_subscription_request': {},
                        'method': 'GET',
                        'url': None,
                        'request_delete_keys': [],
                        'request_key': None,
                        'params': {},
                        'headers': {},
                        'response_key': None}

    @staticmethod
    def _uuid():
        return str(uuid.uuid4())

    @property
    def http_transport(self):
        return self._api.transport.name == 'http'

    @property
    def websocket_transport(self):
        return self._api.transport.name == 'websocket'

    def action(self, action):
        self._action = action

    def set(self, key, value, request_key=False):
        if not value:
            return
        self._request[key] = value
        if not request_key:
            return
        self._params['request_key'] = key

    def subscription_request(self, subscription_api_request):
        request = subscription_api_request.extract(self._uuid(), self._uuid())
        self._params['subscription_request'] = request

    def response_subscription_id_key(self, key):
        self._params['response_subscription_id_key'] = key

    def remove_subscription_request(self, remove_subscription_api_request):
        request = remove_subscription_api_request.extract()
        self._params['remove_subscription_request'] = request

    def method(self, method):
        self._params['method'] = method

    def url(self, url, **args):
        for key in args:
            value = args[key]
            url = url.replace('{%s}' % key, str(value))
            self._request[key] = value
            self._params['request_delete_keys'].append(key)
        self._params['url'] = url

    def param(self, key, value):
        if not value:
            return
        self._request[key] = value
        self._params['request_delete_keys'].append(key)
        self._params['params'][key] = value

    def header(self, name, value):
        self._params['headers'][name] = value

    def response_key(self, key):
        self._params['response_key'] = key

    def execute(self, error_message):
        request_id = self._uuid()
        request = self._request.copy()
        logger.debug('Request id: %s. Action: %s. Request: %s. Params: %s.',
                     request_id, self._action, request, self._params)
        response = self._api.transport.request(request_id, self._action,
                                               request, **self._params)
        api_response = ApiResponse(response, self._params['response_key'])
        logger.debug('Response id: %s. Action: %s. Success: %s. Response: %s.',
                     api_response.id, api_response.action, api_response.success,
                     api_response.response)
        if api_response.success:
            return api_response.response
        raise ApiResponseError(error_message, self._api.transport.name,
                               api_response.code, api_response.error) class AuthApiRequest(ApiRequest):
    """Auth api request class."""

    def execute(self, error_message):
        self.header(*self._api.token.auth_header)
        try:
            return super(AuthApiRequest, self).execute(error_message)
        except ApiResponseError as api_response_error:
            if api_response_error.code != 401:
                raise
        self._api.token.auth()
        self.header(*self._api.token.auth_header)
        return super(AuthApiRequest, self).execute(error_message) class AuthSubscriptionApiRequest(SubscriptionApiRequest):
    """Auth subscription api request class."""

    def __init__(self, api):
        super(AuthSubscriptionApiRequest, self).__init__()
        auth_header_name, auth_header_value = api.token.auth_header
        self._params['headers'][auth_header_name] = auth_header_value
        self._params['response_error_handler'] = self.response_error_handler
        self._params['response_error_handler_args'] = [api.token]

    @staticmethod
    def response_error_handler(params, response_code, token):
        if response_code != 401:
            return
        try:
            token.auth()
            auth_header_name, auth_header_value = token.auth_header
            params['headers'][auth_header_name] = auth_header_value
            return True
        except ApiResponseError:
            return class Device(object):
    """Device class."""

    ID_KEY = 'id'
    NAME_KEY = 'name'
    DATA_KEY = 'data'
    NETWORK_ID_KEY = 'networkId'
    DEVICE_TYPE_ID_KEY = 'deviceTypeId'
    IS_BLOCKED_KEY = 'isBlocked'

    def __init__(self, api, device=None):
        self._api = api
        self._id = None
        self.name = None
        self.data = None
        self.network_id = None
        self.device_type_id = None
        self.is_blocked = None
        if device:
            self._init(device)

    def _init(self, device):
        self._id = device[self.ID_KEY]
        self.name = device[self.NAME_KEY]
        self.data = device[self.DATA_KEY]
        self.network_id = device[self.NETWORK_ID_KEY]
        self.device_type_id = device[self.DEVICE_TYPE_ID_KEY]
        self.is_blocked = device[self.IS_BLOCKED_KEY]

    def _ensure_exists(self):
        if self._id:
            return
        raise DeviceError('Device does not exist.')

    @property
    def id(self):
        return self._id

    def get(self, device_id):
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.url('device/{deviceId}', deviceId=device_id)
        auth_api_request.action('device/get')
        auth_api_request.response_key('device')
        device = auth_api_request.execute('Device get failure.')
        self._init(device)

    def save(self):
        self._ensure_exists()
        device = {self.NAME_KEY: self.name,
                  self.DATA_KEY: self.data,
                  self.NETWORK_ID_KEY: self.network_id,
                  self.DEVICE_TYPE_ID_KEY: self.device_type_id,
                  self.IS_BLOCKED_KEY: self.is_blocked}
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('PUT')
        auth_api_request.url('device/{deviceId}', deviceId=self._id)
        auth_api_request.action('device/save')
        auth_api_request.set('device', device, True)
        auth_api_request.execute('Device save failure.')

    def remove(self):
        self._ensure_exists()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('DELETE')
        auth_api_request.url('device/{deviceId}', deviceId=self._id)
        auth_api_request.action('device/delete')
        auth_api_request.execute('Device remove failure.')
        self._id = None
        self.name = None
        self.data = None
        self.network_id = None
        self.device_type_id = None
        self.is_blocked = None

    def subscribe_insert_commands(self, names=(), timestamp=None):
        self._ensure_exists()
        return self._api.subscribe_insert_commands(self.id, names=names,
                                                   timestamp=timestamp)

    def subscribe_update_commands(self, names=(), timestamp=None):
        self._ensure_exists()
        return self._api.subscribe_update_commands(self.id, names=names,
                                                   timestamp=timestamp)

    def list_commands(self, start=None, end=None, command=None, status=None,
                      sort_field=None, sort_order=None, take=None, skip=None):
        self._ensure_exists()
        return self._api.list_commands(device_id=self._id, start=start, end=end,
                                       command=command, status=status,
                                       sort_field=sort_field,
                                       sort_order=sort_order,
                                       take=take, skip=skip)

    def send_command(self, command_name, parameters=None, lifetime=None,
                     timestamp=None, status=None, result=None):
        self._ensure_exists()
        return self._api.send_command(device_id=self._id,
                                      command_name=command_name,
                                      parameters=parameters, lifetime=lifetime,
                                      timestamp=timestamp, status=status,
                                      result=result)

    def subscribe_notifications(self, names=(), timestamp=None):
        self._ensure_exists()
        return self._api.subscribe_notifications(self.id, names=names,
                                                 timestamp=timestamp)

    def list_notifications(self, start=None, end=None, notification=None,
                           sort_field=None, sort_order=None, take=None,
                           skip=None):
        self._ensure_exists()
        return self._api.list_notifications(device_id=self._id, start=start,
                                            end=end,
                                            notification=notification,
                                            sort_field=sort_field,
                                            sort_order=sort_order,
                                            take=take, skip=skip)

    def send_notification(self, notification_name, parameters=None,
                          timestamp=None):
        self._ensure_exists()
        return self._api.send_notification(device_id=self._id,
                                           notification_name=notification_name,
                                           parameters=parameters,
                                           timestamp=timestamp) class Command(object):
    """Command class."""

    DEVICE_ID_KEY = 'deviceId'
    ID_KEY = 'id'
    USER_ID_KEY = 'userId'
    COMMAND_KEY = 'command'
    PARAMETERS_KEY = 'parameters'
    LIFETIME_KEY = 'lifetime'
    TIMESTAMP_KEY = 'timestamp'
    LAST_UPDATED_KEY = 'lastUpdated'
    STATUS_KEY = 'status'
    RESULT_KEY = 'result'

    def __init__(self, api, command):
        self._api = api
        self._device_id = command[self.DEVICE_ID_KEY]
        self._id = command[self.ID_KEY]
        self._user_id = command[self.USER_ID_KEY]
        self._command = command[self.COMMAND_KEY]
        self._parameters = command[self.PARAMETERS_KEY]
        self._lifetime = command[self.LIFETIME_KEY]
        self._timestamp = command[self.TIMESTAMP_KEY]
        self._last_updated = command[self.LAST_UPDATED_KEY]
        self.status = command[self.STATUS_KEY]
        self.result = command[self.RESULT_KEY]

    @property
    def device_id(self):
        return self._device_id

    @property
    def id(self):
        return self._id

    @property
    def user_id(self):
        return self._user_id

    @property
    def command(self):
        return self._command

    @property
    def parameters(self):
        return self._parameters

    @property
    def lifetime(self):
        return self._lifetime

    @property
    def timestamp(self):
        return self._timestamp

    def last_updated(self):
        return self._last_updated

    def save(self):
        command = {self.STATUS_KEY: self.status, self.RESULT_KEY: self.result}
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('PUT')
        auth_api_request.url('device/{deviceId}/command/{commandId}',
                             deviceId=self._device_id, commandId=self._id)
        auth_api_request.action('command/update')
        auth_api_request.set('command', command, True)
        auth_api_request.execute('Command save failure.') class Notification(object):
    """Notification class."""

    DEVICE_ID_KEY = 'deviceId'
    ID_KEY = 'id'
    NOTIFICATION_KEY = 'notification'
    PARAMETERS_KEY = 'parameters'
    TIMESTAMP_KEY = 'timestamp'

    def __init__(self, notification):
        self._device_id = notification[self.DEVICE_ID_KEY]
        self._id = notification[self.ID_KEY]
        self._notification = notification[self.NOTIFICATION_KEY]
        self._parameters = notification[self.PARAMETERS_KEY]
        self._timestamp = notification[self.TIMESTAMP_KEY]

    @property
    def device_id(self):
        return self._device_id

    @property
    def id(self):
        return self._id

    @property
    def notification(self):
        return self._notification

    @property
    def parameters(self):
        return self._parameters

    @property
    def timestamp(self):
        return self._timestamp class CommandsSubscription(BaseSubscription):
    """CommandsSubscription class"""

    def _get_subscription_type(self):
        return 'command' class NotificationsSubscription(BaseSubscription):
    """NotificationsSubscription class"""

    def _get_subscription_type(self):
        return 'notification' class Network(object):
    """Network class."""

    ID_KEY = 'id'
    NAME_KEY = 'name'
    DESCRIPTION_KEY = 'description'

    def __init__(self, api, network=None):
        self._api = api
        self._id = None
        self.name = None
        self.description = None
        if network:
            self._init(network)

    def _init(self, device):
        self._id = device[self.ID_KEY]
        self.name = device[self.NAME_KEY]
        self.description = device[self.DESCRIPTION_KEY]

    def _ensure_exists(self):
        if self._id:
            return
        raise NetworkError('Network does not exist.')

    @property
    def id(self):
        return self._id

    def get(self, network_id):
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.url('network/{networkId}', networkId=network_id)
        auth_api_request.action('network/get')
        auth_api_request.response_key('network')
        network = auth_api_request.execute('Network get failure.')
        self._init(network)

    def save(self):
        self._ensure_exists()
        network = {self.ID_KEY: self._id,
                   self.NAME_KEY: self.name,
                   self.DESCRIPTION_KEY: self.description}
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('PUT')
        auth_api_request.url('network/{networkId}', networkId=self._id)
        auth_api_request.action('network/update')
        auth_api_request.set('network', network, True)
        auth_api_request.execute('Network save failure.')

    def remove(self, force=False):
        self._ensure_exists()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('DELETE')
        auth_api_request.url('network/{networkId}', networkId=self._id)
        auth_api_request.action('network/delete')
        auth_api_request.param('force', force)
        auth_api_request.execute('Network remove failure.')
        self._id = None
        self.name = None
        self.description = None

    def list_devices(self, name=None, name_pattern=None, sort_field=None,
                     sort_order=None, take=None, skip=None):
        self._ensure_exists()
        return self._api.list_devices(name, name_pattern, self._id, self.name,
                                      sort_field, sort_order, take, skip)

    def subscribe_insert_commands(self, names=(), timestamp=None):
        self._ensure_exists()
        return self._api.subscribe_insert_commands(network_ids=[self.id],
                                                   names=names,
                                                   timestamp=timestamp)

    def subscribe_update_commands(self, names=(), timestamp=None):
        self._ensure_exists()
        return self._api.subscribe_update_commands(network_ids=[self.id],
                                                   names=names,
                                                   timestamp=timestamp)

    def subscribe_notifications(self, names=(), timestamp=None):
        self._ensure_exists()
        return self._api.subscribe_notifications(network_ids=[self.id],
                                                 names=names,
                                                 timestamp=timestamp) class DeviceType(object):
    """DeviceType class."""

    ID_KEY = 'id'
    NAME_KEY = 'name'
    DESCRIPTION_KEY = 'description'

    def __init__(self, api, device_type=None):
        self._api = api
        self._id = None
        self.name = None
        self.description = None
        if device_type:
            self._init(device_type)

    def _init(self, device_type):
        self._id = device_type[self.ID_KEY]
        self.name = device_type[self.NAME_KEY]
        self.description = device_type[self.DESCRIPTION_KEY]

    def _ensure_exists(self):
        if self._id:
            return
        raise DeviceTypeError('DeviceType does not exist.')

    @property
    def id(self):
        return self._id

    def get(self, device_type_id):
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.url('devicetype/{deviceTypeId}',
                             deviceTypeId=device_type_id)
        auth_api_request.action('devicetype/get')
        auth_api_request.response_key('deviceType')
        devicetype = auth_api_request.execute('DeviceType get failure.')
        self._init(devicetype)

    def save(self):
        self._ensure_exists()
        device_type = {self.ID_KEY: self._id,
                       self.NAME_KEY: self.name,
                       self.DESCRIPTION_KEY: self.description}
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('PUT')
        auth_api_request.url('devicetype/{deviceTypeId}', deviceTypeId=self._id)
        auth_api_request.action('devicetype/update')
        auth_api_request.set('deviceType', device_type, True)
        auth_api_request.execute('DeviceType save failure.')

    def remove(self, force=False):
        self._ensure_exists()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('DELETE')
        auth_api_request.url('devicetype/{deviceTypeId}', deviceTypeId=self._id)
        auth_api_request.action('devicetype/delete')
        auth_api_request.param('force', force)
        auth_api_request.execute('DeviceType remove failure.')
        self._id = None
        self.name = None
        self.description = None

    def list_devices(self, name=None, name_pattern=None, sort_field=None,
                     sort_order=None, take=None, skip=None):
        self._ensure_exists()
        return self._api.list_devices(name, name_pattern, self._id, self.name,
                                      sort_field, sort_order, take, skip)

    def subscribe_insert_commands(self, names=(), timestamp=None):
        self._ensure_exists()
        return self._api.subscribe_insert_commands(
            device_type_ids=[self.id], names=names, timestamp=timestamp)

    def subscribe_update_commands(self, names=(), timestamp=None):
        self._ensure_exists()
        return self._api.subscribe_update_commands(
            device_type_ids=[self.id], names=names, timestamp=timestamp)

    def subscribe_notifications(self, names=(), timestamp=None):
        self._ensure_exists()
        return self._api.subscribe_notifications(device_type_ids=[self.id],
                                                 names=names,
                                                 timestamp=timestamp) class User(object):
    """User class."""

    ID_KEY = 'id'
    LOGIN_KEY = 'login'
    LAST_LOGIN_KEY = 'lastLogin'
    INTRO_REVIEWED_KEY = 'introReviewed'
    ROLE_KEY = 'role'
    STATUS_KEY = 'status'
    DATA_KEY = 'data'
    PASSWORD_KEY = 'password'
    NETWORKS_KEY = 'networks'
    ALL_DEVICE_TYPES_KEY = 'allDeviceTypesAvailable'
    ADMINISTRATOR_ROLE = 0
    CLIENT_ROLE = 1
    ACTIVE_STATUS = 0
    LOCKED_STATUS = 1
    DISABLED_STATUS = 2

    def __init__(self, api, user=None):
        self._api = api
        self._id = None
        self._login = None
        self._last_login = None
        self._intro_reviewed = None
        self._all_device_types_available = None
        self.role = None
        self.status = None
        self.data = None

        if user:
            self._init(user)

    def _init(self, user):
        self._id = user[self.ID_KEY]
        self._login = user[self.LOGIN_KEY]
        self._last_login = user[self.LAST_LOGIN_KEY]
        self._intro_reviewed = user[self.INTRO_REVIEWED_KEY]
        self._all_device_types_available = user[self.ALL_DEVICE_TYPES_KEY]
        self.role = user[self.ROLE_KEY]
        self.status = user[self.STATUS_KEY]
        self.data = user[self.DATA_KEY]

    def _ensure_exists(self):
        if self._id:
            return
        raise UserError('User does not exist.')

    def _ensure_all_device_types_available(self):
        if self._all_device_types_available:
            return
        raise UserError('User does not have access to all device types.')

    def _ensure_not_all_device_types_available(self):
        if not self._all_device_types_available:
            return
        raise UserError('User have access to all device types.')

    @property
    def id(self):
        return self._id

    @property
    def login(self):
        return self._login

    @property
    def last_login(self):
        return self._last_login

    @property
    def intro_reviewed(self):
        return self._intro_reviewed

    @property
    def all_device_types_available(self):
        return self._all_device_types_available

    def get_current(self):
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.url('user/current')
        auth_api_request.action('user/getCurrent')
        auth_api_request.response_key('current')
        user = auth_api_request.execute('Current user get failure.')
        self._init(user)

    def get(self, user_id):
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.url('user/{userId}', userId=user_id)
        auth_api_request.action('user/get')
        auth_api_request.response_key('user')
        user = auth_api_request.execute('User get failure.')
        self._init(user)

    def save(self):
        self._ensure_exists()
        user = {self.ROLE_KEY: self.role,
                self.STATUS_KEY: self.status,
                self.DATA_KEY: self.data}
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('PUT')
        auth_api_request.url('user/{userId}', userId=self._id)
        auth_api_request.action('user/update')
        auth_api_request.set('user', user, True)
        auth_api_request.execute('User save failure.')

    def update_password(self, password):
        self._ensure_exists()
        user = {self.PASSWORD_KEY: password}
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('PUT')
        auth_api_request.url('user/{userId}', userId=self._id)
        auth_api_request.action('user/update')
        auth_api_request.set('user', user, True)
        auth_api_request.execute('User password update failure.')

    def remove(self):
        self._ensure_exists()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('DELETE')
        auth_api_request.url('user/{userId}', userId=self._id)
        auth_api_request.action('user/delete')
        auth_api_request.execute('User remove failure.')
        self._id = None
        self._login = None
        self._last_login = None
        self._intro_reviewed = None
        self._all_device_types_available = None
        self.role = None
        self.status = None
        self.data = None

    def list_networks(self):
        self._ensure_exists()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.url('user/{userId}', userId=self._id)
        auth_api_request.action('user/get')
        auth_api_request.response_key('user')
        user = auth_api_request.execute('List networks failure.')
        return [Network(self._api, network)
                for network in user[User.NETWORKS_KEY]]

    def assign_network(self, network_id):
        self._ensure_exists()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('PUT')
        auth_api_request.url('user/{userId}/network/{networkId}',
                             userId=self._id, networkId=network_id)
        auth_api_request.action('user/assignNetwork')
        auth_api_request.execute('Assign network failure.')

    def unassign_network(self, network_id):
        self._ensure_exists()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('DELETE')
        auth_api_request.url('user/{userId}/network/{networkId}',
                             userId=self._id, networkId=network_id)
        auth_api_request.action('user/unassignNetwork')
        auth_api_request.execute('Unassign network failure.')

    def list_device_types(self):
        self._ensure_exists()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.url('user/{userId}/devicetype', userId=self._id)
        auth_api_request.action('user/getDeviceTypes')
        auth_api_request.response_key('deviceTypes')
        device_types = auth_api_request.execute('List device types failure.')
        return [DeviceType(self._api, device_type)
                for device_type in device_types]

    def allow_all_device_types(self):
        self._ensure_exists()
        self._ensure_not_all_device_types_available()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('PUT')
        auth_api_request.url('user/{userId}/devicetype/all', userId=self._id)
        auth_api_request.action('user/allowAllDeviceTypes')
        auth_api_request.execute('Assign all device types failure.')
        self._all_device_types_available = True

    def disallow_all_device_types(self):
        self._ensure_exists()
        self._ensure_all_device_types_available()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('DELETE')
        auth_api_request.url('user/{userId}/devicetype/all', userId=self._id)
        auth_api_request.action('user/disallowAllDeviceTypes')
        auth_api_request.execute('Unassign device type failure.')
        self._all_device_types_available = False

    def assign_device_type(self, device_type_id):
        self._ensure_exists()
        self._ensure_not_all_device_types_available()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('PUT')
        auth_api_request.url('user/{userId}/devicetype/{deviceTypeId}',
                             userId=self._id, deviceTypeId=device_type_id)
        auth_api_request.action('user/assignDeviceType')
        auth_api_request.execute('Assign device type failure.')

    def unassign_device_type(self, device_type_id):
        self._ensure_exists()
        self._ensure_not_all_device_types_available()
        auth_api_request = AuthApiRequest(self._api)
        auth_api_request.method('DELETE')
        auth_api_request.url('user/{userId}/devicetype/{deviceTypeId}',
                             userId=self._id, deviceTypeId=device_type_id)
        auth_api_request.action('user/unassignDeviceType')
        auth_api_request.execute('Unassign device type failure.')
from devicehive.token import Token
from devicehive.api_request import ApiRequest
from devicehive.api_request import AuthApiRequest
from devicehive.api_request import AuthSubscriptionApiRequest
from devicehive.device import Device
from devicehive.command import Command
from devicehive.notification import Notification
from devicehive.subscription import CommandsSubscription, \
    NotificationsSubscription
from devicehive.network import Network
from devicehive.device_type import DeviceType
from devicehive.user import User

    def list_devices(self, name=None, name_pattern=None, network_id=None,
                     network_name=None, sort_field=None, sort_order=None,
                     take=None, skip=None):
        auth_api_request = AuthApiRequest(self)
        auth_api_request.url('device')
        auth_api_request.action('device/list')
        auth_api_request.param('name', name)
        auth_api_request.param('namePattern', name_pattern)
        auth_api_request.param('networkId', network_id)
        auth_api_request.param('networkName', network_name)
        auth_api_request.param('sortField', sort_field)
        auth_api_request.param('sortOrder', sort_order)
        auth_api_request.param('take', take)
        auth_api_request.param('skip', skip)
        auth_api_request.response_key('devices')
        devices = auth_api_request.execute('List devices failure.')
        return [Device(self, device) for device in devices]

    def get_device(self, device_id):
        device = Device(self)
        device.get(device_id)
        return device

    def put_device(self, device_id, name=None, data=None, network_id=None,
                   device_type_id=None, is_blocked=False):
        if not name:
            name = device_id
        device = {Device.ID_KEY: device_id,
                  Device.NAME_KEY: name,
                  Device.DATA_KEY: data,
                  Device.NETWORK_ID_KEY: network_id,
                  Device.DEVICE_TYPE_ID_KEY: device_type_id,
                  Device.IS_BLOCKED_KEY: is_blocked}
        device = Device(self, device)
        device.save()
        device.get(device_id)
        return device

    def list_commands(self, device_id, start=None, end=None, command=None,
                      status=None, sort_field=None, sort_order=None, take=None,
                      skip=None):
        auth_api_request = AuthApiRequest(self)
        auth_api_request.url('device/{deviceId}/command', deviceId=device_id)
        auth_api_request.action('command/list')
        auth_api_request.param('start', start)
        auth_api_request.param('end', end)
        auth_api_request.param('command', command)
        auth_api_request.param('status', status)
        auth_api_request.param('sortField', sort_field)
        auth_api_request.param('sortOrder', sort_order)
        auth_api_request.param('take', take)
        auth_api_request.param('skip', skip)
        auth_api_request.response_key('commands')
        commands = auth_api_request.execute('List commands failure.')
        return [Command(self, command) for command in commands]

    def send_command(self, device_id, command_name, parameters=None,
                     lifetime=None, timestamp=None, status=None, result=None):
        command = {Command.COMMAND_KEY: command_name}
        if parameters:
            command[Command.PARAMETERS_KEY] = parameters
        if lifetime:
            command[Command.LIFETIME_KEY] = lifetime
        if timestamp:
            command[Command.TIMESTAMP_KEY] = timestamp
        if status:
            command[Command.STATUS_KEY] = status
        if result:
            command[Command.RESULT_KEY] = result
        auth_api_request = AuthApiRequest(self)
        auth_api_request.method('POST')
        auth_api_request.url('device/{deviceId}/command', deviceId=device_id)
        auth_api_request.action('command/insert')
        auth_api_request.set('command', command, True)
        auth_api_request.response_key('command')
        command = auth_api_request.execute('Command send failure.')
        command[Command.DEVICE_ID_KEY] = device_id
        command[Command.COMMAND_KEY] = command_name
        command[Command.PARAMETERS_KEY] = parameters
        command[Command.LIFETIME_KEY] = lifetime
        command[Command.STATUS_KEY] = status
        command[Command.RESULT_KEY] = result
        return Command(self, command)

    def list_notifications(self, device_id, start=None, end=None,
                           notification=None, sort_field=None, sort_order=None,
                           take=None, skip=None):
        auth_api_request = AuthApiRequest(self)
        auth_api_request.url('device/{deviceId}/notification',
                             deviceId=device_id)
        auth_api_request.action('notification/list')
        auth_api_request.param('start', start)
        auth_api_request.param('end', end)
        auth_api_request.param('notification', notification)
        auth_api_request.param('sortField', sort_field)
        auth_api_request.param('sortOrder', sort_order)
        auth_api_request.param('take', take)
        auth_api_request.param('skip', skip)
        auth_api_request.response_key('notifications')
        notifications = auth_api_request.execute('List notifications failure.')
        return [Notification(notification) for notification in notifications]

    def send_notification(self, device_id, notification_name, parameters=None,
                          timestamp=None):
        notification = {'notification': notification_name}
        if parameters:
            notification['parameters'] = parameters
        if timestamp:
            notification['timestamp'] = timestamp
        auth_api_request = AuthApiRequest(self)
        auth_api_request.method('POST')
        auth_api_request.url('device/{deviceId}/notification',
                             deviceId=device_id)
        auth_api_request.action('notification/insert')
        auth_api_request.set('notification', notification, True)
        auth_api_request.response_key('notification')
        notification = auth_api_request.execute('Notification send failure.')
        notification[Notification.DEVICE_ID_KEY] = device_id
        notification[Notification.NOTIFICATION_KEY] = notification_name

        notification[Notification.PARAMETERS_KEY] = parameters