awt 0.1.0

A simulation engine which can emulate a client/server with multiple requests.
use core::fmt::{Debug, Display};
use std::cell::{Ref, RefCell};
use std::collections::HashMap;
use std::rc::Rc;

use super::{Request, RequestStatus};
use crate::{Metric, MetricType};

#[derive(Default)]
pub struct Statistics {
    metrics: HashMap<MetricType, Metric>,
    calculated: bool,
}

fn report(m: &mut Metric, r: &Ref<'_, Request>) {
    match m.metric() {
        MetricType::ServiceLevel(ticks) if &RequestStatus::Answered == r.status() => {
            if let Some(tick) = r.wait_time() {
                m.report_bool(tick <= ticks);
            }
        }
        MetricType::AverageWorkTime if &RequestStatus::Answered == r.status() => {
            if let Some(tick) = r.handle_time() {
                m.report_duration(tick);
            }
        }
        MetricType::AverageSpeedAnswer if &RequestStatus::Answered == r.status() => {
            if let Some(tick) = r.wait_time() {
                m.report_duration(tick);
            }
        }
        MetricType::AverageTimeToAbandon if &RequestStatus::Abandoned == r.status() => {
            if let Some(tick) = r.wait_time() {
                m.report_duration(tick);
            }
        }
        MetricType::AbandonRate => m.report_bool(&RequestStatus::Abandoned == r.status()),
        MetricType::AverageTimeInQueue => {
            if let Some(tick) = r.wait_time() {
                m.report_duration(tick);
            }
        }
        MetricType::AnswerCount if &RequestStatus::Answered == r.status() => m.report(),
        MetricType::UtilisationTime => todo!(),
        _ => (),
    }
}

impl Display for Statistics {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for metric in self.metrics.values() {
            writeln!(
                f,
                "{:20} {:<5} {}",
                format!("{:?}", metric.metric()),
                metric.on_target(),
                metric
            )?;
        }
        Ok(())
    }
}

impl Debug for Statistics {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for metric in &self.metrics {
            writeln!(f, "{metric:?}")?;
        }
        Ok(())
    }
}

impl Statistics {
    pub fn push(&mut self, m: Metric) {
        self.metrics.insert(m.metric(), m);
    }

    #[allow(dead_code)]
    pub fn get(&self, m: &MetricType) -> Option<&Metric> {
        self.metrics.get(m)
    }

    pub fn calculate(&mut self, requests: &Vec<Rc<RefCell<Request>>>) {
        if self.calculated {
            return;
        }

        for request in requests {
            for metric in &mut self.metrics.values_mut() {
                report(metric, &request.borrow());
            }
        }
    }
}