import Model from "./model.js";
import Item from "./item.js";
import { sentenceCase, pluralize, uncountable } from "../string_utils.js";
function toString(bag, pluralizerFunc) {
let string = "",
cash = 0;
if (bag.entries.length) {
let items = false;
let len = bag.entries.filter((entry) => entry.item.not("cash")).length;
bag.entries.forEach((entry) => {
if (entry.item.is("cash")) {
cash += entry.item.value * 100 * entry.count;
} else {
items = true;
string += pluralizerFunc(entry.item, entry.count);
if (entry.item.title) {
string += ` (${entry.item.title})`;
}
if (len === 1) {
string += ".";
} else if (len === 2) {
string += ", and ";
} else {
string += ", ";
}
len--;
}
});
if (items && cash) {
string += " ";
}
if (cash) {
string += "$" + cash.toFixed(0) + " in cash.";
}
string = sentenceCase(string);
} else {
string += "empty.";
}
if (bag.descriptor) {
string = bag.descriptor + ": " + string;
}
return string;
}
function copy(entries) {
return (entries || []).map((entry) => ({ item: new Item(entry.item), count: entry.count }));
}
class Bag extends Model {
/**
* A bag.
*
* @param data {Object} The properties to set for this item.
*
* @extends Model
*/
constructor(data = {}) {
super(data);
this.entries = copy(data.entries);
this.type = "Bag";
}
addBag(bag) {
((bag && bag.entries) || []).forEach((entry) => this.add(entry.item, entry.count));
}
removeBag(bag) {
((bag && bag.entries) || []).forEach((entry) => this.remove(entry.item, entry.count));
}
add(item, count = 1) {
if (!item) {
throw new Error("No item passed to bag.add()");
}
if (count < 0) {
throw new Error("Cannot add a negative number of items");
}
if (count == 0) {
return 0;
}
let entry = this.visit(null, (e) => e.item.equals(item));
if (!entry) {
entry = { item: new Item(item), count: 0 };
this.entries.push(entry);
}
entry.count += count;
return entry.count;
}
remove(item, count = 1) {
if (count < 0) {
throw new Error("Cannot remove a negative number of items");
}
let entry = this.visit(null, (e) => e.item.equals(item));
if (!entry) {
throw new Error("Can’t remove item that’s not in the bag");
}
if (count > entry.count) {
throw new Error(`Can’t remove ${count} items in bag that has only ${entry.count}`);
}
if (count == 0) {
return entry.count;
}
entry.count -= count;
if (entry.count === 0) {
this.entries.splice(this.entries.indexOf(entry), 1);
}
return entry.count;
}
visit(startValue, pred, collector = (e) => e) {
return this.entries.reduce((acc, entry) => {
if (pred(entry, acc)) acc = collector(entry, acc);
return acc;
}, startValue);
}
// Find an entry by name or tag
find(name) {
return this.visit(null, (e) => e.item.name === name || e.item.tags.has(name));
}
value(item) {
return this.visit(
0,
(e) => !item || e.item.equals(item),
(e, value) => value + e.item.value * e.count
);
}
enc(item) {
return this.visit(
0,
(e) => !item || e.item.equals(item),
(e, value) => value + e.item.enc * e.count
);
}
totalValue() {
return this.visit(
0,
() => true,
(e, value) => value + e.item.value * e.count
);
}
totalEnc() {
return this.visit(
0,
() => true,
(e, value) => value + e.item.enc * e.count
);
}
count(item) {
return this.visit(
0,
(e) => !item || e.item.equals(item),
(e, value) => value + e.count
);
}
toUncountableString() {
return toString(this, uncountable);
}
toString() {
return toString(this, pluralize);
}
}
export default Bag;