use std::collections::HashSet;
use std::io;
use crate::errors;
use crate::io::fasta;
#[derive(Debug, StructOpt)]
#[structopt(verbatim_doc_comment)]
pub struct Filter {
#[structopt(short = "m", long = "minlen", default_value = "5")]
pub min_length: usize,
#[structopt(short = "M", long = "maxlen", default_value = "50")]
pub max_length: usize,
#[structopt(short = "c", long = "contains", default_value = "")]
pub contains: String,
#[structopt(short = "l", long = "lacks", default_value = "")]
pub lacks: String,
}
pub fn filter(args: Filter) -> errors::Result<()> {
let contains = args.contains.chars().collect::<HashSet<char>>();
let lacks = args.lacks.chars().collect::<HashSet<char>>();
let mut writer = fasta::Writer::new(io::stdout(), "\n", false);
for record in fasta::Reader::new(io::stdin(), false).records() {
let fasta::Record { header, sequence } = record?;
writer.write_record(fasta::Record {
header,
sequence: sequence
.into_iter()
.filter(|seq| {
let length = seq.len();
length >= args.min_length && length <= args.max_length
})
.filter(|seq| {
let set = seq.chars().collect::<HashSet<char>>();
contains.intersection(&set).count() == contains.len()
&& lacks.intersection(&set).count() == 0
})
.collect(),
})?;
}
Ok(())
}