use crate::types::*;

#[derive(Debug, Clone, Copy, Default)]
pub struct CurrentStats {
    pub dirty: bool,
    pub min_tot_nodes: NodeCount,
    pub min_tot_nodes_quorum: RegionCount,
    pub max_tot_nodes: NodeCount,
    pub max_tot_nodes_quorum: RegionCount,
    pub min_tot_honest: NodeCount,
    pub min_tot_honest_quorum: RegionCount,
    pub max_tot_honest: NodeCount,
    pub max_tot_honest_quorum: RegionCount,
    pub min_tot_malicious: NodeCount,
    pub min_tot_malicious_quorum: RegionCount,
    pub max_tot_malicious: NodeCount,
    pub max_tot_malicious_quorum: RegionCount,
    pub min_tot_last_join: TimeCount,
    pub min_tot_last_join_quorum: RegionCount,
    pub max_tot_last_join: TimeCount,
    pub max_tot_last_join_quorum: RegionCount,
    pub min_b_0: f64,
    pub min_b_0_quorum: RegionCount,
    pub max_b_0: f64,
    pub max_b_0_quorum: RegionCount,
}

impl CurrentStats {
    pub fn update(&mut self, i: RegionCount, q: &Quorum, force: bool) -> bool {
        let mut below_bmax: bool = true;
        if self.dirty == false && (
            self.min_tot_nodes_quorum == i ||
                self.max_tot_nodes_quorum == i ||
                self.min_tot_honest_quorum == i ||
                self.max_tot_honest_quorum == i ||
                self.min_tot_malicious_quorum == i ||
                self.max_tot_malicious_quorum == i ||
                self.min_tot_last_join_quorum == i ||
                self.max_tot_last_join_quorum == i ||
                self.min_b_0_quorum == i ||
                self.max_b_0_quorum == i) {
            self.dirty = true;
        }
        let nodes = q.tot_honest + q.tot_malicious;
        if force || nodes < self.min_tot_nodes {
            self.min_tot_nodes = nodes;
            self.min_tot_nodes_quorum = i;
        }
        if force || nodes > self.max_tot_nodes {
            self.max_tot_nodes = nodes;
            self.max_tot_nodes_quorum = i;
        }
        if force || q.tot_honest < self.min_tot_honest {
            self.min_tot_honest = q.tot_honest;
            self.min_tot_honest_quorum = i;
        }
        if force || q.tot_honest > self.max_tot_honest {
            self.max_tot_honest = q.tot_honest;
            self.max_tot_honest_quorum = i;
        }
        if force || q.tot_malicious < self.min_tot_malicious {
            self.min_tot_malicious = q.tot_malicious;
            self.min_tot_malicious_quorum = i;
        }
        if force || q.tot_malicious > self.max_tot_malicious {
            self.max_tot_malicious = q.tot_malicious;
            self.max_tot_malicious_quorum = i;
        }
        if force || q.tot_last_join < self.min_tot_last_join {
            self.min_tot_last_join = q.tot_last_join;
            self.min_tot_last_join_quorum = i;
        }
        if force || q.tot_last_join > self.max_tot_last_join {
            self.max_tot_last_join = q.tot_last_join;
            self.max_tot_last_join_quorum = i;
        }
        let b_0 : f64 = (q.tot_malicious as f64) / (q.tot_honest as f64 + q.tot_malicious as f64);
        if force || (b_0 < self.min_b_0 && q.tot_malicious != 0) {
            self.min_b_0 = b_0;
            self.min_b_0_quorum = i;
        }
        if force || b_0 > self.max_b_0 {
            self.max_b_0 = b_0;
            self.max_b_0_quorum = i;
            if b_0 > 0.25 {
                below_bmax = false;
            }
        }
        below_bmax
    }

    #[allow(dead_code)]
    pub fn print(&self) {
        print!("nodes {} ({}) {} ({}) ", self.min_tot_nodes, self.min_tot_nodes_quorum, self.max_tot_nodes, self.max_tot_nodes_quorum);
        print!("honest {} ({}) {} ({}) ", self.min_tot_honest, self.min_tot_honest_quorum, self.max_tot_honest, self.max_tot_honest_quorum);
        print!("malicious {} ({}) {} ({}) ", self.min_tot_malicious, self.min_tot_malicious_quorum, self.max_tot_malicious, self.max_tot_malicious_quorum);
        print!("lastjoin {} ({}) {} ({}) ", self.min_tot_last_join, self.min_tot_last_join_quorum, self.max_tot_last_join, self.max_tot_last_join_quorum);
        println!("b_0 {} ({}) {} ({})", self.min_b_0, self.min_b_0_quorum, self.max_b_0, self.max_b_0_quorum);
    }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct CumulativeStats {
    pub max_tot_honest: NodeCount,
    pub min_tot_honest: NodeCount,
    pub min_tot_malicious: NodeCount,
    pub max_tot_malicious: NodeCount,
    pub min_tot_nodes: NodeCount,
    pub max_tot_nodes: NodeCount,
    pub min_age: TimeCount,
    pub max_age: TimeCount,
    pub min_b_0: f64,
    pub max_b_0: f64,
}

impl CumulativeStats {
    #[allow(dead_code)]
    pub fn print(&self) {
        println!("Total nodes: min {} max {}, honest: min {} max {}, malicious: min {} max {}, b_0: min {} max {}",
            self.min_tot_nodes, self.max_tot_nodes,
            self.min_tot_honest, self.max_tot_honest,
            self.min_tot_malicious, self.max_tot_malicious,
            self.min_b_0, self.max_b_0);
    }
}
