use crate::instance::*;
use crate::repository::*;
use crate::semantics::Class;
use anyhow::{Ok, Result};
pub fn create_entity_frame(
tx: &mut ReadWriteTransaction,
parent_uid: &str,
uid: &str,
class: &Class,
) -> Result<()> {
let mut frame = Frame::init(tx, uid, parent_uid)?;
for spec in class.collects.iter() {
subscribe(&mut frame, &spec.class_name);
}
let frame_uid = frame.uid;
tx.save(&frame_uid)
}
pub fn remove_entity_frame(tx: &mut ReadWriteTransaction, uid: &str) -> Result<()> {
tx.remove(&format!("{}_frame", uid))
}
pub fn collect(
instance: &SandboxBuilder,
tx: &mut ReadWriteTransaction,
parent_uid: &str,
uid: &str,
class_name: &str,
) -> anyhow::Result<()> {
let mut frame_owner_uid: String = parent_uid.to_string();
while frame_owner_uid != "root" {
let parent_owner_uid = {
let frame = tx
.load(&format!("{}_frame", frame_owner_uid))
.unwrap()
.as_frame();
for parent in instance.sandbox.classes[class_name].hierarchy.iter() {
let unused = &mut frame.obj["$collections"]["$unused"];
if unused.as_object().unwrap().contains_key(parent) {
unused[parent]
.as_array_mut()
.unwrap()
.push(serde_json::to_value(uid).unwrap());
break;
}
}
frame.obj["$parent"].clone()
};
tx.save(&format!("{}_frame", frame_owner_uid))?;
frame_owner_uid = parent_owner_uid.as_str().unwrap().to_string();
}
Ok(())
}
pub fn withdraw(
instance: &SandboxBuilder,
tx: &mut ReadWriteTransaction,
origin_owner_uid: &str,
class_name: &str,
) -> anyhow::Result<()> {
let mut frame_owner_uid: String = origin_owner_uid.to_string();
while frame_owner_uid != "root" {
let parent_owner_uid = {
let frame = tx
.load(&format!("{}_frame", frame_owner_uid))
.unwrap()
.as_frame();
for parent in instance.sandbox.classes[class_name].hierarchy.iter() {
let unused = &mut frame.obj["$collections"]["$unused"];
if unused.as_object().unwrap().contains_key(parent) {
unused[parent]
.as_array_mut()
.unwrap()
.retain(|v| v != origin_owner_uid);
}
}
for parent in instance.sandbox.classes[class_name].hierarchy.iter() {
let used = &mut frame.obj["$collections"]["$unused"];
if used.as_object().unwrap().contains_key(parent) {
used[parent]
.as_array_mut()
.unwrap()
.retain(|v| v != origin_owner_uid);
}
}
frame.obj["$parent"].clone()
};
tx.save(&format!("{}_frame", frame_owner_uid))?;
frame_owner_uid = parent_owner_uid.as_str().unwrap().to_string();
}
Ok(())
}
pub fn use_collected(
instance: &SandboxBuilder,
tx: &mut ReadWriteTransaction,
origin_owner_uid: &str,
class_name: &str,
) -> Result<Option<String>> {
let mut ret: Option<String> = None;
let mut frame_owner_uid: String = origin_owner_uid.to_string();
while frame_owner_uid != "root" && ret.is_none() {
let parent_owner_uid = {
let frame = tx
.load(&format!("{}_frame", frame_owner_uid))
.unwrap()
.as_frame();
let unused = &mut frame.obj["$collections"]["$unused"];
if unused.as_object().unwrap().contains_key(class_name) {
let unused_list = unused[class_name].as_array().unwrap();
if unused_list.is_empty() {
return Ok(None);
}
let selected = instance
.randomizer
.in_range(0, unused_list.len() as i32 - 1);
let selected_uid = unused_list[selected as usize].clone();
unused[class_name]
.as_array_mut()
.unwrap()
.remove(selected as usize);
frame.obj["$collections"]["$used"][class_name]
.as_array_mut()
.unwrap()
.push(selected_uid.clone());
ret = Some(selected_uid.as_str().unwrap().to_string());
}
frame.obj["$parent"].clone()
};
tx.save(&format!("{}_frame", frame_owner_uid))?;
frame_owner_uid = parent_owner_uid.as_str().unwrap().to_string();
}
Ok(ret)
}
pub fn recycle(
tx: &mut ReadWriteTransaction,
origin_owner_uid: &str,
uid_to_recycle: &str,
class_name: &str,
) -> Result<()> {
let mut frame_owner_uid: String = origin_owner_uid.to_string();
while frame_owner_uid != "root" {
let parent_owner_uid = {
let frame = tx
.load(&format!("{}_frame", frame_owner_uid))
.unwrap()
.as_frame();
let unused = &mut frame.obj["$collections"]["$unused"];
if unused.as_object().unwrap().contains_key(class_name) {
unused[class_name]
.as_array_mut()
.unwrap()
.push(serde_json::Value::from(uid_to_recycle));
frame.obj["$collections"]["$used"][class_name]
.as_array_mut()
.unwrap()
.retain(|uid| uid != uid_to_recycle);
}
frame.obj["$parent"].clone()
};
tx.save(&format!("{}_frame", frame_owner_uid))?;
frame_owner_uid = parent_owner_uid.as_str().unwrap().to_string();
}
Ok(())
}
pub fn pick_collected(
instance: &SandboxBuilder,
tx: &mut ReadWriteTransaction,
origin_owner_uid: &str,
class_name: &str,
) -> Result<Option<String>> {
let mut ret: Option<String> = None;
let mut frame_owner_uid: String = origin_owner_uid.to_string();
while frame_owner_uid != "root" {
let parent_owner_uid = {
let frame = tx
.load(&format!("{}_frame", frame_owner_uid))
.unwrap()
.as_frame();
let unused = &mut frame.obj["$collections"]["$unused"];
if unused.as_object().unwrap().contains_key(class_name) {
let unused_list = unused[class_name].as_array().unwrap();
if unused_list.is_empty() {
return Ok(None);
}
let selected = instance
.randomizer
.in_range(0, unused_list.len() as i32 - 1);
let selected_uid = unused_list[selected as usize].clone();
ret = Some(selected_uid.as_str().unwrap().to_string());
break;
}
frame.obj["$parent"].clone()
};
tx.save(&format!("{}_frame", frame_owner_uid))?;
frame_owner_uid = parent_owner_uid.as_str().unwrap().to_string();
}
Ok(ret)
}
pub struct Frame<'a> {
pub uid: String,
pub obj: &'a mut serde_json::Value,
}
impl<'a> Frame<'a> {
pub fn from_value(v: &'a mut serde_json::Value) -> Self {
Frame {
uid: v["uid"].as_str().unwrap().to_string(),
obj: v,
}
}
pub fn init(
tx: &'a mut ReadWriteTransaction,
uid2: &'a str,
parent_uid: &'a str,
) -> Result<Self> {
let frame_uid = format!("{}_frame", uid2);
let frame = tx.create(&frame_uid)?.as_frame();
frame.obj["$parent"] = serde_json::Value::from(parent_uid);
let collections = &mut frame.obj["$collections"];
collections["$unused"] = serde_json::json!({});
collections["$used"] = serde_json::json!({});
Ok(frame)
}
}
pub trait FrameConvertor<'a> {
fn as_frame(&'a mut self) -> Frame<'a>;
}
impl<'b> FrameConvertor<'b> for serde_json::Value {
fn as_frame(&'b mut self) -> Frame<'b> {
Frame::from_value(self)
}
}
fn subscribe(frame: &mut Frame, class_name: &str) {
let collections = &mut frame.obj["$collections"];
collections["$unused"][class_name] = serde_json::json!([]);
collections["$used"][class_name] = serde_json::json!([]);
}