#ifndef MQ2GASSENSOR_H
#define MQ2GASSENSOR_H

#include <Arduino.h>
#include <Wire.h>
#include "common.h"
#include "LCDHelper.h"

/**
 * This class encapsulates
 */
class MQ2GasSensor {
private:
  byte loadRes;
  byte sensorAnalogPIN;
  byte sensorDigitalPIN;
  float airFactor;
  const float* smokeCurve;
  bool sensorCalibrated;
  word sensorValue;
  float baselineResistance;   //resistance of sensor after calibration
  float currResistance;
  LCDHelper* lcdHelper;
  unsigned int sensorWarmupTime;
  byte readSamples;
  unsigned short readInterval;

  // Fan RPM monitoring variables
  static MQ2GasSensor* instance; // Static instance pointer for interrupt handling
  float getSensorResistance(byte samples, word interval);
  /**
   * Function does the initial sensor calibration. It performs initial resistance reading.
   *
   * @return When calibration is finished, it will return true. Otherwise, it returns false.
   */
  bool calibrateSensor();

  static void digitalInputTriggered(); // Static interrupt handler
  void (*onDigitalInputTriggeredCallback)();  // Function pointer for the callback
public:
    static constexpr byte DEFAULT_LOAD_RES = (byte)10;         // Load resistance value in kΩ
    static constexpr float DEFAULT_AIR_FACTOR = 9.83;     // Air factor for calibration (clean air reference resistance)
    static const float SMOKE_CURVE[];
    static constexpr unsigned int DEFAULT_GAS_SENSE_WARMUP_TIME = 180000;  // warm up time for gas sensor
    static constexpr byte CALIBRATION_SAMPLES_COUNT = 50;
    static constexpr unsigned short CALIBRATION_SAMPLE_INTERVAL = 500;
    static constexpr byte SAMPLES_COUNT = 5;
    static constexpr byte SAMPLE_INTERVAL = 50;

    // Constructors
    MQ2GasSensor(byte sensorAnalogPIN, byte sensorDigitalPIN);    
    MQ2GasSensor(byte sensorAnalogPIN, byte sensorDigitalPIN, LCDHelper* lcdHelper);    
    MQ2GasSensor(byte sensorAnalogPIN, byte sensorDigitalPIN ,LCDHelper* lcdHelper, unsigned int sensorWarmupTime, const float* smokeCurve);

    /**
     * This function attaches to analog and digital PIN specified in constructor
     */
    void attach();    
    /**
     * This function performs initial sensor calibration. It waits for sensor warm-up and does initial resistance reading. It is non-blocking.
     * You can tell when sensor is calibrated by calling {@link #isSensorCalibrated()}.
     */
    void calibrateGasSensor();
    /**
     * This functions returns the raw sensor analog value.
     */
    word getSensorValue();
    /**
     * This functions returns sensor value recalculated to PPM.
     */
    word getSensorValuePPM();
    /**
     * This function returns the sensor resistance. It is not the "actual" value, but the last read. Resistance is being determined by multiple readings of sensor
     * value over some time, so this is from alst finished reading.
     */
    float getSensorResistance();    
    bool isSensorCalibrated() const;
    unsigned int getSensorWarmupTime() const;
    void onDigitalInputTriggered(void (*callback)()); // Method to set the callback

    ~MQ2GasSensor();
};

#endif
