/** * Represents the smallest part of a content. Is a wrapper for what is being compared. * Holds an array of things. Only returns positive comparisons when all of them match, unless both sides only left optional nouns. */ class ContentAtom { protected nouns : Array = []; public constructor (...nouns : Array) { this.addNoun(...nouns); } public addNoun (...nouns : Array) { this.nouns.push(...nouns); return this; } public setNouns (...nouns : Array) { this.nouns = []; this.addNoun(...nouns); return this; } public getNouns () { return [...this.nouns]; } public getAtomPriority () { let weight = 0; this.nouns.forEach(value => { weight += ContentAtom.weightNoun(value); }); return weight; } /** * Comparisons are always made assuming we're comparing the SPECIFIC side to the VAGUE side. * @param other */ public compareAgainst (other : ContentAtom) { let specificNouns = [...this.nouns]; let vagueNouns = [...other.nouns]; for (let i = specificNouns.length - 1; i >= 0; i--) { let specificNoun = specificNouns[i]; for (let k = vagueNouns.length - 1; k >= 0; k--) { let vagueNoun = vagueNouns[k]; if (ContentAtom.compareNoun(specificNoun, vagueNoun)) { specificNouns.splice(i, 1); vagueNouns.splice(k, 1); break; } } } if (specificNouns.length == 0 && vagueNouns.length == 0) { return true; } else { // If any mandatory nouns were left unfilled, return false for (let i = 0; i < specificNouns.length; i++) { if (!(specificNouns[i] instanceof ContentNoun) || ( specificNouns[i]).getType() == ContentNounType.MANDATORY) { return false; } } // If any non-adaptive nouns were left on the vague side, return false // Adaptive nouns means the content will handle it not existing for us for (let i = 0; i < vagueNouns.length; i++) { if (!(vagueNouns[i] instanceof ContentNoun) || ( vagueNouns[i]).getType() != ContentNounType.FULLY_ADAPTIVE) { return false; } } // All tests passed, must be okay return true; } } public static compareNoun (specificNoun : any, vagueNoun : any) { if (specificNoun instanceof ContentNoun) { return specificNoun.compareAgainst(vagueNoun); } else if (typeof vagueNoun == "function") { // specific must inherit vague or be vague return specificNoun == vagueNoun || specificNoun instanceof vagueNoun || (typeof specificNoun == "function" && ( specificNoun).prototype instanceof vagueNoun) } else if (vagueNoun instanceof Thing) { // specific must be vague return specificNoun == vagueNoun; } // Last strict check, probably returns false every time, unless we're dealing with numbers? return vagueNoun === specificNoun; } public static weightNoun (noun : any) : number { if (noun instanceof ContentNoun) { // This is a collection of multiple nouns! Add the weights? let weight = 0; noun.getNouns().forEach(value => { weight += ContentAtom.weightNoun(value); }); return weight; } else if (noun instanceof ContentNounSimple) { // It's just a marker return 1; } else { // Normal noun. if (typeof noun == "function") { if (noun.prototype instanceof Thing) { let specificity = 2; // Vague Thing let parentClass = Object.getPrototypeOf(noun); while (parentClass != Thing) { specificity += 0.1; parentClass = Object.getPrototypeOf(parentClass); } return specificity; } else { return 2.5; // It's not a "Thing", so it's probably a weird class, which is kind of specific } } else if (noun instanceof Thing) { return 4; // Specific thing } else { return 0.5; // The fuck is this shit, probably a number or something. } } } }