use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use crate::rdm_cache::RdmCache;
use crate::skos::{parse_skos_to_collections, SkosCollection};
use crate::StaticGraph;
lazy_static::lazy_static! {
static ref GRAPH_REGISTRY: RwLock<HashMap<String, Arc<StaticGraph>>> =
RwLock::new(HashMap::new());
static ref GLOBAL_RDM_CACHE: RwLock<Option<RdmCache>> = RwLock::new(None);
static ref LIST_DATATYPE_REGISTRY: RwLock<HashSet<String>> = {
let mut set = HashSet::new();
set.insert("concept-list".to_string());
set.insert("resource-instance-list".to_string());
set.insert("domain-value-list".to_string());
RwLock::new(set)
};
static ref WIDGET_MAPPING_REGISTRY: RwLock<HashMap<String, String>> =
RwLock::new(HashMap::new());
static ref WIDGET_REGISTRY: RwLock<HashMap<String, RegisteredWidget>> =
RwLock::new(HashMap::new());
}
#[derive(Debug, Clone)]
pub struct RegisteredWidget {
pub id: String,
pub name: String,
pub datatype: String,
pub default_config: serde_json::Value,
}
impl RegisteredWidget {
pub fn new(id: &str, name: &str, datatype: &str, default_config_json: &str) -> Self {
Self {
id: id.to_string(),
name: name.to_string(),
datatype: datatype.to_string(),
default_config: serde_json::from_str(default_config_json)
.unwrap_or(serde_json::Value::Object(serde_json::Map::new())),
}
}
pub fn get_default_config(&self) -> serde_json::Value {
self.default_config.clone()
}
}
pub fn register_graph(graph_id: &str, graph: Arc<StaticGraph>) {
if let Ok(mut registry) = GRAPH_REGISTRY.write() {
registry.insert(graph_id.to_string(), graph);
}
}
pub fn register_graph_owned(graph: StaticGraph) {
let graph_id = graph.graph_id().to_string();
register_graph(&graph_id, Arc::new(graph));
}
pub fn get_graph(graph_id: &str) -> Option<Arc<StaticGraph>> {
GRAPH_REGISTRY
.read()
.ok()
.and_then(|registry| registry.get(graph_id).cloned())
}
pub fn is_graph_registered(graph_id: &str) -> bool {
GRAPH_REGISTRY
.read()
.ok()
.map(|registry| registry.contains_key(graph_id))
.unwrap_or(false)
}
pub fn unregister_graph(graph_id: &str) -> Option<Arc<StaticGraph>> {
GRAPH_REGISTRY
.write()
.ok()
.and_then(|mut registry| registry.remove(graph_id))
}
pub fn clear_registry() {
if let Ok(mut registry) = GRAPH_REGISTRY.write() {
registry.clear();
}
}
pub fn registry_size() -> usize {
GRAPH_REGISTRY
.read()
.ok()
.map(|registry| registry.len())
.unwrap_or(0)
}
pub fn get_registered_graph_ids() -> Vec<String> {
GRAPH_REGISTRY
.read()
.ok()
.map(|registry| registry.keys().cloned().collect())
.unwrap_or_default()
}
pub fn register_list_datatype(datatype: &str) {
if let Ok(mut registry) = LIST_DATATYPE_REGISTRY.write() {
registry.insert(datatype.to_string());
}
}
pub fn is_list_datatype(datatype: &str) -> bool {
LIST_DATATYPE_REGISTRY
.read()
.ok()
.map(|registry| registry.contains(datatype))
.unwrap_or(false)
}
pub fn unregister_list_datatype(datatype: &str) -> bool {
LIST_DATATYPE_REGISTRY
.write()
.ok()
.map(|mut registry| registry.remove(datatype))
.unwrap_or(false)
}
pub fn list_datatypes() -> Vec<String> {
LIST_DATATYPE_REGISTRY
.read()
.ok()
.map(|registry| registry.iter().cloned().collect())
.unwrap_or_default()
}
pub fn register_widget_for_datatype(datatype: &str, widget_name: &str) {
if let Ok(mut registry) = WIDGET_MAPPING_REGISTRY.write() {
registry.insert(datatype.to_string(), widget_name.to_string());
}
}
pub fn get_widget_for_datatype(datatype: &str) -> Option<String> {
WIDGET_MAPPING_REGISTRY
.read()
.ok()
.and_then(|registry| registry.get(datatype).cloned())
}
pub fn unregister_widget_for_datatype(datatype: &str) -> Option<String> {
WIDGET_MAPPING_REGISTRY
.write()
.ok()
.and_then(|mut registry| registry.remove(datatype))
}
pub fn widget_mappings() -> Vec<(String, String)> {
WIDGET_MAPPING_REGISTRY
.read()
.ok()
.map(|registry| {
registry
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect()
})
.unwrap_or_default()
}
pub fn register_widget(widget: RegisteredWidget) {
if let Ok(mut registry) = WIDGET_REGISTRY.write() {
registry.insert(widget.name.clone(), widget);
}
}
pub fn get_registered_widget(name: &str) -> Option<RegisteredWidget> {
WIDGET_REGISTRY
.read()
.ok()
.and_then(|registry| registry.get(name).cloned())
}
pub fn unregister_widget(name: &str) -> Option<RegisteredWidget> {
WIDGET_REGISTRY
.write()
.ok()
.and_then(|mut registry| registry.remove(name))
}
pub fn registered_widgets() -> Vec<String> {
WIDGET_REGISTRY
.read()
.ok()
.map(|registry| registry.keys().cloned().collect())
.unwrap_or_default()
}
pub fn set_global_rdm_cache(cache: RdmCache) {
if let Ok(mut guard) = GLOBAL_RDM_CACHE.write() {
*guard = Some(cache);
}
}
pub fn get_global_rdm_cache() -> Option<RdmCache> {
GLOBAL_RDM_CACHE.read().ok().and_then(|guard| guard.clone())
}
pub fn has_global_rdm_cache() -> bool {
GLOBAL_RDM_CACHE
.read()
.ok()
.map(|guard| guard.is_some())
.unwrap_or(false)
}
pub fn clear_global_rdm_cache() {
if let Ok(mut guard) = GLOBAL_RDM_CACHE.write() {
*guard = None;
}
}
pub fn with_global_rdm_cache<F, R>(f: F) -> Option<R>
where
F: FnOnce(&RdmCache) -> R,
{
GLOBAL_RDM_CACHE
.read()
.ok()
.and_then(|guard| guard.as_ref().map(f))
}
pub fn with_global_rdm_cache_mut<F, R>(f: F) -> Option<R>
where
F: FnOnce(&mut RdmCache) -> R,
{
GLOBAL_RDM_CACHE
.write()
.ok()
.and_then(|mut guard| guard.as_mut().map(f))
}
pub fn ensure_global_rdm_cache<F, R>(f: F) -> R
where
F: FnOnce(&mut RdmCache) -> R,
{
let mut guard = GLOBAL_RDM_CACHE.write().expect("RDM cache lock poisoned");
if guard.is_none() {
*guard = Some(RdmCache::default());
}
f(guard.as_mut().unwrap())
}
pub fn add_to_global_rdm_cache_from_skos(collections: &[SkosCollection]) -> Vec<String> {
ensure_global_rdm_cache(|cache| cache.add_from_skos_collections(collections))
}
pub fn add_to_global_rdm_cache_from_skos_xml(
xml_content: &str,
base_uri: &str,
) -> Result<Vec<String>, String> {
let collections = parse_skos_to_collections(xml_content, base_uri)?;
Ok(add_to_global_rdm_cache_from_skos(&collections))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::StaticGraph;
fn create_test_graph(graph_id: &str) -> StaticGraph {
let json = format!(
r#"{{
"graphid": "{}",
"name": {{"en": "Test Graph"}},
"nodes": [{{
"nodeid": "root",
"name": "Root",
"datatype": "semantic",
"graph_id": "{}"
}}],
"root": {{
"nodeid": "root",
"name": "Root",
"datatype": "semantic",
"graph_id": "{}"
}}
}}"#,
graph_id, graph_id, graph_id
);
StaticGraph::from_json_string(&json).expect("Failed to create test graph")
}
#[test]
fn test_register_and_get() {
let graph = create_test_graph("test-graph-1");
register_graph_owned(graph);
let retrieved = get_graph("test-graph-1");
assert!(retrieved.is_some());
assert_eq!(retrieved.unwrap().graphid, "test-graph-1");
unregister_graph("test-graph-1");
}
#[test]
fn test_is_registered() {
assert!(!is_graph_registered("nonexistent"));
let graph = create_test_graph("test-graph-2");
register_graph_owned(graph);
assert!(is_graph_registered("test-graph-2"));
assert!(!is_graph_registered("nonexistent"));
unregister_graph("test-graph-2");
}
#[test]
fn test_unregister() {
let graph = create_test_graph("test-graph-3");
register_graph_owned(graph);
assert!(is_graph_registered("test-graph-3"));
let removed = unregister_graph("test-graph-3");
assert!(removed.is_some());
assert!(!is_graph_registered("test-graph-3"));
}
}