use std::fs::{File, rename};
use std::io::Read;
use std::fmt;
use std::time::{SystemTime, UNIX_EPOCH};
use tinyjson::JsonValue;
use crate::Errors;
use crate::IO::IOwrapper;
#[derive(Debug)]
pub struct WrapperJson
{
name: String,
path: String,
datas: JsonValue,
}
impl WrapperJson
{
fn file_get(&self, suffix: String) -> Result<(File, String), Errors>
{
let tmp_path = format!("{}{}", self.path, suffix);
let file;
if let Ok(tmp) = File::open(&tmp_path)
{
file = tmp;
} else {
file = File::create(&tmp_path).map_err(|err| Errors::ConfigCannotCreateFile(self.name.clone(), tmp_path.clone(), err))?;
}
return Ok((file,tmp_path));
}
fn file_content_get(&self) -> Result<String, Errors>
{
let (mut file,_) = self.file_get("".to_string())?;
let mut content = String::new();
if (file.read_to_string(&mut content).is_err() || content.is_empty())
{
content = "{}".to_string();
}
return Ok(content);
}
}
impl IOwrapper for WrapperJson
{
fn init(name: &String, path: &String) -> Result<WrapperJson, Errors>
{
let path = format!("{}.{}", path, "json");
let mut tmp = WrapperJson
{
name: name.clone(),
path: path.clone(),
datas: JsonValue::Object(Default::default()),
};
tmp.file_load()?;
return Ok(tmp);
}
fn file_load(&mut self) -> Result<(), Errors>
{
self.datas = self.file_content_get()?.parse()
.map_err(|e| Errors::ConfigCannotConvertFileToJsonValue(self.name.clone(), self.path.clone(), e))?;
return Ok(());
}
fn file_save(&self) -> Result<(), Errors>
{
let (mut tmp_file, path) = self.file_get(format!("_{}", SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_nanos().to_string()))?;
self.datas.format_to(&mut tmp_file)
.map_err(|e| Errors::ConfigCannotSaveFile(self.name.clone(), self.path.clone(), e))?;
rename(&path, self.path.clone())
.map_err(|e| Errors::ConfigCannotSaveFile(self.name.clone(), self.path.clone(), e))?;
return Ok(());
}
fn file_ext<'a>(&self) -> &'a str {
return "json";
}
fn file_path(&self) -> &String {
&self.path
}
fn root_get(&self) -> &JsonValue
{
return &self.datas;
}
fn root_get_mut(&mut self) -> &mut JsonValue
{
return &mut self.datas;
}
fn value_get(&self, path: String) -> Option<JsonValue>
{
let splitedPath: Vec<String> = path.split("/").map(|s| s.to_string()).collect();
return get_recursive(splitedPath, 0, &self.datas);
}
fn value_get_or_set(&mut self, path: String, default: JsonValue) -> JsonValue
{
let splitedPath: Vec<String> = path.split("/").map(|s| s.to_string()).collect();
let Some(value) = get_recursive(splitedPath.clone(), 0, &self.datas) else {
if let Some(defaultset) = set_recursive(splitedPath,0,&mut self.datas)
{
*defaultset = default.clone();
}
return default;
};
return value;
}
fn value_get_mut<'a,'b>(&'b mut self, path: String) -> Option<&'a mut JsonValue>
where 'b: 'a
{
let splitedPath: Vec<String> = path.split("/").map(|s| s.to_string()).collect();
return set_recursive(splitedPath, 0, &mut self.datas);
}
fn value_remove(&mut self, path: &str) -> bool {
let splitedPath: Vec<String> = path.split("/").map(|s| s.to_string()).collect();
let Some((last, parentPath)) = splitedPath.split_last() else {return false;};
let parent = match parentPath.is_empty() {
true => &mut self.datas,
false => {
let Some(parent) = set_recursive(parentPath.to_vec(), 0, &mut self.datas) else {return false;};
parent
}
};
match parent {
JsonValue::Array(childs) => {
if let Ok(last) = last.parse::<usize>()
{
if(last >= childs.len()) {return false;}
childs.remove(last);
return true;
}
}
JsonValue::Object(childs) => {
return (childs.remove(last).is_some());
}
_ => {},
}
return false;
}
fn value_set(&mut self, path: String, newval: JsonValue)
{
let splitedPath: Vec<String> = path.split("/").map(|s| s.to_string()).collect();
if let Some(oldvalue) = set_recursive(splitedPath, 0, &mut self.datas)
{
*oldvalue = newval.into();
}
}
}
impl fmt::Display for WrapperJson {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match &self.datas {
JsonValue::Number(x) => write!(f, "{}", x),
JsonValue::Boolean(x) => write!(f, "{}", x),
JsonValue::String(x) => write!(f, "{}", x),
JsonValue::Null => write!(f, "null"),
JsonValue::Array(x) => write!(f, "{:#?}", x),
JsonValue::Object(x) => write!(f, "{:#?}", x),
}
}
}
fn get_recursive(splintedPath: Vec<String>, i: usize, parent: &JsonValue) -> Option<JsonValue>
{
let Some(thisdir) = splintedPath.get(i) else
{
return None;
};
if let JsonValue::Array(parentAsArray) = &parent
{
if let Ok(tryingint) = thisdir.parse::<usize>()
{
if (tryingint >= parentAsArray.len())
{
return None;
}
else if (i + 1 < splintedPath.len())
{
return get_recursive(splintedPath.clone(), i + 1, parentAsArray.get(tryingint).unwrap());
}
return Some(parentAsArray[tryingint].clone());
}
return None;
}
else if let JsonValue::Object(parentAsObject) = &parent
{
if (!parentAsObject.contains_key(thisdir))
{
return None;
}
else if (i + 1 < splintedPath.len())
{
return get_recursive(splintedPath.clone(), i + 1, parentAsObject.get(thisdir).unwrap());
}
return Some(parentAsObject[thisdir].clone());
}
else
{
return None;
}
}
fn set_recursive(splintedPath: Vec<String>, i: usize, parent: &mut JsonValue) -> Option<&mut JsonValue>
{
let Some(thisdir) = splintedPath.get(i) else
{
return None;
};
match parent {
JsonValue::Object(parentAsObject) => {
if (!parentAsObject.contains_key(thisdir))
{
parentAsObject.insert(thisdir.clone(),JsonValue::Object(Default::default()));
}
if (i + 1 < splintedPath.len())
{
return set_recursive(splintedPath.clone(), i + 1, parentAsObject.get_mut(thisdir).unwrap());
}
return parentAsObject.get_mut(thisdir);
}
JsonValue::Array(parentAsArray) => {
if let Ok(tryingint) = thisdir.parse::<usize>()
{
if (tryingint < parentAsArray.len())
{
return None;
}
else if (i + 1 < splintedPath.len())
{
return set_recursive(splintedPath.clone(), i + 1, parentAsArray.get_mut(tryingint).unwrap());
}
return parentAsArray.get_mut(tryingint);
}
return None;
}
_ => {}
}
return None;
}