A tmpfiles.d implementation for UNIX-like operating systems.
// dtmp: A tmpfiles.d implementation for UNIX-like operating systems.
// Copyright (C) 2025  Aster Boese
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use crate::parser::Config;

/// Types available for usage in tmpfiles.d configuration files.
/// See https://www.freedesktop.org/software/systemd/man/latest/tmpfiles.d.html#Type
const VALID_TYPES: [&'static str; 26] = [
	"f", "w", "d", "D", "e", "v", "q", "Q", "p", "p+", "L", "c", "b", "C", "x", "X", "r", "R", "z",
	"Z", "t", "T", "h", "H", "a", "A",
];

/// Type modifiers for usage in tmpfiles.d configuration files.
/// See https://www.freedesktop.org/software/systemd/man/latest/tmpfiles.d.html#Type%20Modifiers
const VALID_TYPE_MODIFIERS: [&'static str; 6] = ["+", "!", "-", "=", "~", "^"];

/// Specifiers for usage in tmpfiles.d configuration files.
/// See https://www.freedesktop.org/software/systemd/man/latest/tmpfiles.d.html#Specifiers
const VALID_SPECIFIERS: [&'static str; 25] = [
	"%a", "%A", "%b", "%B", "%C", "%g", "%G", "%h", "%H", "%l", "%L", "%m", "%M", "%o", "%q", "%S",
	"%t", "%T", "%u", "%U", "%v", "%V", "%w", "%W", "%%",
];

pub fn sanity_check(config: &Config) -> Result<(), anyhow::Error> {
	let mut specifier_prefix: bool = false;
	if VALID_SPECIFIERS.contains(
		&config
			.file_type
			.as_str()) == true {
		specifier_prefix = true;
	}
	if VALID_TYPES.contains(
		&config
			.file_type
			.chars()
			.next()
			.unwrap()
			.to_string()
			.as_str(),
	) == false && specifier_prefix == false
	{
		anyhow::bail!("Invalid file type!");
	}
	if config.file_type.len() > 1 {
		if VALID_TYPE_MODIFIERS.contains(
			&config
				.file_type
				.chars()
				.nth(1)
				.unwrap()
				.to_string()
				.as_str(),
		) == false && specifier_prefix == false
		{
			anyhow::bail!("Invalid file type!")
		}
	}
	if !config.path.is_absolute() {
		anyhow::bail!("Path does not begin with the root!");
	}
	if config.mode.parse::<i32>().is_err() {
		if config.mode != "-" {
			anyhow::bail!("Invalid file mode!");
		}
	}
	Ok(())
}