use crate::utils::event::{Event, MessageQueue};
use crate::inventory::items::InventoryItem;
use crate::inventory::crafting::CraftingCombination;
use crate::inventory::monitors::InventoryMonitor;
use crate::error::InventoryUseErr;
use std::collections::{HashMap, BTreeMap};
use std::cell::{Cell, RefCell, RefMut};
use std::sync::Arc;
use std::rc::Rc;
mod crud;
mod update;
pub(crate) mod state;
pub mod items;
pub mod crafting;
pub mod monitors;
pub struct Inventory {
pub items: Arc<RefCell<HashMap<String, Box<dyn InventoryItem>>>>,
pub inventory_monitors: Rc<RefCell<HashMap<usize, Box<dyn InventoryMonitor>>>>,
weight: Cell<f32>,
crafting_combinations: Rc<RefCell<HashMap<String, CraftingCombination>>>,
clothes_cache: RefCell<Vec<String>>,
message_queue: RefCell<BTreeMap<usize, Event>>
}
impl Inventory {
pub(crate) fn new() -> Self {
Inventory {
items: Arc::new(RefCell::new(HashMap::new())),
crafting_combinations: Rc::new(RefCell::new(HashMap::new())),
inventory_monitors: Rc::new(RefCell::new(HashMap::new())),
weight: Cell::new(0.),
message_queue: RefCell::new(BTreeMap::new()),
clothes_cache: RefCell::new(Vec::new())
}
}
pub fn get_count_of(&self, name: &String) -> Option<usize> {
self.items.borrow().get(name).map(|x| x.get_count())
}
pub fn get_weight_of(&self, name: &String) -> Option<f32> {
self.items.borrow().get(name).map(|x| x.get_total_weight())
}
pub fn use_item(&self, name: &String, amount: usize) -> Result<(), InventoryUseErr> {
{
let mut b = self.items.borrow_mut();
self.use_item_internal(name, amount, &mut b)?;
}
self.recalculate_weight();
Ok(())
}
fn use_item_internal(&self, name: &String, amount: usize, items_mut: &mut HashMap<String, Box<dyn InventoryItem>>) -> Result<(), InventoryUseErr> {
match items_mut.get_mut(name) {
Some(o) => {
if o.get_is_infinite() {
self.queue_message(Event::InventoryItemUsedPartially(name.to_string(), amount));
return Ok(());
}
let c = o.get_count();
if amount > c { return Err(InventoryUseErr::InsufficientResources) }
if c - amount == 0 {
items_mut.remove(name);
self.queue_message(Event::InventoryItemUsedAll(name.to_string(), amount));
} else {
o.set_count(c - amount);
self.queue_message(Event::InventoryItemUsedPartially(name.to_string(), amount));
}
},
None => return Err(InventoryUseErr::ItemNotFound)
};
Ok(())
}
pub fn get_weight(&self) -> f32 { self.weight.get() }
pub fn recalculate_weight(&self) {
let old_weight = self.weight.get();
let mut new_weight: f32;
new_weight = 0.;
let cc = self.clothes_cache.borrow();
for (name, item) in self.items.borrow().iter() {
if !cc.contains(name) {
new_weight += item.get_total_weight();
}
}
self.weight.set(new_weight);
if old_weight != new_weight {
self.queue_message(Event::InventoryWeightChanged(old_weight, new_weight));
}
}
pub(crate) fn update_clothes_cache(&self, new_clothes: Vec<String>) {
self.clothes_cache.replace(new_clothes);
self.recalculate_weight();
}
}
impl MessageQueue for Inventory {
fn has_messages(&self) -> bool {
self.message_queue.borrow().len() > 0
}
fn queue_message(&self, message: Event) {
let mut q = self.message_queue.borrow_mut();
let id = q.len();
q.insert(id, message);
}
fn get_message_queue(&self) -> RefMut<'_, BTreeMap<usize, Event>> {
self.message_queue.borrow_mut()
}
}