# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Module to get random numbers, strings, etc.

   The values returned by the various functions can be replaced in
   templates to generate test cases.
"""

import math
import random
import sys
import uuid

# This script needs the utils.py and fuzzy_types.py modules in order
# to work. This files are copied by the setup.py script and not checked-in
# next to this code, so we need to disable the style warning.
# pylint: disable=F0401
from resources import utils
from resources import fuzzy_types

import gatt_aliases
import wbt_fakes


# Strings that are used to generate the beginning of a test. The replacement
# fields are replaced by Get*Base() functions below to generate valid test
# cases.
BASIC_BASE = \
    '  return setBluetoothFakeAdapter({fake_adapter_name})\n'\
    '    .then(() => {{\n'

DEVICE_DISCOVERY_BASE = BASIC_BASE + \
    '      return requestDeviceWithKeyDown({{\n'\
    '        filters: [{{services: [{service_uuid}]}}]}});\n'\
    '    }})\n'\
    '    .then(device => {{\n'

CONNECTABLE_BASE = DEVICE_DISCOVERY_BASE + \
    '      return device.gatt.connect();\n'\
    '    }})\n'\
    '    .then(gatt => {{\n'

SERVICE_RETRIEVED_BASE = CONNECTABLE_BASE + \
    '      return gatt.getPrimaryService({service_uuid});\n'\
    '    }})\n'\
    '    .then(services => {{\n'

SERVICES_RETRIEVED_BASE = CONNECTABLE_BASE + \
    '      return gatt.getPrimaryServices({optional_service_uuid});\n'\
    '    }})\n'\
    '    .then(services => {{\n'

CHARACTERISTIC_RETRIEVED_BASE = \
    '      TRANSFORM_PICK_A_SERVICE;\n'\
    '      return service.getCharacteristic({characteristic_uuid});\n'\
    '    }})\n'\
    '    .then(characteristics => {{\n'

CHARACTERISTICS_RETRIEVED_BASE = \
    '      TRANSFORM_PICK_A_SERVICE;\n'\
    '      return service.getCharacteristics({optional_characteristic_uuid});\n'\
    '    }})\n'\
    '    .then(characteristics => {{\n'


def _ToJsStr(s):
    return u'\'{}\''.format(s)


def _get_random_number():
    return utils.UniformExpoInteger(0, sys.maxsize.bit_length() + 1)


def _GetFuzzedJsString(s):
    """Returns a fuzzed string based on |s|.

    Args:
      s: The base string to fuzz.
    Returns:
      A single line string surrounded by quotes.
    """
    while True:
        fuzzed_string = fuzzy_types.FuzzyString(s)
        try:
            fuzzed_string = fuzzed_string.decode('utf8')
        except UnicodeDecodeError:
            print 'Can\'t decode fuzzed string. Trying again.'
        else:
            # Escape 'escape' characters.
            fuzzed_string = fuzzed_string.replace('\\', r'\\')
            # Escape quote characters.
            fuzzed_string = fuzzed_string.replace('\'', r'\'')
            # Put everything in a single line.
            fuzzed_string = '\\n'.join(fuzzed_string.split())
            return _ToJsStr(fuzzed_string)


def _get_array_of_random_ints(max_length, max_value):
    """Returns an string with an array of random integer."""
    length = utils.UniformExpoInteger(0, math.log(max_length, 2))
    exp_max_value = math.log(max_value, 2)
    return '[{}]'.format(', '.join(
        str(utils.UniformExpoInteger(0, exp_max_value)) for _ in xrange(length))
    )


def _get_typed_array():
    """Generates a TypedArray constructor.

    There are nine types of TypedArrays and TypedArray has four constructors.

    Types:
      * Int8Array
      * Int16Array
      * Int32Array
      * Uint8Array
      * Uint16Array
      * Uint32Array
      * Uint8ClampedArray
      * Float32Array
      * Float64Array

    Constructors:

     * new TypedArray(length)
     * new TypedArray(typedArray)
     * new TypedArray(object)
     * new TypedArray(buffer)

    Returns:
      A string made up of a randomly chosen type and argument type from the
      lists above.
    """
    array_type = random.choice(['Int8Array', 'Int16Array', 'Int32Array',
                                'Uint8Array', 'Uint16Array', 'Uint32Array',
                                'Uint8ClampedArray', 'Float32Array',
                                'Float64Array'])

    # Choose an argument type at random.
    arguments = random.choice([
        # length e.g. 293
        # We choose 2**10 as the upper boundry because the max length allowed
        # by WebBluetooth is 2**10.
        lambda: utils.UniformExpoInteger(0, 10),
        # typedArray e.g. new Uint8Array([1,2,3])
        _get_typed_array,
        # object e.g. [1,2,3]
        lambda: _get_array_of_random_ints(max_length=1000, max_value=2 ** 64),
        # buffer e.g. new Uint8Array(10).buffer
        lambda: _get_typed_array() + '.buffer',
    ])

    return 'new {array_type}({arguments})'.format(array_type=array_type,
                                                  arguments=arguments())


def GetAdvertisedServiceUUIDFromFakes():
    """Returns a random service string from the list of fake services."""
    return _ToJsStr(random.choice(wbt_fakes.ADVERTISED_SERVICES))


def get_service_uuid_from_fakes():
    """Returns a random service string from a list of fake services."""
    return _ToJsStr(random.choice(wbt_fakes.SERVICES))


def get_characteristic_uuid_from_fakes():
    """Returns a random characteristic string from a fake characteristics list."""
    return _ToJsStr(random.choice(wbt_fakes.CHARACTERISTICS))


def GetValidServiceAlias():
    """Returns a valid service alias from the list of services aliases."""
    return _ToJsStr(random.choice(gatt_aliases.SERVICES))


def get_valid_characteristic_alias():
    """Returns a valid service alias from the list of services aliases."""
    return _ToJsStr(random.choice(gatt_aliases.CHARACTERISTICS))


def GetRandomUUID():
    """Returns a random UUID, a random number or a fuzzed uuid or alias."""
    choice = random.choice(['uuid', 'number', 'fuzzed string'])
    if choice == 'uuid':
        return _ToJsStr(uuid.uuid4())
    elif choice == 'number':
        return _get_random_number()
    elif choice == 'fuzzed string':
        choice2 = random.choice(['uuid', 'alias'])
        if choice2 == 'uuid':
            random_uuid = str(uuid.uuid4())
            return _GetFuzzedJsString(random_uuid)
        elif choice2 == 'alias':
            alias = random.choice(gatt_aliases.SERVICES)
            return _GetFuzzedJsString(alias)


def GetAdvertisedServiceUUID():
    """Generates a random Service UUID from a set of functions.

    See get_service_uuid_from_fakes(), GetValidServiceAlias() and GetRandomUUID()
    for the different values this function can return.

    This function weights get_service_uuid_from_fakes() more heavily to increase the
    probability of generating test pages that can interact with the fake
    adapters.

    Returns:
      A string or a number that can be used as a Service UUID by the Web
      Bluetooth API.
    """
    roll = random.random()
    if roll < 0.8:
        return GetAdvertisedServiceUUIDFromFakes()
    elif roll < 0.9:
        return GetValidServiceAlias()
    else:
        return GetRandomUUID()


def get_service_uuid():
    """Generates a random Service UUID from a set of functions.

    Similar to GetAdvertisedServiceUUID() but weights get_service_uuid_from_fakes()
    more heavily to increase the  probability of generating test pages that can
    interact with the fake adapters.

    See get_service_uuid_from_fakes(), GetValidServiceAlias() and
    GetRandomUUID() for the different values this function can return.

    Returns:
      A string or a number that can be used as a Service UUID by the Web
      Bluetooth API.
    """
    roll = random.random()
    if roll < 0.8:
        return get_service_uuid_from_fakes()
    elif roll < 0.9:
        return GetValidServiceAlias()
    else:
        return GetRandomUUID()


def get_characteristic_uuid():
    """Generates a random Characteristic UUID from a set of functions.

    Similar to get_service_uuid() but weights get_characteristic_uuid_from_fakes()
    more heavily to increase the  probability of generating test pages that can
    interact with the fake adapters.

    See get_characteristic_uuid_from_fakes(), get_valid_characteristic_alias() and
    GetRandomUUID() for the different values this function can return.

    Returns:
      A string or a number that can be used as a Service UUID by the Web
      Bluetooth API.
    """
    roll = random.random()
    if roll < 0.8:
        return get_characteristic_uuid_from_fakes()
    elif roll < 0.9:
        return get_valid_characteristic_alias()
    else:
        return GetRandomUUID()


def GetRequestDeviceOptions():
    """Returns an object used by navigator.bluetooth.requestDevice."""
    # TODO(ortuno): Randomize the members, number of filters, services, etc.

    return '{filters: [{services: [ %s ]}]}' % GetAdvertisedServiceUUID()


def GetBasicBase():
    """Returns a string that sets a random fake adapter."""
    adapter = _ToJsStr(random.choice(wbt_fakes.ALL_ADAPTERS))
    return BASIC_BASE.format(fake_adapter_name=adapter)


def GetDeviceDiscoveryBase():
    """Generates a string that contains all steps to find a device."""
    adapter, services = random.choice(wbt_fakes.ADAPTERS_WITH_DEVICES)
    return DEVICE_DISCOVERY_BASE.format(
        fake_adapter_name=_ToJsStr(adapter),
        service_uuid=_ToJsStr(random.choice(services)))


def GetConnectableBase():
    """Generates a string that contains all steps to connect to a device.

    Returns: A string that:
      1. Sets an adapter to a fake adapter with a connectable device.
      2. Looks for the connectable device.
      3. Connects to it.
    """
    adapter, services = random.choice(wbt_fakes.ADAPTERS_WITH_DEVICES)
    return DEVICE_DISCOVERY_BASE.format(
        fake_adapter_name=_ToJsStr(adapter),
        service_uuid=_ToJsStr(random.choice(services)))


def get_services_retrieved_base():
    """Returns a string that contains all steps to retrieve a service.

    Returns: A string that:
      1. Sets an adapter to a fake adapter with a connectable device with
         services.
      2. Use one of the device's services to look for that device.
      3. Connects to it.
      4. Retrieve the device's service used in 2.
    """
    adapter, services = random.choice(wbt_fakes.ADAPTERS_WITH_SERVICES)
    service_uuid = _ToJsStr(random.choice(services))

    base = random.choice([SERVICE_RETRIEVED_BASE, SERVICES_RETRIEVED_BASE])
    return base.format(
        fake_adapter_name=_ToJsStr(adapter),
        service_uuid=service_uuid,
        optional_service_uuid=random.choice(['', service_uuid]))


def get_characteristics_retrieved_base():
    """Returns a string that contains all steps to retrieve a characteristic.

      Returns: A string that:
        1. Sets an adapter to a fake adapter with a connectable device with
           services.
        2. Use one of the device's services to look for that device.
        3. Connects to it.
        4. Retrieve the device's service used in 2.
        5. Retrieve a characteristic from that service.
    """
    adapter, services = random.choice(wbt_fakes.ADAPTERS_WITH_CHARACTERISTICS)

    service_uuid, characteristics = random.choice(services)
    service_uuid = _ToJsStr(service_uuid)

    characteristic_uuid = _ToJsStr(random.choice(characteristics))

    optional_service_uuid = random.choice(['', service_uuid])
    optional_characteristic_uuid = random.choice(['', characteristic_uuid])

    services_base = random.choice([SERVICE_RETRIEVED_BASE,
                                   SERVICES_RETRIEVED_BASE])

    characteristics_base = services_base + random.choice([
        CHARACTERISTIC_RETRIEVED_BASE,
        CHARACTERISTICS_RETRIEVED_BASE,
    ])

    return characteristics_base.format(
        fake_adapter_name=_ToJsStr(adapter),
        service_uuid=service_uuid,
        optional_service_uuid=optional_service_uuid,
        characteristic_uuid=characteristic_uuid,
        optional_characteristic_uuid=optional_characteristic_uuid)


def get_get_primary_services_call():
    call = random.choice([u'getPrimaryService({service_uuid})',
                          u'getPrimaryServices({optional_service_uuid})'])

    return call.format(
        service_uuid=get_service_uuid(),
        optional_service_uuid=random.choice(['', get_service_uuid()]))


def get_characteristics_call():
    call = random.choice([
        u'getCharacteristic({characteristic_uuid})',
        u'getCharacteristics({optional_characteristic_uuid})'
    ])

    return call.format(
        characteristic_uuid=get_characteristic_uuid(),
        optional_characteristic_uuid=random.choice(
            ['', get_characteristic_uuid()]))


def get_pick_a_service():
    """Returns a string that picks a service from 'services'."""
    # 'services' may be defined by the GetPrimaryService(s) tokens.
    string = \
        'var service; '\
        'if (typeof services !== \'undefined\') '\
        ' service = Array.isArray(services)'\
        ' ? services[{} % services.length]'\
        ' : services'
    return string.format(random.randint(0, sys.maxint))


def get_pick_a_characteristic():
    """Returns a string that picks a characteristic from 'characteristics'."""
    # 'characteristics' maybe be defined by the GetCharacteristic(s) tokens.
    string = \
        'var characteristic; '\
        'if (typeof characteristics !== \'undefined\') '\
        ' characteristic = Array.isArray(characteristics)'\
        ' ? characteristics[{} % characteristics.length]'\
        ' : characteristics'
    return string.format(random.randint(0, sys.maxint))


def get_reload_id():
    return _ToJsStr(_get_random_number())


def get_buffer_source():
    """Returns a new BufferSource.
    https://heycam.github.io/webidl/#BufferSource
    """

    choice = random.choice(['ArrayBuffer', 'DataView', 'TypedArray'])

    if choice == 'ArrayBuffer':
        # We choose 2**10 as the upper boundry because the max length allowed
        # by WebBluetooth is 2**10.
        return 'new ArrayBuffer({length})'.format(
            length=utils.UniformExpoInteger(0, 10))
    if choice == 'DataView':
        return 'new DataView({typed_array}.buffer)'.format(
            typed_array=_get_typed_array())
    if choice == 'TypedArray':
        return _get_typed_array()
