use crate::io_utils::{FqReader, FxWriter};
pub fn trimfq(fq_path: &str, q_plus_ascii: u8, minlen: usize) -> Result<(), std::io::Error> {
let reader = FqReader::new(fq_path)?;
let mut writer = FxWriter::new(false);
let (mut start, mut end, mut size): (usize, usize, usize);
for record in reader.records() {
let read = record.unwrap();
(start, end) = trim_read_by_q(read.qual(), q_plus_ascii);
if start < end {
size = read.qual().len();
if size < minlen {
(start, end) = (0, size - 1);
} else if minlen > (end - start + 1) {
if size - start >= minlen {
end = start + minlen - 1;
} else {
end = size - 1;
start = size - minlen;
}
}
writer.write(
read.id(),
&read.seq()[start..(end + 1)],
read.desc(),
&read.qual()[start..(end + 1)],
)?;
}
}
Ok(())
}
fn trim_read_by_q(qual: &[u8], q_plus_ascii: u8) -> (usize, usize) {
let mut start: usize = 0;
let len = qual.len();
for &q in qual {
if q >= q_plus_ascii {
break;
} else {
start += 1;
}
}
if start == len {
return (len, len);
}
let qthd_add_ascii_i = q_plus_ascii as isize;
let mut err_sum: Vec<isize> = vec![0; len];
err_sum[start] = qual[start] as isize - qthd_add_ascii_i;
let (mut max_idx, mut max_val) = (start, err_sum[start]);
((start + 1)..len).for_each(|i| {
err_sum[i] = err_sum[i - 1] + qual[i] as isize - qthd_add_ascii_i;
if err_sum[i] >= max_val {
max_idx = i;
max_val = err_sum[i];
}
});
(start, max_idx)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_trim_read() {
let qual = b"&&&&&...&...++.&.++...&...''..'.&..+..++++.++";
let (start, end) = trim_read_by_q(qual, 33 + 10);
assert_eq!(end - start + 1, 40);
let qual= b"?@<DDD;2A<><FIBHB?FCGAHHEBEHAFCBEFGGB@4CCA@?*?DH9?B?BDC/?81.8BFFEHG@>@G=DGCECEHEHF>>;?;?B=3@CC:(,(98',>5(82)<5>>223@4+4>@+5855>>>@:AA@>:43>@##########";
let (start, end) = trim_read_by_q(qual, 33 + 20);
assert_eq!(end - start + 1, 140);
}
}