use crate::domain::niseci::lessclone::{
CampionamentoNISECI, ValoriIntermediNISECI, ValoriIntermediSpecieNISECI,
};
use crate::domain::niseci::{
AnagraficaNISECI, AreaNISECI, IdSpecieNISECI, RiferimentoNISECI, StatoEcologicoNISECI,
};
use crate::engines::niseci::x2::lessclone::MetricheX2;
use std::collections::{hash_map::Entry, HashMap};
use crate::engines::niseci::x1::lessclone::calculate_x1;
use crate::engines::niseci::x2::lessclone::calculate_x2;
use crate::engines::niseci::x2::lessclone::calculate_x2_per_alloctone;
use crate::engines::niseci::x3::lessclone::calculate_x3;
const RQE_NISECI_MAGIC_ADDEND: f32 = std::f32::consts::FRAC_2_SQRT_PI;
const RQE_NISECI_MAGIC_QUOTIENT: f32 = 1.0603;
pub fn calculate_niseci(
campionamento: &CampionamentoNISECI,
riferimento: &RiferimentoNISECI,
anagrafica: &AnagraficaNISECI,
) -> Result<(Option<f32>, ValoriIntermediNISECI), Vec<String>> {
let mut errors = Vec::new();
let x1 = calculate_x1(campionamento, riferimento);
let x2 = calculate_x2(campionamento, anagrafica, riferimento, true);
match x2 {
Ok(_) => {}
Err(x2_errors) => {
for e in x2_errors {
errors.push(format!("Errore durante calcolo x2: {}", e));
}
return Err(errors);
}
}
let (x2, criteri_x2) = x2.expect("calc_niseci() returned earlier on Err match");
let x2_non_attese = calculate_x2(campionamento, anagrafica, riferimento, false);
match x2_non_attese {
Ok(_) => {}
Err(x2_non_attese_errors) => {
for e in x2_non_attese_errors {
errors.push(format!("Errore durante calcolo x2_non_attese: {}", e));
}
return Err(errors);
}
}
let (_x2_non_attese, criteri_x2_non_attese) =
x2_non_attese.expect("calc_niseci() returned earlier on Err match");
let x2_per_alloctone = calculate_x2_per_alloctone(campionamento, riferimento, anagrafica);
match x2_per_alloctone {
Ok(_) => {}
Err(x2_per_alloctone_errors) => {
for e in x2_per_alloctone_errors {
errors.push(format!("Errore durante calcolo x2_per_alloctone: {}", e));
}
return Err(errors);
}
}
let (_x2_per_alloctone, criteri_x2_per_alloctone) =
x2_per_alloctone.expect("calc_niseci() returned earlier on Err match");
let mut valori_intermedi_specie: HashMap<IdSpecieNISECI, ValoriIntermediSpecieNISECI> =
HashMap::new();
valori_intermedi_specie.extend(get_valori_intermedi_specie(&criteri_x2));
let intermedi_non_attese = get_valori_intermedi_specie(&criteri_x2_non_attese);
valori_intermedi_specie.extend(intermedi_non_attese);
valori_intermedi_specie.extend(get_valori_intermedi_specie(&criteri_x2_per_alloctone));
let x3 = calculate_x3(campionamento, riferimento);
match x3 {
Ok(_) => {}
Err(x3_errors) => {
for e in x3_errors {
errors.push(format!("Errore durante calcolo x3: {}", e));
}
return Err(errors);
}
}
let (x3, criteri_x3) = x3.expect("calc_niseci() returned earlier on Err match");
if let Some(ref crit) = criteri_x3 {
let submetriche_map_x3 = crit.get_ref_submetriche_map();
for (key, val) in submetriche_map_x3 {
let classi_eta = val.get_ref_classi_eta();
let specie = key.clone();
let densita_stimata = -1.0; let subvalue_a = val.get_criterio_a();
let subvalue_b = val.get_criterio_b();
let val = ValoriIntermediSpecieNISECI::new(
classi_eta.clone(),
densita_stimata,
0,
val.get_rapporto_ad_juv(),
subvalue_a,
subvalue_b,
0.0,
);
match valori_intermedi_specie.entry(specie) {
Entry::Occupied(_) => {}
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(val);
}
}
}
}
let mut x1_x2_errors = Vec::new();
if x1 < 0.0 {
x1_x2_errors.push(format!("Errore risultato x1: valore negativo: {}", x1));
}
if let Some(val) = x2 {
if val < 0.0 {
x1_x2_errors.push(format!("Errore risultato x2: valore negativo: {}", val));
}
}
if !x1_x2_errors.is_empty() {
return Err(x1_x2_errors);
}
let intermediates = ValoriIntermediNISECI::new(
x1,
x2,
x3,
valori_intermedi_specie,
criteri_x2.get_criterio_a(),
criteri_x2.get_criterio_b(),
criteri_x3.as_ref().map(|v| v.get_criterio_a()),
criteri_x3.as_ref().map(|v| v.get_criterio_b()),
);
match x2 {
Some(x2_val) => {
let niseci = (0.1 * x1.sqrt()) + (0.1 * x2_val.sqrt()) + (0.8 * (x1 * x2_val))
- ((0.1 * (1.0 - x3))
* ((0.1 * x1.sqrt()) + (0.1 * x2_val.sqrt()) + (0.8 * (x1 * x2_val))));
let rounded_niseci = (1000.0 * niseci).round() / 1000.0;
Ok((Some(rounded_niseci), intermediates))
}
None => {
Ok((None, intermediates))
}
}
}
pub fn calculate_rqe_niseci(niseci: Option<f32>) -> Option<f32> {
let rqe =
niseci.map(|val| (val.log(10.0) + RQE_NISECI_MAGIC_ADDEND) / RQE_NISECI_MAGIC_QUOTIENT);
if let Some(r) = rqe {
let rounded_rqe = (100.0 * r).round() / 100.0;
Some(rounded_rqe)
} else {
rqe
}
}
pub fn calculate_stato_ecologico_niseci(
niseci: Option<f32>,
area: &AreaNISECI,
) -> Option<StatoEcologicoNISECI> {
let rqe_niseci = calculate_rqe_niseci(niseci);
rqe_niseci.map(|val| StatoEcologicoNISECI::from((val, area)))
}
fn get_valori_intermedi_specie(
criteri: &MetricheX2,
) -> HashMap<IdSpecieNISECI, ValoriIntermediSpecieNISECI> {
let mut valori_intermedi_specie: HashMap<IdSpecieNISECI, ValoriIntermediSpecieNISECI> =
HashMap::new();
let submetriche_map = criteri.get_ref_submetriche_map();
for (key, val) in submetriche_map.iter() {
let criteri_x2_a = val.get_metriche_x2_a();
let classi_eta = val.get_ref_classi_eta();
let specie = key.clone();
let densita_stimata = val.get_ref_metriche_x2_b().get_densita_stimata();
let quantita_stimata = val.get_ref_metriche_x2_b().get_quantita_stimata();
let x2_b = val.get_ref_metriche_x2_b().get_x2_b();
let val = ValoriIntermediSpecieNISECI::new(
classi_eta.clone(),
densita_stimata,
quantita_stimata,
criteri_x2_a.get_rapporto_ad_juv(),
criteri_x2_a.get_criterio_a(),
criteri_x2_a.get_criterio_b(),
x2_b,
);
match valori_intermedi_specie.entry(specie) {
Entry::Occupied(_) => {}
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(val);
}
}
}
valori_intermedi_specie
}