use crate::imp::history::file_name::file_name_props::FileNameProps;
use crate::imp::history::file_hist::file_history_item::FileHistoryItem;
use crate::imp::history::file_hist::create_file_history::create_file_history;
use std::path::{Path, PathBuf};
use crate::error::FsResult;
use std::collections::BTreeMap;
use crate::imp::history::remove::history_remover::HistoryRemover;
use crate::imp::common::path::hash_dir_path::hash_dir_path;
#[derive(Debug)]
pub struct FileHistory{
ctls : BTreeMap<u32, FileHistoryItem>,
max_phase : usize,
cumulative : bool,
}
impl FileHistory{
pub(crate) fn new(max_phase : usize, cumulative : bool) -> FileHistory{
FileHistory{ ctls : BTreeMap::new(), max_phase, cumulative }
}
pub fn max_phase(&self) -> usize{ self.max_phase }
pub fn cumulative(&self) -> bool{ self.cumulative }
pub fn create<P : AsRef<Path>>(history_dir: P, hash : u128, max_phase : usize, cumulative : bool) -> FsResult<FileHistory>{
let dir = hash_dir_path(history_dir.as_ref(), hash);
create_file_history(&dir, max_phase, cumulative)
}
pub fn list_files(&self) -> Vec<&FileNameProps>{
let mut vec = vec![];
for (_,ctl) in &self.ctls{
ctl.flatten(&mut vec);
}
vec
}
pub fn get_removable_old_items(&self, keep_latest : usize) -> Vec<&FileNameProps>{
let files = self.list_files();
let remover = HistoryRemover::from(self);
let num_remove = files.len().saturating_sub(keep_latest);
for item in files.iter().skip(num_remove) {
remover.keep(*item);
}
let props = remover.get_removable_props();
props
}
pub fn remove_old_files<P:AsRef<Path>>(self, keep_latest : usize, history_hash_dir: P) -> Vec<PathBuf>{
let removables = self.get_removable_old_items(keep_latest);
unsafe{ Self::remove_files(removables.iter().map(|a| *a), history_hash_dir) }
}
pub unsafe fn remove_files<'a, P : AsRef<Path>>(filenames : impl Iterator<Item=&'a FileNameProps>, history_hash_dir: P) -> Vec<PathBuf>{
let dir_path = history_hash_dir.as_ref();
let mut r : Vec<PathBuf> = vec![];
for filename in filenames {
let file_path = dir_path.join(filename.calc_filename());
match std::fs::remove_file(&file_path){
Ok(_) =>{},
Err(_) =>{ r.push(file_path) }
}
}
r
}
pub fn newest_file_path(&self, history_hash_dir: &Path) -> Option<PathBuf>{
self.get_newest_prop().map(|props|{
let filename = props.calc_filename();
history_hash_dir.join(filename)
})
}
pub(crate) fn ctls(&self) -> &BTreeMap<u32, FileHistoryItem>{ &self.ctls }
fn newest_ctl(&self) -> Option<&FileHistoryItem>{
self.ctls.iter().last().map(|(_,item)| item)
}
pub(crate) fn get_newest_prop(&self) -> Option<&FileNameProps>{
let his = if let Some(control_his) = self.newest_ctl(){
control_his
} else{
return None;
};
his.get_newest_prop()
}
fn insert_or_get_mut(&mut self, control : u32) -> &mut FileHistoryItem {
if self.ctls.contains_key(&control) == false{
let new_his = FileHistoryItem::new();
self.ctls.insert(control, new_his);
}
self.ctls.get_mut(&control).unwrap()
}
pub(crate) fn add(&mut self, props : FileNameProps){
let mut his = self.insert_or_get_mut(props.control());
for &order in &props.order()[0..(props.order().len()-1)]{
his = his.insert_or_get_mut(order);
}
let index = props.order_last();
his.insert_props(index, props);
}
pub fn get_props(&self, ctl : u32, order : &[u32]) -> Option<&FileNameProps>{
if let Some(h) = self.ctls.get(&ctl){
h.get_props(order)
} else{
None
}
}
pub fn get_parent(&self, props : &FileNameProps) -> Option<&FileNameProps>{
self.get_props(props.prev_ctl(), props.order_base())
}
}