/**
 * @copyright Sister Software
 * @license AGPL-3.0
 * @author Teffen Ellis, et al.
 */
import { TokenContext } from "mailwoman/core/tokenization";
/**
 * Parses a tokenized address into a structured address.
 */
export class AddressParser {
    classifiers;
    solvers;
    solutionLimit;
    #initialized = false;
    constructor({ languages, classifiers = [], solvers = [], solutionLimit = 10 } = {}) {
        this.classifiers = Array.from(classifiers, (AddressClassifier) => {
            return typeof AddressClassifier === "function" ? new AddressClassifier({ languages }) : AddressClassifier;
        });
        this.solvers = Array.from(solvers, (AddressSolver) => {
            return typeof AddressSolver === "function" ? new AddressSolver() : AddressSolver;
        });
        this.solutionLimit = solutionLimit;
    }
    async ready() {
        if (this.#initialized)
            return this;
        await Promise.all(this.classifiers.map((classifier) => classifier.ready?.()));
        this.#initialized = true;
        return this;
    }
    async parse(input, { verbose } = {}) {
        if (typeof input !== "string") {
            throw new TypeError("Failed to parse address: input must be a string.");
        }
        if (input.length === 0)
            return [];
        await this.ready();
        const startTokenizer = performance.now();
        const context = new TokenContext(input);
        const endTokenizer = performance.now();
        const startClassifier = performance.now();
        this.classify(context);
        const endClassifier = performance.now();
        const startSolve = performance.now();
        const solutions = this.findSolutions(context);
        const endSolve = performance.now();
        performance.mark("end-solve");
        if (verbose) {
            return {
                solutions,
                context,
                measures: {
                    tokenizer: performance.measure("Tokenizer", { start: startTokenizer, end: endTokenizer }),
                    classifier: performance.measure("Classifier", { start: startClassifier, end: endClassifier }),
                    solver: performance.measure("Solver", { start: startSolve, end: endSolve }),
                },
            };
        }
        return solutions.map((solution) => solution.toJSON());
    }
    #classifierMeasures = new WeakMap();
    /**
     * Run all classifiers.
     */
    classify(context) {
        for (const [i, classifier] of this.classifiers.entries()) {
            const classifierName = classifier.constructor?.name || `Unknown Classifier ${i + 1}`;
            const start = performance.now();
            classifier.classifyTokens(context);
            const classifyMeasure = performance.measure("Classify", {
                start,
                end: performance.now(),
                detail: classifierName,
            });
            this.#classifierMeasures.set(classifier, classifyMeasure);
        }
    }
    /**
     * Get the performance measure for a classifier in the most recent parse.
     */
    sampleClassifierMeasure(classifier) {
        return this.#classifierMeasures.get(classifier);
    }
    /**
     * Run all solvers.
     */
    findSolutions(context) {
        for (const solver of this.solvers) {
            context.evaluateAndRank(this.solutionLimit);
            solver.solve(context);
        }
        context.evaluateAndRank(this.solutionLimit);
        return context.solutions;
    }
}
//# sourceMappingURL=AddressParser.js.map