mod constants;
mod device;
mod error;
mod frame;
mod hex;

use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::device::RtlSdrDevice;
use clap::Parser;
use crate::constants::DEVICE_RTL2832U;
use crate::frame::ADSBFrame;
use crate::hex::hex_to_bytes;

#[derive(Parser, Debug)]
#[command(author, version, about = "An ADS-B Receiver")]
struct ReceiverArgs {
  /// Hex-string to decode
  #[arg(short = 'd', long)]
  decode: Option<String>,

  /// Connect to the USB device
  #[arg(short = 'c', long, action)]
  connect: bool,

  /// Display ADS-B/Mode-S receiver info
  #[arg(short = 'i', long, action)]
  info: bool,

  /// Enable debug logging
  #[arg(short = 'D', long, action = clap::ArgAction::Count)]
  debug: u8,
}

fn main() {
  let args = ReceiverArgs::parse();

  let default_filter = match args.debug {
    0 => "warn,adsb=info",   // no -D
    1 => "warn,adsb=debug",  // -D
    _ => "trace,adsb=trace", // -DD or more
  };

  env_logger::init_from_env(env_logger::Env::default().filter_or("RUST_LOG", default_filter));

  let device_info = DEVICE_RTL2832U;

  // Handle connection
  if args.connect {
    log::info!("Connecting to {:?}", device_info);
    let mut device = match RtlSdrDevice::open(device_info.vid, device_info.pid) {
      Ok(d) => d,
      Err(err) => {
        log::error!("Unable to open RTL SDR device: {:?}", err);
        return;
      }
    };
    log::debug!("Connected to {:?}", device_info.to_string());

    let running = Arc::new(AtomicBool::new(true));
    if let Err(err) = ctrlc::set_handler({
      let running = running.clone();
      move || running.store(false, Ordering::SeqCst)
    }) {
      log::error!("Error setting Ctrl-C handler: {}", err);
      running.store(false, Ordering::SeqCst);
    };

    if let Err(err) = device.process(running) {
      log::error!("Failed to read from device: {}", err);
      if let Err(err) = device.close() {
        log::error!("Failed to close device: {}", err);
      };
    };
  }
  // Display dongle info
  else if args.info {
    RtlSdrDevice::info(device_info.vid, device_info.pid);
  }
  // Handle decode mode
  else if let Some(mut hex_string) = args.decode {
    if let Some(stripped) = hex_string.strip_prefix("0x") {
      hex_string = stripped.to_string();
    }
    let buffer = match hex_to_bytes(&hex_string) {
      Ok(buffer) => buffer,
      Err(err) => {
        eprintln!("Unable to convert hex to bytes: {:?}", err);
        return;
      }
    };
    if let Ok(frame) = ADSBFrame::decode(&buffer) {
      println!("{:?}", frame);
    };
  } else {
    eprintln!("No connection specified");
  }
}
