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::fields::sanity_check;

use anyhow;

use std::{
	fs::File,
	io::{BufRead, BufReader},
};

#[derive(Debug)]
pub struct Config {
	pub file_type: String,
	pub path: std::path::PathBuf,
	pub mode: String,
	pub user: String,
	pub group: String,
	pub age: String,
	pub argument: String,
}

pub fn parse(config_path: &std::path::Path) -> Result<Vec<Config>, anyhow::Error> {
	let mut return_config = Vec::new();

	let tmpfiles_config = read_config(config_path);
	match tmpfiles_config {
		Ok(cfg) => {
			for line in cfg {
				if line.len() >= 1 {
					let line: Vec<&str> = line.iter().map(|item| item.as_str()).collect();
					if line[0].chars().next().unwrap().to_string() == "#" {
						continue;
					}
					return_config.push(Config {
						file_type: String::from(line[0]),
						path: line[1].into(),
						mode: String::from(line[2]),
						user: String::from(line[3]),
						group: String::from(line[4]),
						age: String::from(line[5]),
						argument: String::from(line[6]),
					});
				}
			}
		}
		Err(e) => {
			anyhow::bail!("Parsing failed with error:\n{}", e);
		}
	}
	for config in &return_config {
		match sanity_check(config) {
			Ok(..) => (),
			Err(e) => anyhow::bail!("Parser sanity check failed with error:\n{}", e),
		}
	}
	Ok(return_config)
}

fn read_config(config_path: &std::path::Path) -> Result<Vec<Vec<String>>, anyhow::Error> {
	let mut return_vector = Vec::new();
	let file = File::open(config_path)?;
	for line in BufReader::new(file).lines().map_while(Result::ok) {
		let line: Vec<String> = line
			.split_whitespace()
			.map(|item| item.to_string())
			.collect();
		return_vector.push(line);
	}
	Ok(return_vector)
}