Files
rota/src-tauri/src/config.rs

156 lines
4.1 KiB
Rust

use anyhow::Context;
use chrono::Month;
use serde::{Deserialize, Serialize};
use crate::{
resident::{Resident, ResidentDTO, ResidentId},
slot::Day,
};
const MONTH: u8 = 2;
const YEAR: i32 = 2026;
#[derive(Debug, Clone)]
pub struct ToxicPair((ResidentId, ResidentId));
impl ToxicPair {
pub fn new(res_id_1: u8, res_id_2: u8) -> Self {
Self((ResidentId(res_id_1), ResidentId(res_id_2)))
}
pub fn matches(&self, other: &ToxicPair) -> bool {
let p1 = &self.0;
let p2 = &other.0;
(p1.0 == p2.0 && p1.1 == p2.1) || (p1.0 == p2.1 && p1.1 == p2.0)
}
}
impl From<(ResidentId, ResidentId)> for ToxicPair {
fn from(value: (ResidentId, ResidentId)) -> Self {
Self((value.0, value.1))
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserConfigDTO {
month: u8,
year: i32,
holidays: Vec<u8>,
residents: Vec<ResidentDTO>,
toxic_pairs: Vec<(u8, u8)>,
}
#[derive(Debug, Clone)]
pub struct UserConfig {
pub month: Month,
pub year: i32,
pub holidays: Vec<u8>,
pub residents: Vec<Resident>,
pub toxic_pairs: Vec<ToxicPair>,
pub total_days: u8,
pub total_slots: u8,
pub total_holiday_slots: u8,
}
impl UserConfig {
pub fn with_holidays(mut self, holidays: Vec<u8>) -> Self {
self.holidays = holidays;
self.total_holiday_slots = self.total_holiday_slots();
self
}
pub fn with_residents(mut self, residents: Vec<Resident>) -> Self {
self.residents = residents;
self
}
pub fn add(&mut self, resident: Resident) {
self.residents.push(resident);
}
pub fn with_toxic_pairs(mut self, toxic_pairs: Vec<ToxicPair>) -> Self {
self.toxic_pairs = toxic_pairs;
self
}
fn total_holiday_slots(&self) -> u8 {
(1..=self.total_days)
.filter(|&d| self.is_holiday_or_weekend_slot(d))
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum()
}
pub fn is_holiday_or_weekend_slot(&self, day: u8) -> bool {
let day = Day(day);
day.is_weekend(self.month.number_from_month(), self.year)
|| self.holidays.contains(&(day.0))
}
}
impl Default for UserConfig {
fn default() -> Self {
let month = Month::try_from(MONTH).unwrap();
let total_days = month.num_days(YEAR).unwrap();
let total_slots = (1..=total_days)
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum();
let total_holiday_slots = (1..=total_days)
.filter(|&d| Day(d).is_weekend(month.number_from_month(), YEAR))
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum();
Self {
month,
year: YEAR,
holidays: vec![],
residents: vec![],
toxic_pairs: vec![],
total_days,
total_slots,
total_holiday_slots,
}
}
}
impl TryFrom<UserConfigDTO> for UserConfig {
type Error = anyhow::Error;
fn try_from(value: UserConfigDTO) -> Result<Self, Self::Error> {
let month = Month::try_from(value.month)?;
let total_days = month.num_days(value.year).context("Failed to parse")?;
let total_slots = (1..=total_days)
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum();
let total_holiday_slots = (1..=total_days)
.filter(|&d| {
Day(d).is_weekend(month.number_from_month(), value.year)
|| value.holidays.contains(&d)
})
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum();
Ok(Self {
month,
year: value.year,
holidays: value.holidays,
residents: value.residents.into_iter().map(Resident::from).collect(),
toxic_pairs: value
.toxic_pairs
.into_iter()
.map(|p| ToxicPair::new(p.0, p.1))
.collect(),
total_days,
total_slots,
total_holiday_slots,
})
}
}