use crate::types::Strand;
use std::borrow::Cow;
pub fn reverse_complement(read: &[u8]) -> Vec<u8> {
read.iter().rev().map(|&b| complement(b)).collect()
}
#[inline]
fn complement(b: u8) -> u8 {
match b {
b'A' | b'a' => b'T',
b'T' | b't' => b'A',
b'C' | b'c' => b'G',
b'G' | b'g' => b'C',
other => other,
}
}
pub fn orient_to_seed(read: &[u8], seed: &[u8], k: usize) -> Strand {
if read.len() < k || seed.len() < k {
return Strand::Forward;
}
use std::collections::HashMap;
let mut seed_kmers: HashMap<&[u8], u32> = HashMap::new();
for w in seed.windows(k) {
*seed_kmers.entry(w).or_insert(0) += 1;
}
let fwd_count: u32 = read
.windows(k)
.map(|w| seed_kmers.get(w).copied().unwrap_or(0))
.sum();
let rc = reverse_complement(read);
let rev_count: u32 = rc
.windows(k)
.map(|w| seed_kmers.get(w).copied().unwrap_or(0))
.sum();
if fwd_count >= rev_count {
Strand::Forward
} else {
Strand::Reverse
}
}
pub fn auto_orient<'a>(reads: &'a [Vec<u8>], seed_idx: usize) -> Vec<Cow<'a, [u8]>> {
let seed = &reads[seed_idx];
let k = 8.min(seed.len().saturating_sub(1).max(1));
reads
.iter()
.map(|read| match orient_to_seed(read, seed, k) {
Strand::Forward => Cow::Borrowed(read.as_slice()),
Strand::Reverse => Cow::Owned(reverse_complement(read)),
})
.collect()
}