use std::rc::Rc;
use std::time::Duration;
use dht_hal_drv::{dht_split_init, dht_split_read, DhtType};
use spin_sleep;
use rppal::gpio::IoPin;

use crate::open_pin::OpenPin;
use crate::{Measurement, Sensor};

pub struct DHT22 {
    location: Rc<String>,
    pin: OpenPin,
}

impl DHT22 {
    pub fn new(pin: IoPin, location: String) -> Self {
        DHT22 {
            location: Rc::new(location),
            pin: OpenPin::new(pin),
        }
    }
}

impl Sensor for DHT22 {
    fn read(&mut self) -> Vec<crate::Measurement> {
        let mut delay_us = |d: u16| {
            // We are using here more accurate delays than in std library
            spin_sleep::sleep(Duration::from_micros(d as u64));
        };

        self.pin.switch_output();
        if let Err(_) = dht_split_init(&mut self.pin, &mut delay_us) {
            return vec![];
        }

        self.pin.switch_input();
        match dht_split_read(DhtType::DHT22, &mut self.pin, &mut delay_us) {
            Ok(readings) => vec![
                Measurement::new(self.location.clone(), "temperature", readings.temperature()),
                Measurement::new(self.location.clone(), "humidity", readings.humidity()),
            ],
            Err(_) =>
                vec![]
        }
    }
}
