use std::{
fmt,
ops::Deref,
path::{Path, PathBuf},
};
use clap::{Args, Subcommand, ValueEnum};
use console::style;
use crate::{guess_version, lint, price, Error};
#[derive(Subcommand)]
pub enum Command {
GuessVersion(guess_version::Command),
Lint(lint::Command),
Price(price::Command),
}
impl Command {
pub fn run(self) -> Result<(), Error> {
match self {
Self::GuessVersion(command) => command.run(),
Self::Lint(command) => command.run(),
Self::Price(command) => command.run(),
}
}
}
#[derive(Args)]
pub struct TariffArgs {
#[arg(short = 'c', long)]
pub cdr: Option<PathBuf>,
#[arg(short = 't', long)]
pub tariff: Option<PathBuf>,
#[arg(short = 'z', long, alias = "tz")]
pub timezone: Option<String>,
#[arg(short = 'o', long, value_enum)]
pub ocpi_version: Version,
}
#[derive(Clone, Debug, ValueEnum)]
pub(crate) enum Version {
V221,
V211,
}
impl From<Version> for ocpi_tariffs::Version {
fn from(value: Version) -> Self {
match value {
Version::V221 => ocpi_tariffs::Version::V221,
Version::V211 => ocpi_tariffs::Version::V211,
}
}
}
#[derive(Clone, Debug)]
pub(crate) struct FilePath {
path: PathBuf,
file_name: String,
dir_name: String,
}
impl FilePath {
pub fn from_path(path: &Path) -> Result<Self, Error> {
let path = path.canonicalize().map_err(Error::then_file_io(path))?;
let mut parts = path.iter().rev();
let Some(file_name) = parts.next() else {
return Err(Error::PathNotFile { path });
};
let Some(dir_name) = parts.next() else {
return Err(Error::PathNoParentDir { path });
};
let file_name = file_name.to_string_lossy().to_string();
let dir_name = dir_name.to_string_lossy().to_string();
Ok(Self {
path,
file_name,
dir_name,
})
}
pub fn file_name(&self) -> &str {
&self.file_name
}
pub fn dir_and_name(&self) -> String {
format!("{}/{}", self.dir_name, self.file_name)
}
}
impl fmt::Display for FilePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.path.display())
}
}
impl AsRef<Path> for FilePath {
fn as_ref(&self) -> &Path {
&self.path
}
}
impl Deref for FilePath {
type Target = PathBuf;
fn deref(&self) -> &Self::Target {
&self.path
}
}
pub fn job_description(cdr: Option<&FilePath>, tariff: Option<&FilePath>) -> String {
let cdr_name = cdr
.as_ref()
.map(|c| c.file_name())
.unwrap_or_else(|| "<stdin>");
let tariff_name = tariff
.as_ref()
.map(|c| c.file_name())
.unwrap_or_else(|| "<CDR-tariff>");
format!(
"`{}` with tarifff `{}`",
style(cdr_name).blue(),
style(tariff_name).blue(),
)
}