'use strict';

// Wraps callback and calls rejectFunc if callback throws an error.
class CallbackWrapper {
  constructor(callback, rejectFunc) {
    this.wrapperFunc_ = (args) => {
      try {
        callback(args);
      } catch(e) {
        rejectFunc(e);
      }
    }
  }

  get callback() {
    return this.wrapperFunc_;
  }
}

function sensorMocks() {
  // Helper function that returns resolved promise with result.
  function sensorResponse(success) {
    return Promise.resolve({success});
  }

  // Class that mocks Sensor interface defined in sensor.mojom
  class MockSensor {
    constructor(sensorRequest, handle, offset, size, reportingMode) {
      this.client_ = null;
      this.startShouldFail_ = false;
      this.reportingMode_ = reportingMode;
      this.sensorReadingTimerId_ = null;
      this.updateReadingFunction_ = null;
      this.suspendCalled_ = null;
      this.resumeCalled_ = null;
      this.addConfigurationCalled_ = null;
      this.removeConfigurationCalled_ = null;
      this.requestedFrequencies_ = [];
      let rv = handle.mapBuffer(offset, size);
      assert_equals(rv.result, Mojo.RESULT_OK, "Failed to map shared buffer");
      this.bufferArray_ = rv.buffer;
      this.buffer_ = new Float64Array(this.bufferArray_);
      this.resetBuffer();
      this.binding_ = new mojo.Binding(device.mojom.Sensor, this,
                                       sensorRequest);
      this.binding_.setConnectionErrorHandler(() => {
        this.reset();
      });
    }

    // Returns default configuration.
    getDefaultConfiguration() {
      return Promise.resolve({frequency: 5});
    }

    // Adds configuration for the sensor and starts reporting fake data
    // through updateReadingFunction_ callback.
    addConfiguration(configuration) {
      assert_not_equals(configuration, null, "Invalid sensor configuration.");

      this.requestedFrequencies_.push(configuration.frequency);
      // Sort using descending order.
      this.requestedFrequencies_.sort(
          (first, second) => { return second - first });

      if (!this.startShouldFail_ )
        this.startReading();

      if (this.addConfigurationCalled_ != null)
        this.addConfigurationCalled_(this);

      return sensorResponse(!this.startShouldFail_);
    }

    // Removes sensor configuration from the list of active configurations and
    // stops notification about sensor reading changes if
    // requestedFrequencies_ is empty.
    removeConfiguration(configuration) {
      if (this.removeConfigurationCalled_ != null) {
        this.removeConfigurationCalled_(this);
      }

      let index = this.requestedFrequencies_.indexOf(configuration.frequency);
      if (index == -1)
        return;

      this.requestedFrequencies_.splice(index, 1);
      if (this.requestedFrequencies_.length === 0)
        this.stopReading();
    }

    // Suspends sensor.
    suspend() {
      this.stopReading();
      if (this.suspendCalled_ != null) {
        this.suspendCalled_(this);
      }
    }

    // Resumes sensor.
    resume() {
      assert_equals(this.sensorReadingTimerId_, null);
      this.startReading();
      if (this.resumeCalled_ != null) {
        this.resumeCalled_(this);
      }
    }

    // Mock functions

    // Resets mock Sensor state.
    reset() {
      this.stopReading();

      this.startShouldFail_ = false;
      this.updateReadingFunction_ = null;
      this.requestedFrequencies_ = [];
      this.suspendCalled_ = null;
      this.resumeCalled_ = null;
      this.addConfigurationCalled_ = null;
      this.removeConfigurationCalled_ = null;
      this.resetBuffer();
      this.bufferArray_ = null;
      this.binding_.close();
    }

    // Zeroes shared buffer.
    resetBuffer() {
      for (let i = 0; i < this.buffer_.length; ++i) {
        this.buffer_[i] = 0;
      }
    }

    // Sets callback that is used to deliver sensor reading updates.
    setUpdateSensorReadingFunction(updateReadingFunction) {
      this.updateReadingFunction_ = updateReadingFunction;
      return Promise.resolve(this);
    }

    // Sets flag that forces sensor to fail when addConfiguration is invoked.
    setStartShouldFail(shouldFail) {
      this.startShouldFail_ = shouldFail;
    }

    // Returns resolved promise if suspend() was called, rejected otherwise.
    suspendCalled() {
      return new Promise((resolve, reject) => {
        this.suspendCalled_ = resolve;
      });
    }

    // Returns resolved promise if resume() was called, rejected otherwise.
    resumeCalled() {
      return new Promise((resolve, reject) => {
        this.resumeCalled_ = resolve;
      });
    }

    // Resolves promise when addConfiguration() is called.
    addConfigurationCalled() {
      return new Promise((resolve, reject) => {
        this.addConfigurationCalled_ = resolve;
      });
    }

    // Resolves promise when removeConfiguration() is called.
    removeConfigurationCalled() {
      return new Promise((resolve, reject) => {
        this.removeConfigurationCalled_ = resolve;
      });
    }

    startReading() {
      if (this.updateReadingFunction_ != null) {
        this.stopReading();
        let maxFrequencyUsed = this.requestedFrequencies_[0];
        let timeout = (1 / maxFrequencyUsed) * 1000;
        this.sensorReadingTimerId_ = window.setInterval(() => {
          if (this.updateReadingFunction_) {
            this.updateReadingFunction_(this.buffer_);
            // For all tests sensor reading should have monotonically
            // increasing timestamp in seconds.
            this.buffer_[1] = window.performance.now() * 0.001;
          }
          if (this.reportingMode_ === device.mojom.ReportingMode.ON_CHANGE) {
            this.client_.sensorReadingChanged();
          }
        }, timeout);
      }
    }

    stopReading() {
      if (this.sensorReadingTimerId_ != null) {
        window.clearInterval(this.sensorReadingTimerId_);
        this.sensorReadingTimerId_ = null;
      }
    }

    getSamplingFrequency() {
       assert_true(this.requestedFrequencies_.length > 0);
       return this.requestedFrequencies_[0];
    }

  }

  // Class that mocks SensorProvider interface defined in
  // sensor_provider.mojom
  class MockSensorProvider {
    constructor() {
      this.readingSizeInBytes_ =
          device.mojom.SensorInitParams.kReadBufferSizeForTests;
      this.sharedBufferSizeInBytes_ = this.readingSizeInBytes_ *
              device.mojom.SensorType.LAST;
      let rv = Mojo.createSharedBuffer(this.sharedBufferSizeInBytes_);
      assert_equals(rv.result, Mojo.RESULT_OK, "Failed to create buffer");
      this.sharedBufferHandle_ = rv.handle;
      this.activeSensor_ = null;
      this.getSensorShouldFail_ = false;
      this.permissionsDenied_ = false;
      this.resolveFunc_ = null;
      this.isContinuous_ = false;
      this.maxFrequency_ = 60;
      this.minFrequency_ = 1;
      this.binding_ = new mojo.Binding(device.mojom.SensorProvider, this);

      this.interceptor_ = new MojoInterfaceInterceptor(
          device.mojom.SensorProvider.name);
      this.interceptor_.oninterfacerequest = e => {
        this.bindToPipe(e.handle);
      };
      this.interceptor_.start();
    }

    // Returns initialized Sensor proxy to the client.
    async getSensor(type) {
      if (this.getSensorShouldFail_) {
        return {result: device.mojom.SensorCreationResult.ERROR_NOT_AVAILABLE,
                initParams: null};
      }
      if (this.permissionsDenied_) {
        return {result: device.mojom.SensorCreationResult.ERROR_NOT_ALLOWED,
                initParams: null};
      }

      let offset = (device.mojom.SensorType.LAST - type) *
          this.readingSizeInBytes_;
      let reportingMode = device.mojom.ReportingMode.ON_CHANGE;
      if (this.isContinuous_) {
        reportingMode = device.mojom.ReportingMode.CONTINUOUS;
      }

      let sensorPtr = new device.mojom.SensorPtr();
      if (this.activeSensor_ == null) {
        let mockSensor = new MockSensor(
            mojo.makeRequest(sensorPtr), this.sharedBufferHandle_, offset,
            this.readingSizeInBytes_, reportingMode);
        this.activeSensor_ = mockSensor;
        this.activeSensor_.client_ = new device.mojom.SensorClientPtr();
      }

      let rv = this.sharedBufferHandle_.duplicateBufferHandle();

      assert_equals(rv.result, Mojo.RESULT_OK);

      let defaultConfig = {frequency: 5};
      // Consider sensor traits to meet assertions in C++ code (see
      // services/device/public/cpp/generic_sensor/sensor_traits.h)
      if (type == device.mojom.SensorType.AMBIENT_LIGHT ||
          type == device.mojom.SensorType.MAGNETOMETER) {
        if (this.maxFrequency_ > 10)
          this.maxFrequency_ = 10;
      }

      let initParams = new device.mojom.SensorInitParams({
        sensor: sensorPtr,
        clientRequest: mojo.makeRequest(this.activeSensor_.client_),
        memory: rv.handle,
        bufferOffset: offset,
        mode: reportingMode,
        defaultConfiguration: defaultConfig,
        minimumFrequency: this.minFrequency_,
        maximumFrequency: this.maxFrequency_
      });

      if (this.resolveFunc_ !== null) {
        this.resolveFunc_(this.activeSensor_);
      }

      return {result: device.mojom.SensorCreationResult.SUCCESS,
              initParams: initParams};
    }

    // Binds object to mojo message pipe
    bindToPipe(pipe) {
      this.binding_.bind(pipe);
      this.binding_.setConnectionErrorHandler(() => {
        this.reset();
      });
    }

    // Mock functions

    // Resets state of mock SensorProvider between test runs.
    reset() {
      if (this.activeSensor_ != null) {
        this.activeSensor_.reset();
        this.activeSensor_ = null;
      }

      this.getSensorShouldFail_ = false;
      this.permissionsDenied_ = false;
      this.resolveFunc_ = null;
      this.maxFrequency_ = 60;
      this.minFrequency_ = 1;
      this.isContinuous_ = false;
      this.binding_.close();
      this.interceptor_.stop();
    }

    // Sets flag that forces mock SensorProvider to fail when getSensor() is
    // invoked.
    setGetSensorShouldFail(shouldFail) {
      this.getSensorShouldFail_ = shouldFail;
    }

    setPermissionsDenied(permissionsDenied) {
      this.permissionsDenied_ = permissionsDenied;
    }

    // Returns mock sensor that was created in getSensor to the layout test.
    getCreatedSensor() {
      if (this.activeSensor_ != null) {
        return Promise.resolve(this.activeSensor_);
      }

      return new Promise((resolve, reject) => {
        this.resolveFunc_ = resolve;
      });
    }

    // Forces sensor to use |reportingMode| as an update mode.
    setContinuousReportingMode() {
      this.isContinuous_ = true;
    }

    // Sets the maximum frequency for a concrete sensor.
    setMaximumSupportedFrequency(frequency) {
      this.maxFrequency_ = frequency;
    }

    // Sets the minimum frequency for a concrete sensor.
    setMinimumSupportedFrequency(frequency) {
      this.minFrequency_ = frequency;
    }
  }

  let mockSensorProvider = new MockSensorProvider;
  return {mockSensorProvider: mockSensorProvider};
}

function sensor_test(func, name, properties) {
  promise_test(async () => {
    let sensor = sensorMocks();

    // Clean up and reset mock sensor stubs asynchronously, so that the blink
    // side closes its proxies and notifies JS sensor objects before new test is
    // started.
    try {
      await func(sensor);
    } finally {
      sensor.mockSensorProvider.reset();
      await new Promise(resolve => { setTimeout(resolve, 0); });
    };
  }, name, properties);
}

// TODO(Mikhail): Refactor further to remove code duplication
// in <concrete sensor>.html files.
function verify_sensor_reading(pattern, values, timestamp, is_null) {
  function round(val) {
    return Number.parseFloat(val).toPrecision(6);
  }

  if (is_null) {
    return (values === null || values.every(r => r === null)) &&
           timestamp === null;
  }
  return values.every((r, i) => round(r) === round(pattern[i])) &&
         timestamp !== null;
}

function verify_xyz_sensor_reading(pattern, {x, y, z, timestamp}, is_null) {
  return verify_sensor_reading(pattern, [x, y, z], timestamp, is_null);
}

function verify_quat_sensor_reading(pattern, {quaternion, timestamp}, is_null) {
  return verify_sensor_reading(pattern, quaternion, timestamp, is_null);
}
