|
| 1 | +use std::{fmt::Display, path::PathBuf}; |
| 2 | + |
| 3 | +use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc}; |
| 4 | +use clap::{command, Args, Parser, ValueEnum}; |
| 5 | + |
| 6 | +use crate::{ |
| 7 | + data_providers::{ |
| 8 | + flightradar24_provider::FlightRadar24ApiProvider, json_provider::FlightDataFileProvider, |
| 9 | + FlightDataProvider, |
| 10 | + }, |
| 11 | + models::result::{GTError, GTResult}, |
| 12 | +}; |
| 13 | + |
| 14 | +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] |
| 15 | +pub enum FlightDataSrc { |
| 16 | + Json, |
| 17 | + Api, |
| 18 | +} |
| 19 | + |
| 20 | +impl Display for FlightDataSrc { |
| 21 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 22 | + let text = match self { |
| 23 | + Self::Json => "json", |
| 24 | + Self::Api => "api", |
| 25 | + }; |
| 26 | + f.write_str(text) |
| 27 | + } |
| 28 | +} |
| 29 | + |
| 30 | +fn parse_dod_date(s: &str) -> Result<DateTime<Utc>, String> { |
| 31 | + match NaiveDate::parse_from_str(s, "%d %b %Y") { |
| 32 | + Ok(date) => { |
| 33 | + let dod = NaiveDateTime::new( |
| 34 | + date, |
| 35 | + NaiveTime::from_num_seconds_from_midnight_opt(0, 0) |
| 36 | + .expect("Midnight value should have succeeded."), |
| 37 | + ); |
| 38 | + |
| 39 | + Ok(dod.and_utc()) |
| 40 | + } |
| 41 | + Err(e) => Err(format!("Invalid dod value provided ('{s}'). Error: {e}")), |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +#[derive(Args)] |
| 46 | +#[command(version, about)] |
| 47 | +pub struct TagArgs { |
| 48 | + /// The flight code of the flight on which the images were taken. |
| 49 | + #[arg(long)] |
| 50 | + pub flight_code: String, |
| 51 | + |
| 52 | + /// Which source to use for flight geodata. |
| 53 | + #[arg(short, long, name = "src", default_value_t = FlightDataSrc::Json)] |
| 54 | + pub flight_data_src: FlightDataSrc, |
| 55 | + |
| 56 | + /// Date of flight departure. |
| 57 | + #[arg(short, long, name = "dod", value_parser = parse_dod_date, default_value_t = Utc::now())] |
| 58 | + pub date_of_departure: DateTime<Utc>, |
| 59 | + |
| 60 | + /// File path to flight geodata json file. |
| 61 | + #[arg(short, long)] |
| 62 | + pub json_file: Option<PathBuf>, |
| 63 | + |
| 64 | + /// Path to directory containing all images to geotag. |
| 65 | + pub images_dir: PathBuf, |
| 66 | +} |
| 67 | + |
| 68 | +impl TagArgs { |
| 69 | + pub fn try_get_provider(&self) -> GTResult<Box<dyn FlightDataProvider>> { |
| 70 | + match self.flight_data_src { |
| 71 | + FlightDataSrc::Json => { |
| 72 | + if let Some(ref path) = self.json_file { |
| 73 | + Ok(Box::new(FlightDataFileProvider::new(path.clone()))) |
| 74 | + } else { |
| 75 | + GTResult::Err(GTError::Args("Invalid configuration.".to_string())) |
| 76 | + } |
| 77 | + } |
| 78 | + FlightDataSrc::Api => Ok(Box::new(FlightRadar24ApiProvider::new( |
| 79 | + self.flight_code.clone(), |
| 80 | + self.date_of_departure, |
| 81 | + ))), |
| 82 | + } |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +#[derive(Parser)] |
| 87 | +#[command(name = "airmode-tagger")] |
| 88 | +#[command(bin_name = "airmode-tagger")] |
| 89 | +pub enum Cli { |
| 90 | + Tag(TagArgs), |
| 91 | +} |
0 commit comments