use crate::libs::data_storage::DataStorage;
use anyhow::Result;
use rust_xlsxwriter::Color;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FontSpec {
pub name: String,
pub size: f64,
#[serde(default)]
pub bold: bool,
}
impl FontSpec {
fn new(name: &str, size: f64, bold: bool) -> Self {
Self {
name: name.to_string(),
size,
bold,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateFonts {
pub title: FontSpec,
pub month: FontSpec,
pub date: FontSpec,
pub header: FontSpec,
pub time: FontSpec,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportTemplate {
pub fonts: TemplateFonts,
pub border_color: String,
pub header_fill: String,
pub col_widths: [f64; 5],
pub data_row_height: f64,
pub title_row_height: f64,
pub show_hours_column: bool,
pub show_result_column: bool,
pub show_comment: bool,
pub comment_rows: u32,
}
impl ReportTemplate {
pub fn siserver() -> Self {
Self {
fonts: TemplateFonts {
title: FontSpec::new("Verdana", 14.0, true),
month: FontSpec::new("Verdana", 14.0, false),
date: FontSpec::new("Verdana", 10.0, true),
header: FontSpec::new("Verdana", 10.0, true),
time: FontSpec::new("Verdana", 10.0, true),
},
border_color: "#333333".to_string(),
header_fill: "#C0C0C0".to_string(),
col_widths: [13.55, 13.55, 96.55, 14.89, 62.55],
data_row_height: 126.0,
title_row_height: 17.4,
show_hours_column: true,
show_result_column: true,
show_comment: true,
comment_rows: 11,
}
}
pub fn load(name: &str) -> Self {
let _ = Self::ensure_default_on_disk();
match Self::templates_dir() {
Ok(dir) => {
let path = dir.join(format!("{}.json", name));
match fs::read_to_string(&path) {
Ok(contents) => match serde_json::from_str::<ReportTemplate>(&contents) {
Ok(template) => template,
Err(_) => Self::siserver(),
},
Err(_) => Self::siserver(),
}
}
Err(_) => Self::siserver(),
}
}
pub fn ensure_default_on_disk() -> Result<()> {
let dir = Self::templates_dir()?;
let path = dir.join("siserver.json");
if !path.exists() {
let json = serde_json::to_string_pretty(&Self::siserver())?;
fs::write(&path, json)?;
}
Ok(())
}
fn templates_dir() -> Result<PathBuf> {
let dir = DataStorage::new().get_path("report_templates")?;
if !dir.exists() {
fs::create_dir_all(&dir)?;
}
Ok(dir)
}
pub fn parse_color(hex: &str, default: u32) -> Color {
let trimmed = hex.trim().trim_start_matches('#');
match u32::from_str_radix(trimmed, 16) {
Ok(value) if trimmed.len() == 6 => Color::RGB(value),
_ => Color::RGB(default),
}
}
pub fn border(&self) -> Color {
Self::parse_color(&self.border_color, 0x333333)
}
pub fn fill(&self) -> Color {
Self::parse_color(&self.header_fill, 0xC0C0C0)
}
}
impl Default for ReportTemplate {
fn default() -> Self {
Self::siserver()
}
}