///
interface RulebookOptions {
noun? : T;
}
/**
* Without the Runner, Rulebooks were not "thread-safe", so we need the runner.
*/
class RulebookRunner {
public noun : T;
private rulesToExecute : Array = [];
public rulebook : Rulebook;
public rule : Rule;
private ruleRunner : number = -1;
public constructor (rulebook : Rulebook, noun : T) {
this.rulebook = rulebook;
this.noun = noun;
}
public addRulebooks (...rulebooks : Array>) {
rulebooks = arrayUniqueNewArray(rulebooks);
rulebooks.forEach((rulebook) => {
this.addRules(...rulebook.rules);
});
}
public addRules (...rules) {
if (this.ruleRunner < 0) {
this.rulesToExecute.push(...rules);
}
}
public skipRule (rule : Rule) {
if (this.ruleRunner >= 0) {
let index = this.rulesToExecute.indexOf(rule);
if (index > this.ruleRunner) {
this.rulesToExecute.splice(index, 1);
console.debug("[Rulebook]" + this.rulebook.name + ", skipping Rule " + rule.name + " due to request.");
} else {
console.warn("[Rulebook]" + this.rulebook.name + ": uname to skip Rule" + rule.name + " due to it being too late to stop it.");
}
}
}
public async execute () {
arrayUnique(this.rulesToExecute).sort(function (a: Rule, b: Rule) {
return a.compareTo(b);
});
for (this.ruleRunner = 0; this.ruleRunner < this.rulesToExecute.length; this.ruleRunner++) {
this.rule = this.rulesToExecute[this.ruleRunner];
let result = await this.rule.execute(this);
if (result != undefined) {
return result;
}
}
}
}
class Rulebook {
public rules : Array = [];
public name : string;
private static indentantionSpaces = 2;
public static rulebookStack : Array = [];
public static getStack () {
let stack = [];
Rulebook.rulebookStack.forEach((rl) => {
if (rl instanceof Object && rl.name != undefined) {
stack.push(rl.name);
} else if (typeof rl == "string") {
stack.push(rl);
} else if (rl instanceof Object && rl.id != undefined) {
stack.push(rl.id);
} else {
stack.push("Undefined");
}
});
return stack;
}
public static getIndentation () {
return " ".repeat(Rulebook.indentantionSpaces).repeat(Rulebook.rulebookStack.length);
}
public static increaseIndentation (rulebook : any) {
Rulebook.rulebookStack.push(rulebook);
}
public static decreaseIndentation () {
Rulebook.rulebookStack.pop();
}
public static isRunning (r : Rule | Rulebook) {
return Rulebook.rulebookStack.indexOf(r) != -1;
}
public isRunning () {
return Rulebook.isRunning(this);
}
public constructor (name : string) {
this.name = name;
}
public async execute (options : RulebookOptions, ...rulebooks) : Promise{
options = options == undefined ? {} : options;
let runner = new RulebookRunner(this, options.noun); // duplicate array
runner.addRulebooks(this, ...rulebooks);
var names = [];
for (let i = 0; i < rulebooks.length; i++) {
if (rulebooks[i] === this) continue;
names.push(rulebooks[i].name);
}
console.debug(Rulebook.getIndentation() + "[RULEBOOK] " + this.name + (names.length > 0 ? (" merged with " + names.join(", ")) : ""));
Rulebook.increaseIndentation(this);
let result = await runner.execute();
Rulebook.decreaseIndentation();
return result;
}
public createAndAddRule (r : RuleOptions) : Rule {
let rule = new Rule(r);
this.addRule(rule);
return rule;
}
public addRule (r : Rule) {
this.rules.push(r);
}
public sortRules () {
this.rules.sort(function (a : Rule, b : Rule) {
return a.compareTo(b);
});
}
}