#include <Arduino.h>

#include "AsyncJson.h"
#include "ArduinoJson.h"


#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BMP3XX.h"

#include "sensor.h"

float Thermistor::resistance(float measured_bit_value){
  return (voltage_divider_ohm * measured_bit_value/1024)/(1-measured_bit_value/1024);
}

float Thermistor::ohm_to_temperature(float resistance){
  int len = sizeof tempistor_y / sizeof tempistor_y[0];

  int i = 0;
  while (i < len &&  tempistor_y[i] < resistance) {
    i++;
  }
  i--;

  if (i == 0 || i == len-1)
  {
    return 0.0;
  }
  return floatmap(resistance, tempistor_y[i], tempistor_y[i+1], temp_range_start+ i*temp_range_step, temp_range_start+ (i+1)*temp_range_step);
}

Thermistor::Thermistor(int pin, int voltage_divider_ohm){
  pin = pin;
  voltage_divider_ohm = voltage_divider_ohm;
  supply_voltage = supply_voltage;
}

void async_wait(int ms) {
  unsigned long t1 = millis();
  int n=0;
  while (t1 + ms > millis())
  {
    n++;
  }
}

float Thermistor::read()
{
  int measured_voltage = analogRead(pin);
  float ohm = resistance(measured_voltage);
  return ohm;
}

void Barometer::init() {
  if (!bmp.begin_I2C()) {   // hardware I2C mode, can pass in address & alt Wire
    Serial.println("Could not find a valid BMP3 sensor, check wiring!");
    while (1);
  }

  bmp.setTemperatureOversampling(BMP3_OVERSAMPLING_8X);
  bmp.setPressureOversampling(BMP3_OVERSAMPLING_4X);
  bmp.setIIRFilterCoeff(BMP3_IIR_FILTER_COEFF_3);
  bmp.setOutputDataRate(BMP3_ODR_50_HZ);
  for (size_t i = 0; i < 100; i++)
  {
    bmp.performReading();
  }
  
}

void Barometer::setAmbientPressure() {
  bmp.performReading();
  ambient_pressure = bmp.pressure;
  Serial.print(ambient_pressure);
}

float Barometer::readWindSpeed() {
  bmp.performReading();
  double current_pressure = bmp.pressure;
  double wind_speed = sqrt(2*abs(current_pressure-ambient_pressure)/1.184);
  return wind_speed;
}

float Barometer::readAltitude() {
  bmp.performReading();
  return bmp.readAltitude(1008);
}

FluidPressureSensor::FluidPressureSensor(int pin) {
  pin = pin;
}

double FluidPressureSensor::read() {
  int measured_voltage = analogRead(pin);
  float pressure = floatmap(measured_voltage, 0.0, 1023.0, 0.0, 4.0);
  return pressure;
}

void Multiplexer::activate(Mux_Input device_to_activate){
      for (int device = thermistor_before_radiator; device != Last; device++ )
      {
        Mux_Input device_mux = static_cast<Mux_Input>(device);
        digitalWrite((uint8_t)device_mux, LOW);
      }
      digitalWrite((uint8_t)device_to_activate, HIGH);
    }

double floatmap(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

DynamicJsonDocument createMeasurementJSON(Sensor_Readings* packet){
  DynamicJsonDocument data_message(1024);
  data_message["topic"] = "data";
  data_message["data"]["ts"] = packet->ts;
  data_message["data"]["temp_before_radiator"] = packet->temp_before_radiator;
  data_message["data"]["temp_after_radiator"] = packet->temp_after_radiator;
  data_message["data"]["pressure_before_radiator"] = packet->pressure_before_radiator;
  data_message["data"]["pressure_after_radiator"] = packet->pressure_after_radiator;
  data_message["data"]["wind_speed"] = packet->wind_speed;
  return data_message;
}

DynamicJsonDocument createEndMessageJSON(long ts, float temp_before_radiator, float temp_after_radiator, float pressure_before_radiator, float pressure_after_radiator, float wind_speed){
  DynamicJsonDocument end_message(1024);
  end_message["topic"] = "end_test";
  return end_message;
}

void sendJSONtoClient(AsyncWebSocket ws, AsyncWebSocketClient* client, DynamicJsonDocument message) {
  size_t len = measureJson(message);
  AsyncWebSocketMessageBuffer * buffer = ws.makeBuffer(len); //  creates a buffer (len + 1) for you.
  if (buffer) {
    serializeJson(message, (char *)buffer->get(), len);
    client->text(buffer);
  }
}