'use strict';

// Should be large enough to trigger large value handling in the IndexedDB
// engines that have special code paths for large values.
const wrapThreshold = 128 * 1024;

// Returns an IndexedDB value created from a descriptor.
//
// See the bottom of the file for descriptor samples.
function createValue(descriptor) {
  if (typeof(descriptor) != 'object')
    return descriptor;

  if (Array.isArray(descriptor))
    return descriptor.map((element) => createValue(element));

  if (!descriptor.hasOwnProperty('type')) {
    const value = {};
    for (let property of Object.getOwnPropertyNames(descriptor))
      value[property] = createValue(descriptor[property]);
    return value;
  }

  switch (descriptor.type) {
    case 'blob':
      return new Blob(
          [largeValue(descriptor.size, descriptor.seed)],
          { type: descriptor.mimeType });
    case 'buffer':
      return largeValue(descriptor.size, descriptor.seed);
  }
}

// Checks an IndexedDB value against a descriptor.
//
// Returns a Promise that resolves if the value passes the check.
//
// See the bottom of the file for descriptor samples.
function checkValue(testCase, value, descriptor) {
  if (typeof(descriptor) != 'object') {
    assert_equals(
        descriptor, value,
        'IndexedDB result should match put() argument');
    return Promise.resolve();
  }

  if (Array.isArray(descriptor)) {
    assert_true(
        Array.isArray(value),
        'IndexedDB result type should match put() argument');
    assert_equals(
        descriptor.length, value.length,
        'IndexedDB result array size should match put() argument');

    const subChecks = [];
    for (let i = 0; i < descriptor.length; ++i)
      subChecks.push(checkValue(testCase, value[i], descriptor[i]));
    return Promise.all(subChecks);
  }

  if (!descriptor.hasOwnProperty('type')) {
    assert_array_equals(
        Object.getOwnPropertyNames(value).sort(),
        Object.getOwnPropertyNames(descriptor).sort(),
        'IndexedDB result object properties should match put() argument');
    const subChecks = [];
    return Promise.all(Object.getOwnPropertyNames(descriptor).map(property =>
        checkValue(testCase, value[property], descriptor[property])));
  }

  switch (descriptor.type) {
    case 'blob':
      assert_class_string(
          value, 'Blob',
          'IndexedDB result class should match put() argument');
      assert_equals(
          descriptor.mimeType, value.type,
          'IndexedDB result Blob MIME type should match put() argument');
      assert_equals(descriptor.size, value.size, 'incorrect Blob size');
      return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onloadend = testCase.step_func(() => {
          if (reader.error) {
            reject(reader.error);
            return;
          }
          const view = new Uint8Array(reader.result);
          assert_equals(
              view.join(','),
              largeValue(descriptor.size, descriptor.seed).join(','),
              'IndexedDB result Blob content should match put() argument');
          resolve();
        });
        reader.readAsArrayBuffer(value);
      });

    case 'buffer':
      assert_class_string(
          value, 'Uint8Array',
          'IndexedDB result type should match put() argument');
      assert_equals(
          value.join(','),
          largeValue(descriptor.size, descriptor.seed).join(','),
          'IndexedDB result typed array content should match put() argument');
      return Promise.resolve();
  }
}

function cloningTestInternal(label, valueDescriptors, options) {
  promise_test(testCase => {
    return createDatabase(testCase, (database, transaction) => {
      let store;
      if (options.useKeyGenerator) {
        store = database.createObjectStore(
            'test-store', { keyPath: 'primaryKey', autoIncrement: true });
      } else {
        store = database.createObjectStore('test-store');
      }
      for (let i = 0; i < valueDescriptors.length; ++i) {
        if (options.useKeyGenerator) {
          store.put(createValue(valueDescriptors[i]));
        } else {
          store.put(createValue(valueDescriptors[i]), i + 1);
        }
      }
    }).then(database => {
      const transaction = database.transaction(['test-store'], 'readonly');
      const store = transaction.objectStore('test-store');
      const subChecks = [];
      let resultIndex = 0;
      for (let i = 0; i < valueDescriptors.length; ++i) {
        subChecks.push(new Promise((resolve, reject) => {
          const requestIndex = i;
          const primaryKey = requestIndex + 1;
          const request = store.get(primaryKey);
          request.onerror =
              testCase.step_func(() => { reject(request.error); });
          request.onsuccess = testCase.step_func(() => {
            assert_equals(
                resultIndex, requestIndex,
                'IDBRequest success events should be fired in request order');
            ++resultIndex;

            const result = request.result;
            if (options.useKeyGenerator) {
              assert_equals(
                  result.primaryKey, primaryKey,
                  'IndexedDB result should have auto-incremented primary key');
              delete result.primaryKey;
            }
            resolve(checkValue(
                testCase, result, valueDescriptors[requestIndex]));
          });
        }));
      }

      subChecks.push(new Promise((resolve, reject) => {
        const requestIndex = valueDescriptors.length;
        const request = store.getAll();
        request.onerror =
            testCase.step_func(() => { reject(request.error); });
        request.onsuccess = testCase.step_func(() => {
          assert_equals(
              resultIndex, requestIndex,
              'IDBRequest success events should be fired in request order');
          ++resultIndex;
          const result = request.result;
          if (options.useKeyGenerator) {
            for (let i = 0; i < valueDescriptors.length; ++i) {
              const primaryKey = i + 1;
              assert_equals(
                  result[i].primaryKey, primaryKey,
                  'IndexedDB result should have auto-incremented primary key');
              delete result[i].primaryKey;
            }
          }
          resolve(checkValue(testCase, result, valueDescriptors));
        });
      }));

      return Promise.all(subChecks);
    });
  }, label);
}

// Performs a series of put()s and verifies that get()s and getAll() match.
//
// Each element of the valueDescriptors array is fed into createValue(), and the
// resulting value is written to IndexedDB via a put() request. After the writes
// complete, the values are read in the same order in which they were written.
// Last, all the results are read one more time via a getAll().
//
// The test verifies that the get() / getAll() results match the arguments to
// put() and that the order in which the get() result events are fired matches
// the order of the get() requests.
function cloningTest(label, valueDescriptors) {
  cloningTestInternal(label, valueDescriptors, { useKeyGenerator: false });
}

// cloningTest, with coverage for key generators.
//
// This creates two tests. One test performs a series of put()s and verifies
// that get()s and getAll() match, exactly like cloningTestWithoutKeyGenerator.
// The other test performs the same put()s in an object store with a key
// generator, and checks that the key generator works properly.
function cloningTestWithKeyGenerator(label, valueDescriptors) {
  cloningTestInternal(label, valueDescriptors, { useKeyGenerator: false });
  cloningTestInternal(
      label + " with key generator", valueDescriptors,
      { useKeyGenerator: true });
}
