organicomplex 0.7.0

Interactive complex-valued cellular automaton on 2D and 3D grids in search of that stuff - emergence, open-endedness, organicity etc.
use std::{
    collections::HashMap,
    fs
};

use serde_json::Value;

use crate::base::{
    BASE_DIR,
    JEXT,
    PrependErrorString
};

use crate::sys::System;

const LINGUA_DIR: &str = "lingua";

pub struct Lingua {
    lang: String,
    lingua_map: HashMap<String, Vec<String>>, // id to text(s) in lang language
    prefix: String
}

impl Lingua {
    pub fn new(sys: &System) -> Self {
        let lang = sys.lang();
        let lingua_map = HashMap::<String, Vec<String>>::new();
        let prefix = String::new();
        Self{lang, lingua_map, prefix}
    }

    pub fn load(&mut self, lingua_filepaths_noext: &[impl ToString]) -> Result<(), String> {
        for lingua_filepath_noext in lingua_filepaths_noext {
            let filepath = format!("{}/{}/{}/{}.{}", BASE_DIR, LINGUA_DIR, & self.lang, lingua_filepath_noext.to_string(), JEXT);
            let b = fs::read(&filepath).pre_err(format!("cannot read '{}'", &filepath))?;
            let v: Value = serde_json::from_slice(&b).pre_err(format!("cannot parse '{}'", &filepath))?;

            match v.as_object() {
                Some(objmap) => {
                    for (id, val) in objmap {
                        let id = id.clone();
                        let texts = if val.is_string() {
                            vec![val.as_str().unwrap().to_string()]
                        } else if val.is_array() {
                            let texts_values = val.as_array().unwrap();
                            let mut texts = Vec::<String>::new();
                            for sv in texts_values {
                                match sv.as_str() {
                                    Some(text) => {
                                        texts.push(text.to_string());
                                    },
                                    None => {
                                        return Err(format!("cannot load '{}': array-value of id-key '{}' contains not only strings, ({:?})", &filepath, &id, sv))
                                    }
                                }
                            }
                            texts
                        } else {
                            return Err(format!("cannot load '{}': value of id-key '{}' is neither a string, nor an array of strings", &filepath, &id));
                        };
                        let prefixed_id = format!("{}:{}", lingua_filepath_noext.to_string(), &id);
                        match self.lingua_map.insert(prefixed_id.clone(), texts) {
                            Some(..) => return Err(format!("cannot load '{}': id-key '{}' exists already", &filepath, &prefixed_id)),
                            None => {}
                        };
                    }
                },
                None => return Err(format!("cannot load '{}': content is not a json object", &filepath))
            }
        }

        Ok(())
    }

    pub fn set_prefix(&mut self, prefix: impl ToString) {
        self.prefix = format!("{}:", prefix.to_string());
    }

    pub fn clear_prefix(&mut self) {
        self.prefix.clear();
    }

    #[allow(dead_code)]
    pub fn get1(&self, id: impl ToString) -> Option<String> {
        let id = format!("{}{}", &self.prefix, id.to_string());
        self.lingua_map.get(&id).map(|texts| texts[0].clone())
    }

    #[allow(dead_code)]
    pub fn get1_or_echo(&self, id: impl ToString) -> String {
        let prefixed_id = format!("{}{}", &self.prefix, id.to_string());
        self.get1(id).unwrap_or_else(|| format!("{{{}}}", &prefixed_id)) // "{prefix:id}"
    }

    #[allow(dead_code)]
    pub fn get(&self, id: impl ToString) -> Option<Vec<String>> {
        let id = format!("{}{}", &self.prefix, id.to_string());
        self.lingua_map.get(&id).map(|texts| texts.clone())
    }

    #[allow(dead_code)]
    pub fn get_or_echo(&self, id: impl ToString) -> Vec<String> {
        let prefixed_id = format!("{}{}", &self.prefix, id.to_string());
        self.get(id).unwrap_or_else(|| vec![format!("{{{} 0}}", &prefixed_id)]) // ["{prefix:id 0}"]
    }

}