use std::rc::Rc;
use std::time::Duration;
use rppal::gpio::{Gpio, Mode};

mod open_pin;
mod dht;

#[derive(Debug, Clone)]
pub struct Measurement {
    pub location: Rc<String>,
    pub type_: &'static str,
    pub value: f64,
}

impl Measurement {
    pub fn new<V: Into<f64>>(
        location: Rc<String>,
        type_: &'static str,
        value: V,
    ) -> Self {
        Measurement {
            location, type_,
            value: value.into(),
        }
    }
}

pub trait Sensor {
    fn read(&mut self) -> Vec<Measurement>;
}

fn main() {
    let hostname = std::fs::read("/proc/sys/kernel/hostname")
        .expect("hostname");
    let hostname = String::from_utf8_lossy(&hostname);
    let hostname = hostname.trim();
    let gpio = Gpio::new().expect("Can not init Gpio structure");

    let mut args = std::env::args().skip(1);
    let interval: u64 = args.next()
        .expect("interval argument")
        .parse()
        .expect("interval integer");
    let interval = Duration::from_secs(interval);

    let mut sensors: Vec<Box<dyn Sensor>> = vec![];
    while let Some(kind) = args.next() {
        match &kind[..] {
            "dht22" => {
                let pin: u8 = args.next()
                    .expect("pin argument")
                    .parse()
                    .expect("pin integer");
                let location = args.next()
                    .expect("location");
                let iopin = gpio
                    .get(pin)
                    .expect("Was not able to get Pin")
                    .into_io(Mode::Input);
                let dht = dht::DHT22::new(iopin, location);
                sensors.push(Box::new(dht));
            }
            _ => panic!("Unknown sensor kind: {}", kind),
        }
    }

    loop {
        for sensor in &mut sensors {
            for m in sensor.read() {
                println!(
                    "PUTVAL {}/{}-{}/{}-{} interval={} N:{}",
                    hostname,
                    "sensors", "sensors-pi",
                    m.type_, m.location,
                    interval.as_secs(),
                    m.value
                );
            }
        }
        std::thread::sleep(interval);
    }
}
