import { StateField } from '@codemirror/state';
import { Log } from '../utils/debug-utils';
import { BreedType } from '../lang/classes/structures';
/** StatePreprocess: The first-pass state for the NetLogo Language. */
export class StatePreprocess {
    constructor() {
        /** PluralBreeds: Breeds in the model. */
        this.PluralBreeds = [];
        /** SingularBreeds: Breeds in the model. */
        this.SingularBreeds = [];
        /** SingularBreeds: Breed types in the model. */
        this.BreedTypes = [];
        /** BreedVars: Breed variables in the model. */
        this.BreedVars = new Map();
        /** Commands: Commands in the model. */
        this.Commands = new Map();
        /** Reporters: Reporters in the model. */
        this.Reporters = new Map();
        /** Editor: The editor for the state. */
        this.Editor = null;
    }
    /** ParseState: Parse the state from an editor state. */
    ParseState(State) {
        this.Commands.clear();
        this.Reporters.clear();
        this.BreedVars.clear();
        // Only leave the global statements
        let doc = State.doc.toString().toLowerCase();
        let globals = doc.replace(/(^|\n)([^;\n]+[ ]+)?to\s+[\s\S]*\s+end/gi, '');
        // Breeds
        let breeds = globals.matchAll(/(^|\n)([^;\n]+[ ]+)?(directed-link-|undirected-link-)?breed\s*\[\s*([^\s]+)\s+([^\s]+)\s*\]/g);
        this.processBreeds(breeds);
        // Breed variables
        let breedVars = globals.matchAll(/(^|\n)([^;\n]+[ ]+)?([^\s]+)-own\s*\[([^\]]+)/g);
        this.processBreedVars(breedVars);
        // Commands
        let commands = doc.matchAll(/(^|\n)([^;\n]+[ ]+)?to\s+([^\s\[;]+)(\s*\[([^\];]*)\])?/g);
        this.Commands = this.processProcedures(commands);
        // Reporters
        let reporters = doc.matchAll(/(^|\n)([^;\n]+[ ]+)?to-report\s+([^\s\[;]+)(\s*\[([^\]']*)\])?/g);
        this.Reporters = this.processProcedures(reporters);
        return this;
    }
    /** SetEditor: Set the editor for the state. */
    SetEditor(Editor) {
        this.Editor = Editor;
    }
    /** processBreedVars: Parse the code for breed variables. */
    processBreedVars(matches) {
        var _a, _b, _c;
        for (var m of matches) {
            let variables = m[4];
            variables = variables.replace(/;[^\n]*\n/g, '');
            variables = variables.replace(/\n/g, ' ');
            this.BreedVars.set(m[3], variables.split(' ').filter((v) => v != '' && v != '\n'));
        }
        this.BreedVars.set('patches', ((_a = this.BreedVars.get('patches')) !== null && _a !== void 0 ? _a : []).concat(['pxcor', 'pycor', 'pcolor', 'plabel', 'plabel-color']));
        this.BreedVars.set('turtles', ((_b = this.BreedVars.get('turtles')) !== null && _b !== void 0 ? _b : []).concat([
            'who',
            'color',
            'heading',
            'xcor',
            'ycor',
            'shape',
            'label',
            'label-color',
            'hidden?',
            'size',
            'pen-size',
            'pen-mode',
            'breed',
        ]));
        this.BreedVars.set('links', ((_c = this.BreedVars.get('links')) !== null && _c !== void 0 ? _c : []).concat([
            'end1',
            'end2',
            'color',
            'label',
            'label-color',
            'hidden?',
            'breed',
            'thickness',
            'shape',
            'tie-mode',
        ]));
    }
    /** processProcedures: Parse the code for procedure names. */
    processProcedures(procedures) {
        let matches = new Map();
        for (var match of procedures) {
            if (!match[2] || match[2].split('"').length % 2 != 0) {
                const name = match[3];
                const args = match[5];
                matches.set(name, args == null ? 0 : [...args.matchAll(/([^\s])+/g)].length);
            }
        }
        return matches;
    }
    /** processBreeds: Parse the code for breed names. */
    processBreeds(breeds) {
        this.SingularBreeds = ['patch', 'turtle', 'link'];
        this.PluralBreeds = ['patches', 'turtles', 'links'];
        this.BreedTypes = [BreedType.Patch, BreedType.Turtle, BreedType.UndirectedLink];
        for (var match of breeds) {
            var Type = BreedType.Turtle;
            if (match[3] == 'directed-link-')
                Type = BreedType.DirectedLink;
            if (match[3] == 'undirected-link-')
                Type = BreedType.UndirectedLink;
            this.BreedTypes.push(Type);
            this.PluralBreeds.push(match[4]);
            this.SingularBreeds.push(match[5]);
        }
    }
}
/** StateExtension: Extension for managing the editor state.  */
const preprocessStateExtension = StateField.define({
    create: (State) => {
        let state = new StatePreprocess();
        state.ParseState(State);
        return state;
    },
    update: (Original, Transaction) => {
        if (!Transaction.docChanged)
            return Original;
        Original.ParseState(Transaction.state);
        // Notify the editor
        if (Original.Editor)
            Original.Editor.UpdatePreprocessContext();
        Log(Original);
        return Original;
    },
});
export { preprocessStateExtension };
//# sourceMappingURL=extension-state-preprocess.js.map