use crate::cli::DddaToM6aOptions;
use crate::utils::basemods;
use crate::utils::basemods::BaseMods;
use crate::*;
use anyhow::Error;
use bio::alphabets::dna::revcomp;
use rayon::iter::ParallelIterator;
use rayon::prelude::*;
use rust_htslib::bam::Record;
pub fn ddda_to_m6a_record(record: &mut Record, _opts: &DddaToM6aOptions) {
let was_reverse = record.is_reverse();
let cigar = bam::record::CigarString(record.cigar().to_vec());
let q_name = record.qname().to_vec();
let qual = record.qual().to_vec();
let mut forward_seq = record.seq().as_bytes();
if was_reverse {
forward_seq = revcomp(&forward_seq);
}
let mut modified_bases_forward = vec![];
let mut y_count = 0;
let mut r_count = 0;
let mut new_forward_seq = vec![];
for (idx, bp) in forward_seq.iter().enumerate() {
if bp == &b'Y' {
modified_bases_forward.push(idx as i64);
y_count += 1;
new_forward_seq.push(b'T');
} else if bp == &b'R' {
modified_bases_forward.push(idx as i64);
r_count += 1;
new_forward_seq.push(b'A');
} else {
new_forward_seq.push(*bp);
}
}
if !(y_count == 0 || r_count == 0) {
panic!("Y and R cannot be in the same sequence");
} else if y_count == 0 && r_count == 0 {
return;
}
let is_top_strand = y_count > 0;
if was_reverse {
new_forward_seq = revcomp(&new_forward_seq);
}
record.set(&q_name, Some(&cigar), &new_forward_seq, &qual);
let (modified_base, strand) = if is_top_strand {
(b'T', '-')
} else {
(b'A', '+')
};
let modification_type = 'a';
let modified_probabilities_forward = vec![255; modified_bases_forward.len()];
let fake_base_mods = basemods::BaseMod::new(
record,
modified_base,
strand,
modification_type,
modified_bases_forward,
modified_probabilities_forward,
);
let mut base_mods = basemods::BaseMods::new(record, 0);
base_mods.base_mods.push(fake_base_mods);
base_mods.add_mm_and_ml_tags(record);
let _ = BaseMods::new(record, 0);
}
pub fn ddda_to_m6a(opts: &mut DddaToM6aOptions) -> Result<(), Error> {
let mut bam = opts.input.bam_reader();
let mut out = opts.input.bam_writer(&opts.out);
let bam_chunk_iter = BamChunk::new(bam.records(), None);
for mut chunk in bam_chunk_iter {
chunk
.par_iter_mut()
.for_each(|record| ddda_to_m6a_record(record, opts));
chunk
.into_iter()
.for_each(|record| out.write(&record).unwrap());
}
Ok(())
}