hgame 0.26.4

CG production management structs, e.g. of assets, personnels, progress, etc.
Documentation
use super::*;
use std::cmp;

#[cfg(feature = "ticket")]
use crate::ticket::SubTicket;

#[cfg(feature = "gui")]
use egui_extras::TableRow;

#[derive(Debug, Clone, Default)]
/// Ratio of subticket statuses within a container [`Ticket`].
pub struct TicketTally {
    // `SubTicketClass`
    defects: u8,
    direction: u8,
    // `SubTicketStatus`
    addressed: u8,
    closed: u8,
    //
    pub total: u8,
}

impl TicketTally {
    #[cfg(feature = "ticket")]
    pub(crate) fn from_subtickets(subtickets: Option<&[SubTicket]>) -> Self {
        use crate::ticket::SubTicketClass;

        if let Some(subtickets) = subtickets {
            let iter = || subtickets.iter();
            Self {
                defects: iter().filter(|s| s.class == SubTicketClass::Defect).count() as u8,
                direction: iter()
                    .filter(|s| s.class == SubTicketClass::Direction)
                    .count() as u8,
                addressed: iter().filter(|s| s.is_addressed()).count() as u8,
                closed: iter().filter(|s| s.is_closed()).count() as u8,
                total: iter().len() as u8,
            }
        } else {
            Self::default()
        }
    }

    fn open_count(&self) -> u8 {
        self.total - self.closed
    }

    /// Announcement when a `Ticket` gets created.
    pub fn genesis_headline(&self) -> String {
        match self.total.cmp(&1) {
            Ordering::Greater => format!("New Ticket comprising of {} Subtickets", self.total),
            Ordering::Equal => "New Ticket containing a single Subticket".to_owned(),
            Ordering::Less => "New empty Ticket".to_owned(),
        }
    }

    /// Announcement when a [`SubTicket`] gets closed.
    pub fn progress_headline(&self) -> String {
        format!(
            "Closed. ☞ {} open Subtickets remaining. Please address",
            self.open_count() - self.addressed - 1
        )
    }

    /// Zero addressed and zero closed.
    pub fn all_open(total: u8) -> Self {
        Self {
            total,
            ..Default::default()
        }
    }

    #[cfg(feature = "gui")]
    pub fn ui(&self, ui: &mut egui::Ui) {
        // uses `Self::fmt` below
        ui.strong(format!("{}", &self));
    }

    /// Whether `Self::closed` is 1 smaller than `Self::total`.
    pub fn is_next_to_all_closed(&self) -> bool {
        self.total - self.closed == 1
    }

    #[cfg(feature = "gui")]
    /// NOTE: strictly THREE columns.
    pub fn subticket_class_row_ui(&self, mut row: TableRow) {
        // Defects
        row.col(|ui| {
            ui.label(format!("{}", self.defects));
        });
        // Direction
        row.col(|ui| {
            ui.label(format!("{}", self.direction));
        });
        // Total
        row.col(|ui| {
            ui.strong(format!("{}", self.total));
        });
    }
}

impl fmt::Display for TicketTally {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match &self.closed.cmp(&self.total) {
            cmp::Ordering::Less => {
                match &self.closed.cmp(&0) {
                    cmp::Ordering::Greater => {
                        write!(
                            f,
                            "{} addressed 🙋, {} closed ✅, {} open 💬",
                            self.addressed,
                            self.closed,
                            self.open_count()
                        )
                    }
                    _ => {
                        // none was addressed, so we care about open items
                        write!(
                            f,
                            "{} open 💬 of {} total",
                            self.total - self.closed,
                            self.total
                        )
                    }
                }
            }
            cmp::Ordering::Equal => match &self.total {
                0 => {
                    write!(f, "No subticket found")
                }
                1 => {
                    write!(f, "Single subticket closed")
                }
                _ => write!(f, "All {} closed", self.total),
            },
            cmp::Ordering::Greater => {
                // shouldn't happen
                unreachable!()
            }
        }
    }
}