pub static HOBBIT_STORAGE: &str = "/var/tmp/hdb/";
macro_rules! unwrap_or_return {
    ( $e:expr ) => {
        match $e {
            Ok(x) => x,
            Err(e) => return Err(e.to_string()),
        }
    };
}
macro_rules! some_or_return {
    ( $e:expr ) => {
        match $e {
            Some(x) => x.to_string(),
            _ => return Err("None".to_string()),
        }
    };
}
fn trim_slash(s: &str) -> String {
    let trim_len = match s.rfind('/') {
        None => 0,
        Some(i) => {
            if i == s.len() - 1 {
                i
            } else {
                i + 1
            }
        }
    };
    let trimmed = &s[..trim_len];
    trimmed.to_string()
}
pub fn get(table: &str, key: &str) -> Result<String, String> {
    let path = format!("{}{}", HOBBIT_STORAGE, table);
    if let Ok(data) = std::fs::read_to_string(&path) {
        let json: serde_json::Value = unwrap_or_return!(serde_json::from_str(&data));
        return Ok(some_or_return!(json[key].as_str()));
    }
    let error = format!("Error reading table '{}'", table);
    Err(error)
}
pub fn set(table: &str, key: &str, value: &str) -> Result<(), String> {
    let _ = make(table);
    let path = format!("{}{}", HOBBIT_STORAGE, table);
    if let Ok(data) = std::fs::read_to_string(&path) {
        let mut json: serde_json::Value = unwrap_or_return!(serde_json::from_str(&data));
        json[key] = serde_json::Value::String(value.to_string());
        return match std::fs::write(&path, json.to_string()) {
            Ok(_) => Ok(()),
            Err(e) => Err(e.to_string()),
        };
    }
    let error = format!("Error reading table '{}'", table);
    Err(error)
}
pub fn del(table: &str, key: &str) -> Result<(), String> {
    let path = format!("{}{}", HOBBIT_STORAGE, table);
    if let Ok(data) = std::fs::read_to_string(&path) {
        let json: serde_json::Value = unwrap_or_return!(serde_json::from_str(&data));
        match json {
            serde_json::Value::Object(mut map) => {
                map.remove(key);
                if map.len() == 0 {
                    let _ = std::fs::remove_file(&path);
                    let _ = std::fs::remove_dir(trim_slash(&path));
                    return Ok(());
                } else {
                    let v: serde_json::Value = map.into();
                    return match std::fs::write(&path, v.to_string()) {
                        Ok(_) => Ok(()),
                        Err(e) => Err(e.to_string()),
                    };
                }
            }
            _ => return Err("Key not found".to_string()),
        }
    }
    let error = format!("Error reading table '{}'", table);
    Err(error)
}
fn make(table: &str) -> Result<(), String> {
    let _ = std::fs::create_dir_all(HOBBIT_STORAGE);
    let path = format!("{}{}", HOBBIT_STORAGE, table);
    let _ = std::fs::create_dir_all(trim_slash(&path));
    if !std::fs::metadata(path.to_string()).is_ok() {
        let data = serde_json::json!({});
        match std::fs::write(path.to_string(), data.to_string()) {
            Ok(_) => return Ok(()),
            Err(e) => return Err(e.to_string()),
        }
    }
    Ok(())
}
pub fn map(table: &str) -> Result<serde_json::Map<String, serde_json::Value>, String> {
    let path = format!("{}{}", HOBBIT_STORAGE, table);
    if let Ok(data) = std::fs::read_to_string(&path) {
        let json: serde_json::Value = unwrap_or_return!(serde_json::from_str(&data));
        match json {
            serde_json::Value::Object(map) => {
                return Ok(map);
            }
            _ => return Err("Could not parse table as Map".to_string()),
        }
    }
    let error = format!("Error reading table '{}'", table);
    Err(error)
}