//! [Clap] struct used to parse command line arguments.

use std::path::PathBuf;

use crate::extension_set::ExtensionSet;
use clap::{Clap, AppSettings};
use smartstring::{LazyCompact, SmartString};

#[derive(Clap, PartialEq, Debug)]
pub enum OutputFormat {
	/// A Bourne shell compatible script.
	Script,
	/// Plain text.
	Text,
}

// TODO: convert this to macro style?: https://docs.rs/clap/3.0.0-beta.2/clap/index.html#using-macros

#[derive(Clap, Debug)]
#[clap(
	version = option_env!("CARGO_PKG_VERSION").unwrap_or("???"),
	author = option_env!("CARGO_PKG_AUTHORS").unwrap_or("Lynnesbian"),
	about = option_env!("CARGO_PKG_DESCRIPTION").unwrap_or("File Info Fixer"),
	before_help = "Copyright © 2021 Lynnesbian under the GPL3 (or later) License.",
	before_long_help = "Copyright © 2021 Lynnesbian\n\
	This program is free software: you can redistribute it and/or modify \
	it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 \
	of the License, or (at your option) any later version.",
	setting(AppSettings::ColoredHelp)
)]
pub struct Parameters {
	/// Only examine files with these extensions (Comma-separated list)
	#[clap(
		short,
		long,
		use_delimiter = true,
		require_delimiter = true,
		required_unless_present = "ext-set"
	)]
	pub exts: Option<Vec<SmartString<LazyCompact>>>,

	/// Use a preset list of extensions as the search filter
	#[clap(short = 'E', long, arg_enum, required_unless_present = "exts")]
	pub ext_set: Option<ExtensionSet>,

	/// Don't skip hidden files and directories
	#[clap(short, long)]
	pub scan_hidden: bool,

	/// Scan files without extensions
	#[clap(short = 'S', long)]
	pub scan_extensionless: bool,

	/// Output format to use
	#[clap(short, long, default_value = "script", arg_enum)]
	pub output_format: OutputFormat,

	/// Directory to process
	// TODO: right now this can only take a single directory - should this be improved?
	#[clap(name = "DIR", default_value = ".", parse(from_os_str))]
	pub dirs: PathBuf,
}

/// Further options relating to scanning.
pub struct ScanOpts {
	/// Whether hidden files and directories should be scanned.
	pub hidden: bool,
	/// Whether files without extensions should be scanned.
	pub extensionless: bool
}

impl Parameters {
	pub fn extensions(&self) -> Vec<&str> {
		if let Some(exts) = &self.exts {
			// extensions supplied like "-e png,jpg,jpeg"
			exts.iter().map(|s| s.as_str()).collect()
		} else if let Some(exts) = &self.ext_set {
			// extensions supplied like "-E images"
			exts.extensions()
		} else {
			// neither -E nor -e was passed - this should be impossible
			unreachable!()
		}
	}

	pub fn get_scan_opts(&self) -> ScanOpts {
		ScanOpts { hidden: self.scan_hidden, extensionless: self.scan_extensionless }
	}
}
