/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#include <vector>

#include "common/libs/threads/cuttlefish_thread.h"
#include "common/libs/fs/shared_fd.h"
#include "guest/hals/sensors/sensors.h"
#include "guest/hals/sensors/sensors_hal.h"

namespace cvd {

// Used for sending control messages to the receiver thread.
// The sensor_handle field may be left unused if it is not needed.
enum ControlMessageType {
  THREAD_STOP,
  SENSOR_STATE_UPDATE
};
typedef struct {
  ControlMessageType message_type;
  uint8_t sensor_handle;
} SensorControlMessage;

#if VSOC_SENSORS_DEVICE_API_VERSION_ATLEAST(1_0)
// Last updated to HAL 1.4
// Version history:
//   Before jb, jb-mr1 SENSORS_DEVICE_API_VERSION_0_1 (no version in sensors.h)
//   jb-mr2: SENSORS_DEVICE_API_VERSION_1_0
//   k: SENSORS_DEVICE_API_VERSION_1_1
//   l, l-mr1: SENSORS_DEVICE_API_VERSION_1_3
//   m, n, n-mr1: SENSORS_DEVICE_API_VERSION_1_4
#else
// Pre-1.0 sensors do not define the sensors_poll_device_1 type.
typedef sensors_poll_device_t sensors_poll_device_1;
#endif

class GceSensors : public sensors_poll_device_1 {
 public:
  GceSensors();
  ~GceSensors();

  /**
   ** SENSOR HAL API FUNCTIONS FOR MODULE
   **/

  // Gets a list of all supported sensors and stores in list.
  // Returns the number of supported sensors.
  static int GetSensorsList(struct sensors_module_t* module,
    struct sensor_t const** list);

  // Place the module in a specific mode. The following modes are defined
  //
  //  0 - Normal operation. Default state of the module.
  //  1 - Loopback mode. Data is injected for the supported
  //      sensors by the sensor service in this mode.
  // @return 0 on success
  //         -EINVAL if requested mode is not supported
  //         -EPERM if operation is not allowed
  static int SetOperationMode(unsigned int mode);


  /**
   ** SENSOR HAL API FUNCTIONS FOR DEVICE
   **/
  // Opens the device.
  static int Open(const struct hw_module_t* module, const char* name,
    struct hw_device_t** device);

  // Closes the device, closing all sensors.
  int Close();

  // Activate (or deactivate) the sensor with the given handle.
  //
  // One-shot sensors deactivate themselves automatically upon receiving an
  // event, and they must still accept to be deactivated through a call to
  // activate(..., enabled=0).
  // Non-wake-up sensors never prevent the SoC from going into suspend mode;
  // that is, the HAL shall not hold a partial wake-lock on behalf of
  // applications.
  //
  // If enabled is 1 and the sensor is already activated, this function is a
  // no-op and succeeds.
  //
  // If enabled is 0 and the sensor is already deactivated, this function is a
  // no-op and succeeds.
  //
  // This function returns 0 on success and a negative error number otherwise.
  int Activate(int handle, int enabled);

  // Sets the delay (in ns) for the sensor with the given handle.
  // Deprecated as of HAL 1.1
  // Called after activate()
  int SetDelay(int handle, int64_t sampling_period_ns);

