use crate::error::{CheckForResourcesErr, CombinationExecuteErr};
use crate::inventory::crafting::fluent::BuilderStepResultItem;
use crate::inventory::Inventory;
use crate::inventory::items::InventoryItem;
use crate::utils::event::{MessageQueue, Event};
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::fmt::Debug;
mod fluent;
impl Inventory {
pub fn register_crafting_combinations(&self, combinations: Vec<CraftingCombination>) {
let mut b = self.crafting_combinations.borrow_mut();
for combination in combinations {
b.insert(combination.unique_key.to_string(), combination);
}
}
pub fn get_suitable_combinations_for(&self, items: Vec<&String>) -> Vec<String> {
let key_to_check_against = get_match_key(items);
let mut result = Vec::new();
for (key, cmb) in self.crafting_combinations.borrow().iter() {
if cmb.match_key == key_to_check_against {
result.push(key.to_string());
}
}
return result;
}
pub fn check_for_resources(&self, combination_id: &String) -> Result<(), CheckForResourcesErr> {
match self.crafting_combinations.borrow().get(combination_id) {
Some(cmb) => {
for (name, item_data) in cmb.items.borrow().iter() {
match self.items.borrow().get(name) {
Some(item) => {
if !item.get_is_infinite() && item.get_count() < item_data.count {
return Err(CheckForResourcesErr::InsufficientResources(name.to_string()));
}
},
None => return Err(CheckForResourcesErr::ItemNotFound(name.to_string()))
}
}
Ok(())
},
None => Err(CheckForResourcesErr::CombinationNotFound)
}
}
pub fn execute_combination(&self, combination_id: &String) -> Result<(), CombinationExecuteErr> {
let cc = self.crafting_combinations.borrow();
let cmb = match cc.get(combination_id) {
Some(c) => c,
None => return Err(CombinationExecuteErr::CombinationNotFound)
};
match self.check_for_resources(combination_id) {
Err(e) => return Err(CombinationExecuteErr::ResourceError(e)),
_ => { } }
{
let mut b = self.items.borrow_mut();
for (key, item_data) in cmb.items.borrow().iter() {
match self.use_item_internal(key, item_data.count, &mut b) {
Err(e) => return Err(CombinationExecuteErr::UseItemError(e)),
_ => { } }
}
let resulted = (cmb.create)();
match b.get_mut(&cmb.result_item) {
Some(item) => {
item.set_count(item.get_count() + resulted.get_count())
},
None => {
b.insert(cmb.result_item.to_string(), resulted);
}
}
}
self.recalculate_weight();
self.queue_message(Event::CraftingCombinationExecuted(combination_id.to_string()));
Ok(())
}
}
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Default)]
pub struct ItemInCombination {
pub item_name: String,
pub count: usize
}
impl fmt::Display for ItemInCombination {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} of {}", self.count, self.item_name)
}
}
impl ItemInCombination {
pub fn new(name: &str, count: usize) -> Self {
ItemInCombination {
item_name: String::from(name),
count
}
}
pub fn copy(&self) -> ItemInCombination {
ItemInCombination {
item_name: String::from(&self.item_name),
count: self.count
}
}
}
pub struct CraftingCombination {
pub unique_key: String,
pub match_key: String,
pub result_item: String,
pub items: Rc<RefCell<HashMap<String, ItemInCombination>>>,
create: Box<dyn Fn() -> Box<dyn InventoryItem> + 'static>
}
impl Debug for CraftingCombination {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CraftingCombination")
.field("unique_key", &self.unique_key)
.field("match_key", &self.match_key)
.field("result_item", &self.result_item)
.field("items", &self.items)
.finish()
}
}
impl fmt::Display for CraftingCombination {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Combination for {} ({} items). id={}", self.result_item, self.items.borrow().len(), self.unique_key)
}
}
impl CraftingCombination {
pub fn new(result_item: String, items: Vec<ItemInCombination>,
create: Box<dyn Fn() -> Box<dyn InventoryItem> + 'static>) -> Self {
let mut mapped = HashMap::new();
let mut copy = Vec::from(items);
let key = &mut String::from(&result_item);
let mut item_names: Vec<&String> = Vec::new();
let mut b = [0; 2];
let sep = '\u{0003}'.encode_utf8(&mut b);
key.push_str(sep);
copy.sort_by(|a, b| a.item_name.cmp(&b.item_name));
for item in copy.iter() {
item_names.push(&item.item_name);
mapped.insert(String::from(&item.item_name), item.copy());
key.push_str(&item.item_name);
key.push_str(&sep);
key.push_str(&item.count.to_string());
key.push_str(&sep);
}
CraftingCombination {
unique_key: key.to_string(),
match_key: get_match_key(item_names).to_string(),
result_item,
items: Rc::new(RefCell::new(mapped)),
create
}
}
}
pub struct Builder {
result_item: RefCell<String>,
items: Rc<RefCell<Vec<ItemInCombination>>>
}
impl Builder {
pub fn start() -> Box<dyn BuilderStepResultItem> {
Box::new(Builder {
result_item: RefCell::new(String::new()),
items: Rc::new(RefCell::new(Vec::new()))
})
}
}
fn get_match_key(items: Vec<&String>) -> String {
let mut match_key: String = String::new();
let mut copy = Vec::from(items);
let mut b = [0; 2];
let sep = '\u{0003}'.encode_utf8(&mut b);
copy.sort_by(|a, b| a.cmp(b));
for item in copy.iter() {
match_key.push_str(item);
match_key.push_str(&sep);
}
return match_key.to_string();
}