use bincode::{Decode, Encode};
use na_seq::Seq;
use crate::{
gui::navigation::{Page, PageSeq, Tab},
primer::{Primer, TM_TARGET},
state::State,
util::RangeIncl,
};
#[derive(Clone, Encode, Decode)]
pub struct PcrUi {
pub primer_tm: f32,
pub product_len: usize,
pub polymerase_type: PolymeraseType,
pub num_cycles: u16,
pub primer_selected: usize,
pub primer_fwd: usize,
pub primer_rev: usize,
}
impl Default for PcrUi {
fn default() -> Self {
Self {
primer_tm: TM_TARGET,
product_len: 1_000,
polymerase_type: Default::default(),
num_cycles: 30,
primer_selected: 0,
primer_fwd: 0,
primer_rev: 0,
}
}
}
#[derive(Default, Encode, Decode)]
pub struct TempTime {
pub temp: f32,
pub time: u16,
}
impl TempTime {
pub fn new(temp: f32, time: u16) -> Self {
Self { temp, time }
}
}
#[derive(Clone, Copy, PartialEq, Encode, Decode)]
pub enum PolymeraseType {
NormalFidelity,
HighFidelity,
}
impl Default for PolymeraseType {
fn default() -> Self {
Self::NormalFidelity
}
}
impl PolymeraseType {
pub fn extension_time(&self, product_len: usize) -> u16 {
match self {
Self::NormalFidelity => (60 * product_len / 1_000) as u16,
Self::HighFidelity => (15 * product_len / 1_000) as u16, }
}
pub fn denaturation(&self) -> TempTime {
match self {
Self::NormalFidelity => TempTime::new(94., 30),
Self::HighFidelity => TempTime::new(98., 10), }
}
pub fn denaturation_initial(&self) -> TempTime {
match self {
Self::NormalFidelity => TempTime::new(94., 120),
Self::HighFidelity => TempTime::new(98., 30),
}
}
pub fn to_str(self) -> String {
match self {
Self::NormalFidelity => "Normal fidelity",
Self::HighFidelity => "High fidelity (eg Phusion)",
}
.to_owned()
}
}
#[derive(Default, Encode, Decode)]
pub struct PcrParams {
pub initial_denaturation: TempTime,
pub denaturation: TempTime,
pub annealing: TempTime,
pub extension: TempTime,
pub final_extension: TempTime,
pub num_cycles: u16,
}
impl PcrParams {
pub fn new(data: &PcrUi) -> Self {
Self {
initial_denaturation: data.polymerase_type.denaturation_initial(),
denaturation: data.polymerase_type.denaturation(),
annealing: TempTime::new(data.primer_tm - 5., 30),
extension: TempTime::new(72., data.polymerase_type.extension_time(data.product_len)),
final_extension: TempTime::new(72., 60 * 6),
num_cycles: data.num_cycles,
}
}
}
pub fn make_amplicon_tab(
state: &mut State,
product_seq: Seq,
range: RangeIncl,
fwd_primer: Primer,
rev_primer: Primer,
) {
let mut product_features = Vec::new();
for feature in &state.generic[state.active].features {
if range.start < feature.range.start && range.end > feature.range.end {
let mut product_feature = feature.clone();
product_feature.range.start -= range.start - 1;
product_feature.range.end -= range.start - 1;
product_features.push(product_feature);
}
}
state.add_tab();
state.tabs_open.push(Default::default());
state.generic[state.active].seq = product_seq;
let product_primers = vec![fwd_primer, rev_primer];
state.generic[state.active].features = product_features;
state.generic[state.active].primers = product_primers;
state.generic[state.active].metadata.plasmid_name = "PCR amplicon".to_owned();
state.sync_seq_related(None);
state.ui.page = Page::Sequence;
state.ui.page_seq = PageSeq::View;
}