  // Returns an array of sensor data by filling the data argument.
  // This function must block until events are available. It will return
  // the number of events read on success, or a negative number in case of
  // an error.
  int Poll(sensors_event_t* data, int count);

#if VSOC_SENSORS_DEVICE_API_VERSION_ATLEAST(1_0)
  // Sets a sensor’s parameters, including sampling frequency and maximum
  // report latency. This function can be called while the sensor is
  // activated, in which case it must not cause any sensor measurements to
  // be lost: transitioning from one sampling rate to the other cannot cause
  // lost events, nor can transitioning from a high maximum report latency to
  // a low maximum report latency.
  //
  // Before SENSORS_DEVICE_API_VERSION_1_3, flags included:
  //   SENSORS_BATCH_DRY_RUN
  //   SENSORS_BATCH_WAKE_UPON_FIFO_FULL
  //
  // After SENSORS_DEVICE_API_VERSION_1_3 see WAKE_UPON_FIFO_FULL
  // in sensor_t.flags
  int Batch(int sensor_handle, int flags, int64_t sampling_period_ns,
            int64_t max_report_latency_ns) {
    // TODO: Add support for maximum report latency with max_report_latency_ns.
    return SetDelay(sensor_handle, sampling_period_ns);
  }
#endif

#if VSOC_SENSORS_DEVICE_API_VERSION_ATLEAST(1_1)
  // Adds a META_DATA_FLUSH_COMPLETE event (sensors_event_meta_data_t)
  // to the end of the "batch mode" FIFO for the specified sensor and flushes
  // the FIFO.
  //
  // If the FIFO is empty or if the sensor doesn't support batching (FIFO
  // size zero), it should return SUCCESS along with a trivial
  // META_DATA_FLUSH_COMPLETE event added to the event stream. This applies to
  // all sensors other than one-shot sensors.
  //
  // If the sensor is a one-shot sensor, flush must return -EINVAL and not
  // generate any flush complete metadata.
  //
  // If the sensor is not active at the time flush() is called, flush() should
  // return -EINVAL.
  int Flush(int sensor_handle) {
    return -EINVAL;
  }
#endif

#if VSOC_SENSORS_DEVICE_API_VERSION_ATLEAST(1_4)
  // Inject a single sensor sample to be to this device.
  // data points to the sensor event to be injected
  // @return 0 on success
  //  -EPERM if operation is not allowed
  //  -EINVAL if sensor event cannot be injected
  int InjectSensorData(const sensors_event_t *data) {
    return -EINVAL;
  }
#endif

 private:
  typedef std::vector<SensorState*> SensorStateVector;
  typedef std::vector<sensors_event_t> FifoType;
  // Total number of sensors supported by this HAL.
  static int total_sensor_count_;
  // Vector of static sensor information for sensors supported by this HAL.
  // Indexed by the handle. Length must always be equal to total_sensor_count_.
  static SensorInfo* sensor_infos_;
  // Vector of sensor state information, indexed by the handle.
  // Assumption here is that the sensor handles will start at 0 and be
  // contiguous up to the number of supported sensors.
  SensorStateVector sensor_states_;
  // Keep track of the time when the thread in Poll() is scheduled to wake.
  cvd::time::MonotonicTimePoint current_deadline_;

  // Ordered set of sensor values.
  // TODO(ghartman): Simulate FIFO overflow.
  FifoType fifo_;
  // Thread to handle new connections.
  pthread_t receiver_thread_;
  // Socket to receive sensor events on.
  cvd::SharedFD sensor_listener_socket_;
  // Socket for listener thread to receive control messages.
  cvd::SharedFD control_receiver_socket_;
  // Socket to send control messages to listener thread.
  cvd::SharedFD control_sender_socket_;

  // Lock to protect shared state, including
  // sensor_states_ and next_deadline_.
  // Associated with deadline_change_ condition variable.
  cvd::Mutex sensor_state_lock_;
  // Condition variable to signal changes in the deadline.
  cvd::ConditionVariable deadline_change_;

  // When events are arriving from a client, we report only
  // when they arrive, rather than at a fixed cycle. After not
  // receiving a real event for both a given number of periods
  // and a given time period, we will give up and resume
  // sending mock events.
  const static int kInjectedEventWaitPeriods;
  const static cvd::time::Nanoseconds kInjectedEventWaitTime;

  /**
   ** UTILITY FUNCTIONS
   **/

  // Receive data from remoter.
  void* Receiver();

  // Notifies the remoter that the HAL is awake and ready.
  inline bool NotifyRemoter();

  // Looks through all active sensor deadlines, and finds the one that
  // is coming up next. If this is not next_deadline_, then the deadline
  // has changed. Update it and signal the Poll thread.
  // This should be called anytime the next deadline may have changed.
  // Can only be called while holding sensor_state_lock_.
  // Returns true if the deadline has changed.
  cvd::time::MonotonicTimePoint UpdateDeadline();

  // Sends an update for the sensor with the given handle to the remoter.
  // Update will be enqueued for receiver, not send immediately.
  inline bool UpdateRemoterState(int handle);

  // Sends a control event to the listener.
  inline bool SendControlMessage(SensorControlMessage msg);

  // Populates the list of static sensor info. Returns the number
  // of sensors supported. Should only be called once.
  static inline int RegisterSensors();

};

} //namespace cvd