use std::io;
use std::io::BufRead;
use std::io::Write;
use std::path::PathBuf;
use crate::errors;
use crate::rank;
use crate::rank::Rank;
use crate::taxon;
use crate::taxon::TaxonId;
#[derive(Debug, StructOpt)]
#[structopt(verbatim_doc_comment)]
pub struct SnapTaxon {
#[structopt(
short = "r",
long = "rank",
possible_values = &Rank::variants()
)]
pub rank: Option<Rank>,
#[structopt(short = "t", long = "taxons")]
pub taxons: Vec<TaxonId>,
#[structopt(short = "i", long = "invalid")]
pub invalid: bool,
#[structopt(parse(from_os_str))]
pub taxon_file: PathBuf,
}
pub fn snaptaxon(args: SnapTaxon) -> errors::Result<()> {
let taxons = taxon::read_taxa_file(&args.taxon_file)?;
if args.rank.map(|r| r == rank::Rank::NoRank).unwrap_or(false) {
return Err(errors::ErrorKind::InvalidInvocation("Snap to an actual rank.".into()).into());
}
let tree = taxon::TaxonTree::new(&taxons);
let by_id = taxon::TaxonList::new(taxons);
let snapping = tree.filter_ancestors(|tid| {
args.taxons.contains(&tid)
|| by_id
.get(tid)
.map(|t| {
(args.invalid || t.valid) && args.rank.map(|r| t.rank == r).unwrap_or(false)
})
.unwrap_or(false)
});
let stdin = io::stdin();
let stdout = io::stdout();
let mut handle = stdout.lock();
for line in stdin.lock().lines() {
let line = line?;
if line.starts_with('>') {
writeln!(handle, "{}", line)?;
} else {
let taxon = line.parse::<taxon::TaxonId>()?;
let snapped = snapping[taxon].unwrap_or(0);
writeln!(handle, "{}", snapped)?;
}
}
Ok(())
}