<commit_before>import * as cp from "cross-spawn";
import * as fs from "fs-extra";
import * as glob from "glob";
import * as path from "path";

import * as bslglobals from "./features/bslGlobals";
import * as oscriptStdLib from "./features/oscriptStdLib";

import FileQueue = require("filequeue");
import loki = require("lokijs");
import Parser = require("onec-syntaxparser");
import xml2js = require("xml2js");
const fq = new FileQueue(500);

export class Global {

    public static create(adapter?: any): Global {
        if (!Global.instance) {
            Global.instance = new Global(adapter);
        }
        return Global.instance;
    }

    private static instance: Global;

    public cache: any;
    public db: any;
    public dbmodules: any;
    public dbcalls: Map<string, any[]>;
    public globalfunctions: IMethods;
    public globalvariables: IPropertyDefinitions;
    public keywords: IKeywordsForLanguage;
    public systemEnum: ISystemEnums;
    public classes: IClasses;
    public toreplaced: any;
    public methodForDescription: any = undefined;
    public syntaxFilled: string = "";
    public hoverTrue: boolean = true;
    public autocompleteLanguage: any;
    private bslCacheUpdated: boolean;
    private oscriptCacheUpdated: boolean;

    constructor(adapter?: any) {
        if (adapter) {
            this.redefineMethods(adapter);
        }
        const configuration = this.getConfiguration("language-1c-bsl");
        this.autocompleteLanguage = this.getConfigurationKey(configuration, "languageAutocomplete");
        const postfix = (this.autocompleteLanguage === "en") ? "_en" : "";
        this.toreplaced = this.getReplaceMetadata();
        this.cache = new loki("gtags.json");
        this.globalfunctions = {};
        this.globalvariables = {};
        this.systemEnum = {};
        this.classes = {};
        const globalfunctions: IBSLMethods = bslglobals.globalfunctions();
        const globalvariables: IPropertyDefinition = bslglobals.globalvariables();
        this.keywords = {};
        for (const keyword in bslglobals.keywords()[this.autocompleteLanguage]) {
            this.keywords[keyword.toLowerCase()] = keyword;
        }
        for (const key in globalfunctions) {
            const globalFunction = globalfunctions[key];
            const newName = globalFunction["name" + postfix];
            const newElement: IMethod = {
                name: newName,
                alias: (postfix === "_en") ? globalFunction.name : globalFunction.name_en,
                description: globalFunction.description,
                signature: globalFunction.signature,
                returns: globalFunction.returns,
            };
            this.globalfunctions[newName.toLowerCase()] = newElement;
        }
        const globalContextOscript: IOscriptGlobalContext = oscriptStdLib.globalContextOscript();
        for (const segmentKey in globalContextOscript) {
            const segmentMethods = globalContextOscript[segmentKey].methods;
            for (const methodKey in segmentMethods) {
                const method = segmentMethods[methodKey];
                if (this.globalfunctions[method["name" + postfix].toLowerCase()]) {
                    const globMethod = this.globalfunctions[method["name" + postfix].toLowerCase()];
                    globMethod.oscript_signature = {
                        default: {
                            СтрокаПараметров: method.signature,
                            Параметры: method.params
                        }
                    };
                    globMethod.oscript_description = method.description;
                } else {
                    const newName = method["name" + postfix];
                    const newElement: IMethod = {
                        name: newName,
                        alias: (postfix === "_en") ? method.name : method.name_en,
                        description: undefined,
                        signature: undefined,
                        returns: method.returns,
                        oscript_signature: {
                            default: {
                                СтрокаПараметров: method.signature,
                                Параметры: method.params
                            }
                        },
                        oscript_description: method.description
                    };
                    this.globalfunctions[newName.toLowerCase()] = newElement;
                }
            }
        }
        for (const element in globalvariables) {
            if (!globalvariables.hasOwnProperty(element)) {
                continue;
            }
            const newName = globalvariables[element]["name" + postfix];
            const newElement: IPropertyDefinition = {
                name: newName,
                alias: (postfix === "_en") ? globalvariables[element].name : globalvariables[element].name_en,
                description: globalvariables[element].description
            };
            this.globalvariables[newName.toLowerCase()] = newElement;
        }
        for (const element in globalContextOscript) {
            if (!globalContextOscript.hasOwnProperty(element)) {
                continue;
            }
            const segment = globalContextOscript[element];
            for (const key in segment.properties) {
                if (this.globalvariables[segment.properties[key]["name" + postfix].toLowerCase()]) {
                    const globVar = this.globalvariables[segment.properties[key]["name" + postfix].toLowerCase()];
                    globVar.oscript_description = segment.properties[key].description;
                    globVar.oscript_access = segment.properties[key].access;
                } else {
                    const newName = segment.properties[key]["name" + postfix];
                    const newElement: IPropertyDefinition = {
                        name: newName,
                        alias: (postfix === "_en")
                            ? segment.properties[key].name
                            : segment.properties[key].name_en,
                        description: undefined,
                        oscript_description: segment.properties[key].description,
                        oscript_access: segment.properties[key].access
                    };
                    this.globalvariables[newName.toLowerCase()] = newElement;
                }
            }
        }
        let systemEnum: IBSLSystemEnums = bslglobals.systemEnum();
        for (const element in systemEnum) {
            if (!systemEnum.hasOwnProperty(element)) {
                continue;
            }
            const segment = systemEnum[element];
            const newName = segment["name" + postfix];
            const newElement: ISystemEnum = {
                name: newName,
                alias: (postfix === "_en") ? segment.name : segment.name_en,
                description: segment.description,
                values: [],
            };
            const values = segment.values;
            for (const key in values) {
                if (!values.hasOwnProperty(key)) {
                    continue;
                }
                const newNameValues = values[key]["name" + postfix];
                const elementValue: ISystemEnumValue = {
                    name: newNameValues,
                    alias: (postfix === "_en") ? values[key].name : values[key].name_en,
                    description: values[key].description,
                };
                newElement.values.push(elementValue);
            }
            this.systemEnum[newName.toLowerCase()] = newElement;
        }
        systemEnum = oscriptStdLib.systemEnum();
        for (const element in systemEnum) {
            if (!systemEnum.hasOwnProperty(element)) {
                continue;
            }
            const segment = systemEnum[element];
            const newName = segment["name" + postfix];
            if (this.systemEnum[newName.toLowerCase()]) {
                const findEnum = this.systemEnum[newName.toLowerCase()];
                findEnum.oscript_description = segment.description;
            } else {
                const newElement: ISystemEnum = {
                    name: newName,
                    alias: (postfix === "_en") ? segment.name : segment.name_en,
                    description: undefined,
                    values: [],
                    oscript_description: segment.description,
                };
                const values = segment.values;
                for (const key in values) {
                    if (!values.hasOwnProperty(key)) {
                        continue;
                    }
                    const newNameValues = values[key]["name" + postfix];
                    const elementValue: ISystemEnumValue = {
                        name: newNameValues,
                        alias: (postfix === "_en") ? values[key].name : values[key].name_en,
                        description: values[key].description,
                    };
                    newElement.values.push(elementValue);
                }
                this.systemEnum[newName.toLowerCase()] = newElement;
            }
        }
        const classes: IBSLClasses = bslglobals.classes();
        for (const element in classes) {
            if (!classes.hasOwnProperty(element)) {
                continue;
            }
            const segment = classes[element];
            const newName = segment["name" + postfix];
            const newElement: IClass = {
                name: newName,
                alias: (postfix === "_en") ? segment.name : segment.name_en,
                description: segment.description,
                methods: (segment.methods) ? {} : undefined,
                properties: (segment.properties) ? {} : undefined,
                constructors: (segment.constructors) ? {} : undefined,
            };
            for (const key in segment.methods) {
                const method = segment.methods[key];
                const newNameMethod = method["name" + postfix];
                const newMethod: IMethod = {
                    name: newName,
                    alias: (postfix === "_en") ? method.name : method.name_en,
                    description: method.description,
                    // TODO: undefined?
                    signature: undefined,
                };
                newElement.methods[newNameMethod.toLowerCase()] = newMethod;
            }
            for (const key in segment.properties) {
                const property = segment.properties[key];
                const newNameProp = property["name" + postfix];
                const newProp: IPropertyDefinition = {
                    name: newName,
                    alias: (postfix === "_en") ? property.name : property.name_en,
                    description: property.description,
                };
                newElement.properties[newNameProp.toLowerCase()] = newProp;
            }
            for (const key in segment.constructors) {
                const constructor = segment.constructors[key];
                const newCntr: IConstructorDefinition = {
                    signature: constructor.signature,
                    description: constructor.description,
                };
                newElement.constructors[key.toLowerCase()] = newCntr;
            }
            this.classes[newName.toLowerCase()] = newElement;
        }
        const classesOscript: IBSLClasses = oscriptStdLib.classesOscript();
        for (const element in classesOscript) {
            if (!classesOscript.hasOwnProperty(element)) {
                continue;
            }
            const segment = classesOscript[element];
            const newName = segment["name" + postfix];
            if (this.classes[newName.toLowerCase()]) {
                const findClass = this.classes[newName.toLowerCase()];
                findClass.oscript_description = (segment.description) ? (segment.description) : findClass.description;
                for (const key in segment.methods) {
                    const nameMethod = segment.methods[key]["name" + postfix];
                    if (!findClass.methods) {
                        findClass.methods = {};
                    }
                    let findMethod = findClass.methods[nameMethod.toLowerCase()];
                    if (!findMethod) {
                        findMethod = {
                            name: nameMethod,
                            alias: (postfix === "_en")
                                ? segment.methods[key].name
                                : segment.methods[key].name_en,
                            description: undefined,
                            oscript_description: segment.methods[key].description,
                            // TODO: ?
                            signature: undefined,
                        };
                        findClass.methods[nameMethod.toLowerCase()] = findMethod;
                    } else {
                        findMethod.oscript_description = segment.methods[key].description;
                    }
                }
                for (const key in segment.properties) {
                    const nameProp = segment.properties[key]["name" + postfix];
                    if (!findClass.properties) {
                        findClass.properties = {};
                    }
                    let findProp = findClass.properties[nameProp.toLowerCase()];
                    if (!findProp) {
                        findProp = {
                            name: nameProp,
                            alias: (postfix === "_en")
                                ? segment.properties[key].name
                                : segment.properties[key].name_en,
                            description: undefined,
                            oscript_description: segment.properties[key].description,
                        };
                        findClass.properties[nameProp.toLowerCase()] = findProp;
                    } else {
                        findProp.oscript_description = segment.properties[key].description;
                    }
                }
                for (const key in segment.constructors) {
                    if (!findClass.constructors) {
                        findClass.constructors = {};
                    }
                    let findCntr = findClass.constructors[key.toLowerCase()];
                    if (!findCntr) {
                        findCntr = {
                            description: undefined,
                            oscript_description: segment.constructors[key].description,
                            // TODO ?
                            signature: undefined,
                        };
                        findClass.constructors[key.toLowerCase()] = findCntr;
                    } else {
                        findCntr.oscript_description = segment.constructors[key].description;
                    }
                }
            } else {
                const newElement: IClass = {
                    name: newName,
                    alias: (postfix === "_en") ? segment.name : segment.name_en,
                    description: undefined,
                    oscript_description: segment.description,
                    methods: (segment.methods) ? {} : undefined,
                    properties: (segment.properties) ? {} : undefined,
                    constructors: (segment.constructors) ? {} : undefined,
                };
                for (const key in segment.constructors) {
                    const newCntr: IConstructorDefinition = {
                        signature: segment.constructors[key].signature,
                        description: undefined,
                        oscript_description: segment.constructors[key].description,
                    };
                    newElement.constructors[key.toLowerCase()] = newCntr;
                }
                for (const key in segment.properties) {
                    const newNameProp = segment.properties[key]["name" + postfix];
                    const newProp: IPropertyDefinition = {
                        name: newName,
                        alias: (postfix === "_en")
                            ? segment.properties[key].name
                            : segment.properties[key].name_en,
                        description: undefined,
                        oscript_description: segment.properties[key].description,
                    };
                    newElement.properties[newNameProp.toLowerCase()] = newProp;
                }
                for (const key in segment.methods) {
                    const newNameMethod = segment.methods[key]["name" + postfix];
                    const newMethod: IMethod = {
                        name: newName,
                        alias: (postfix === "_en") ? segment.methods[key].name : segment.methods[key].name_en,
                        description: undefined,
                        oscript_description: segment.methods[key].description,
                        // TODO ?
                        signature: undefined,
                    };
                    newElement.methods[newNameMethod.toLowerCase()] = newMethod;
                }
                this.classes[newName.toLowerCase()] = newElement;
            }
        }
    }

    public getCacheLocal(
        filename: string,
        word: string,
        source,
        update: boolean = false,
        allToEnd: boolean = true,
        fromFirst: boolean = true
    ) {
        const suffix = allToEnd ? "" : "$";
        const prefix = fromFirst ? "^" : "";
        const querystring = { name: { $regex: new RegExp(prefix + word + suffix, "i") } };
        const entries = new Parser().parse(source).getMethodsTable().find(querystring);
        return entries;
    }

    public getRefsLocal(filename: string, source: string) {
        const parsesModule = new Parser().parse(source);
        const entries = parsesModule.getMethodsTable().find();
        const collection = this.cache.addCollection(filename);
        this.updateReferenceCallsOld(collection, parsesModule.context.CallsPosition, "GlobalModuleText", filename);
        for (const item of entries) {
            this.updateReferenceCallsOld(collection, item._method.CallsPosition, item, filename);
        }
        return collection;
    }

    public getReplaceMetadata() {
        return {
            AccountingRegisters: "РегистрыБухгалтерии",
            AccumulationRegisters: "РегистрыНакопления",
            BusinessProcesses: "БизнесПроцессы",
            CalculationRegisters: "РегистрыРасчета",
            ChartsOfAccounts: "ПланыСчетов",
            ChartsOfCalculationTypes: "ПланыВидовРасчета",
            ChartsOfCharacteristicTypes: "ПланыВидовХарактеристик",
            Constants: "Константы",
            Catalogs: "Справочники",
            DataProcessors: "Обработки",
            DocumentJournals: "ЖурналыДокументов",
            Documents: "Документы",
            Enums: "Перечисления",
            ExchangePlans: "ПланыОбмена",
            InformationRegisters: "РегистрыСведений",
            Reports: "Отчеты",
            SettingsStorages: "ХранилищаНастроек",
            Tasks: "Задачи"
        };
    }

    public getMetadataForPath(fullpath: string, rootPath: string): any {
        const splitsymbol = "/";
        const moduleArray: string[] = fullpath.substr(
            rootPath.length + (rootPath.slice(-1) === "\\" ? 0 : 1)
        ).split(splitsymbol);
        const filepath = fullpath;
        const hierarchy = moduleArray.length;
        let result: any;
        if (hierarchy > 3) {
            if (moduleArray[hierarchy - 1].startsWith("ObjectModule.bsl")
                && moduleArray[hierarchy - 2].startsWith("Ext")) {
                const meta: IMetaData = {
                    type: "ObjectModule",
                    fullpath: filepath,
                    parenttype: moduleArray[hierarchy - 4],
                    module: moduleArray[hierarchy - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("ManagerModule.bsl")
                && hierarchy > 3
                && moduleArray[hierarchy - 2].startsWith("Ext")) {
                const meta: IMetaData = {
                    type: "ManagerModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy  - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("RecordSetModule.bsl")
                && hierarchy > 3
                && moduleArray[hierarchy - 2].startsWith("Ext")) {
                const meta: IMetaData = {
                    type: "RecordSetModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("CommandModule.bsl") && hierarchy > 5) {
                const meta: IMetaData = {
                    type: "CommandModule",
                    parenttype: moduleArray[hierarchy - 6],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 6] + "."
                            + moduleArray[hierarchy - 5] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 6).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("CommandModule.bsl")
                && moduleArray[hierarchy - 4].startsWith("CommonCommands")) {
                const meta: IMetaData = {
                    type: "CommandModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("Module.bsl")
                && moduleArray[hierarchy - 4].startsWith("CommonModules")) {
                const meta: IMetaData = {
                    type: "CommonModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("Module.bsl")
                && moduleArray[hierarchy - 2].startsWith("Form")) {
            const meta: IMetaData = {
                type: "FormModule",
                parenttype: moduleArray[hierarchy - 7],
                fullpath: filepath,
                module: moduleArray[hierarchy - 7] + "."
                        + moduleArray[hierarchy - 6] + "." + moduleArray[hierarchy - 4],
                project: moduleArray.slice(0, hierarchy - 7).join("/")
            };
            result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("Module.bsl")
                && moduleArray[hierarchy - 2].startsWith("Ext")
                && moduleArray[hierarchy - 4].startsWith("WebServices")) {
                const meta: IMetaData = {
                    type: "CommonModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 4]
                            + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                this.dbmodules.insert(meta);
            } else if (moduleArray[hierarchy - 1].startsWith("ValueManagerModule.bsl")
                && hierarchy > 3
                && moduleArray[hierarchy - 2].startsWith("Ext")) {
                const meta: IMetaData = {
                    type: "ValueManagerModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            }  else {
               // console.error("error set metadata for " + fullpath);
            }
        }
        return result;
    }

    public getModuleForPath(fullpath: string, rootPath: string): string {
        const splitsymbol = "/";
        const moduleArray: string[] = fullpath.substr(
            rootPath.length + (rootPath.slice(-1) === "\\" ? 0 : 1)
        ).split(splitsymbol);
        let moduleStr: string = "";
        const hierarchy = moduleArray.length;
        if (hierarchy > 3) {
            if (moduleArray[hierarchy - 4].startsWith("CommonModules")) {
                moduleStr = moduleArray[hierarchy - 3];
            } else if (hierarchy > 3 && this.toreplaced[moduleArray[hierarchy - 4]] !== undefined) {
                moduleStr = this.toreplaced[moduleArray[hierarchy - 4]] + "." + moduleArray[hierarchy - 3];
            }
        }
        return moduleStr;
    }

    public getHumanMetadata(meta: any): string {
        const toReplacedPrefix = this.getReplaceMetadata();
        const toReplecedSuffix = {
            ObjectModule: "МодульОбъекта",
            ManagerModule: "МодульМенеджера",
            CommandModule: "МодульОбщий",
            FormModule: "МодульФормы",<commit_msg>Исправил на правильную локализацию<commit_after>import * as cp from "cross-spawn";
import * as fs from "fs-extra";
import * as glob from "glob";
import * as path from "path";

import * as bslglobals from "./features/bslGlobals";
import * as oscriptStdLib from "./features/oscriptStdLib";

import FileQueue = require("filequeue");
import loki = require("lokijs");
import Parser = require("onec-syntaxparser");
import xml2js = require("xml2js");
const fq = new FileQueue(500);

export class Global {

    public static create(adapter?: any): Global {
        if (!Global.instance) {
            Global.instance = new Global(adapter);
        }
        return Global.instance;
    }

    private static instance: Global;

    public cache: any;
    public db: any;
    public dbmodules: any;
    public dbcalls: Map<string, any[]>;
    public globalfunctions: IMethods;
    public globalvariables: IPropertyDefinitions;
    public keywords: IKeywordsForLanguage;
    public systemEnum: ISystemEnums;
    public classes: IClasses;
    public toreplaced: any;
    public methodForDescription: any = undefined;
    public syntaxFilled: string = "";
    public hoverTrue: boolean = true;
    public autocompleteLanguage: any;
    private bslCacheUpdated: boolean;
    private oscriptCacheUpdated: boolean;

    constructor(adapter?: any) {
        if (adapter) {
            this.redefineMethods(adapter);
        }
        const configuration = this.getConfiguration("language-1c-bsl");
        this.autocompleteLanguage = this.getConfigurationKey(configuration, "languageAutocomplete");
        const postfix = (this.autocompleteLanguage === "en") ? "_en" : "";
        this.toreplaced = this.getReplaceMetadata();
        this.cache = new loki("gtags.json");
        this.globalfunctions = {};
        this.globalvariables = {};
        this.systemEnum = {};
        this.classes = {};
        const globalfunctions: IBSLMethods = bslglobals.globalfunctions();
        const globalvariables: IPropertyDefinition = bslglobals.globalvariables();
        this.keywords = {};
        for (const keyword in bslglobals.keywords()[this.autocompleteLanguage]) {
            this.keywords[keyword.toLowerCase()] = keyword;
        }
        for (const key in globalfunctions) {
            const globalFunction = globalfunctions[key];
            const newName = globalFunction["name" + postfix];
            const newElement: IMethod = {
                name: newName,
                alias: (postfix === "_en") ? globalFunction.name : globalFunction.name_en,
                description: globalFunction.description,
                signature: globalFunction.signature,
                returns: globalFunction.returns,
            };
            this.globalfunctions[newName.toLowerCase()] = newElement;
        }
        const globalContextOscript: IOscriptGlobalContext = oscriptStdLib.globalContextOscript();
        for (const segmentKey in globalContextOscript) {
            const segmentMethods = globalContextOscript[segmentKey].methods;
            for (const methodKey in segmentMethods) {
                const method = segmentMethods[methodKey];
                if (this.globalfunctions[method["name" + postfix].toLowerCase()]) {
                    const globMethod = this.globalfunctions[method["name" + postfix].toLowerCase()];
                    globMethod.oscript_signature = {
                        default: {
                            СтрокаПараметров: method.signature,
                            Параметры: method.params
                        }
                    };
                    globMethod.oscript_description = method.description;
                } else {
                    const newName = method["name" + postfix];
                    const newElement: IMethod = {
                        name: newName,
                        alias: (postfix === "_en") ? method.name : method.name_en,
                        description: undefined,
                        signature: undefined,
                        returns: method.returns,
                        oscript_signature: {
                            default: {
                                СтрокаПараметров: method.signature,
                                Параметры: method.params
                            }
                        },
                        oscript_description: method.description
                    };
                    this.globalfunctions[newName.toLowerCase()] = newElement;
                }
            }
        }
        for (const element in globalvariables) {
            if (!globalvariables.hasOwnProperty(element)) {
                continue;
            }
            const newName = globalvariables[element]["name" + postfix];
            const newElement: IPropertyDefinition = {
                name: newName,
                alias: (postfix === "_en") ? globalvariables[element].name : globalvariables[element].name_en,
                description: globalvariables[element].description
            };
            this.globalvariables[newName.toLowerCase()] = newElement;
        }
        for (const element in globalContextOscript) {
            if (!globalContextOscript.hasOwnProperty(element)) {
                continue;
            }
            const segment = globalContextOscript[element];
            for (const key in segment.properties) {
                if (this.globalvariables[segment.properties[key]["name" + postfix].toLowerCase()]) {
                    const globVar = this.globalvariables[segment.properties[key]["name" + postfix].toLowerCase()];
                    globVar.oscript_description = segment.properties[key].description;
                    globVar.oscript_access = segment.properties[key].access;
                } else {
                    const newName = segment.properties[key]["name" + postfix];
                    const newElement: IPropertyDefinition = {
                        name: newName,
                        alias: (postfix === "_en")
                            ? segment.properties[key].name
                            : segment.properties[key].name_en,
                        description: undefined,
                        oscript_description: segment.properties[key].description,
                        oscript_access: segment.properties[key].access
                    };
                    this.globalvariables[newName.toLowerCase()] = newElement;
                }
            }
        }
        let systemEnum: IBSLSystemEnums = bslglobals.systemEnum();
        for (const element in systemEnum) {
            if (!systemEnum.hasOwnProperty(element)) {
                continue;
            }
            const segment = systemEnum[element];
            const newName = segment["name" + postfix];
            const newElement: ISystemEnum = {
                name: newName,
                alias: (postfix === "_en") ? segment.name : segment.name_en,
                description: segment.description,
                values: [],
            };
            const values = segment.values;
            for (const key in values) {
                if (!values.hasOwnProperty(key)) {
                    continue;
                }
                const newNameValues = values[key]["name" + postfix];
                const elementValue: ISystemEnumValue = {
                    name: newNameValues,
                    alias: (postfix === "_en") ? values[key].name : values[key].name_en,
                    description: values[key].description,
                };
                newElement.values.push(elementValue);
            }
            this.systemEnum[newName.toLowerCase()] = newElement;
        }
        systemEnum = oscriptStdLib.systemEnum();
        for (const element in systemEnum) {
            if (!systemEnum.hasOwnProperty(element)) {
                continue;
            }
            const segment = systemEnum[element];
            const newName = segment["name" + postfix];
            if (this.systemEnum[newName.toLowerCase()]) {
                const findEnum = this.systemEnum[newName.toLowerCase()];
                findEnum.oscript_description = segment.description;
            } else {
                const newElement: ISystemEnum = {
                    name: newName,
                    alias: (postfix === "_en") ? segment.name : segment.name_en,
                    description: undefined,
                    values: [],
                    oscript_description: segment.description,
                };
                const values = segment.values;
                for (const key in values) {
                    if (!values.hasOwnProperty(key)) {
                        continue;
                    }
                    const newNameValues = values[key]["name" + postfix];
                    const elementValue: ISystemEnumValue = {
                        name: newNameValues,
                        alias: (postfix === "_en") ? values[key].name : values[key].name_en,
                        description: values[key].description,
                    };
                    newElement.values.push(elementValue);
                }
                this.systemEnum[newName.toLowerCase()] = newElement;
            }
        }
        const classes: IBSLClasses = bslglobals.classes();
        for (const element in classes) {
            if (!classes.hasOwnProperty(element)) {
                continue;
            }
            const segment = classes[element];
            const newName = segment["name" + postfix];
            const newElement: IClass = {
                name: newName,
                alias: (postfix === "_en") ? segment.name : segment.name_en,
                description: segment.description,
                methods: (segment.methods) ? {} : undefined,
                properties: (segment.properties) ? {} : undefined,
                constructors: (segment.constructors) ? {} : undefined,
            };
            for (const key in segment.methods) {
                const method = segment.methods[key];
                const newNameMethod = method["name" + postfix];
                const newMethod: IMethod = {
                    name: newName,
                    alias: (postfix === "_en") ? method.name : method.name_en,
                    description: method.description,
                    // TODO: undefined?
                    signature: undefined,
                };
                newElement.methods[newNameMethod.toLowerCase()] = newMethod;
            }
            for (const key in segment.properties) {
                const property = segment.properties[key];
                const newNameProp = property["name" + postfix];
                const newProp: IPropertyDefinition = {
                    name: newName,
                    alias: (postfix === "_en") ? property.name : property.name_en,
                    description: property.description,
                };
                newElement.properties[newNameProp.toLowerCase()] = newProp;
            }
            for (const key in segment.constructors) {
                const constructor = segment.constructors[key];
                const newCntr: IConstructorDefinition = {
                    signature: constructor.signature,
                    description: constructor.description,
                };
                newElement.constructors[key.toLowerCase()] = newCntr;
            }
            this.classes[newName.toLowerCase()] = newElement;
        }
        const classesOscript: IBSLClasses = oscriptStdLib.classesOscript();
        for (const element in classesOscript) {
            if (!classesOscript.hasOwnProperty(element)) {
                continue;
            }
            const segment = classesOscript[element];
            const newName = segment["name" + postfix];
            if (this.classes[newName.toLowerCase()]) {
                const findClass = this.classes[newName.toLowerCase()];
                findClass.oscript_description = (segment.description) ? (segment.description) : findClass.description;
                for (const key in segment.methods) {
                    const nameMethod = segment.methods[key]["name" + postfix];
                    if (!findClass.methods) {
                        findClass.methods = {};
                    }
                    let findMethod = findClass.methods[nameMethod.toLowerCase()];
                    if (!findMethod) {
                        findMethod = {
                            name: nameMethod,
                            alias: (postfix === "_en")
                                ? segment.methods[key].name
                                : segment.methods[key].name_en,
                            description: undefined,
                            oscript_description: segment.methods[key].description,
                            // TODO: ?
                            signature: undefined,
                        };
                        findClass.methods[nameMethod.toLowerCase()] = findMethod;
                    } else {
                        findMethod.oscript_description = segment.methods[key].description;
                    }
                }
                for (const key in segment.properties) {
                    const nameProp = segment.properties[key]["name" + postfix];
                    if (!findClass.properties) {
                        findClass.properties = {};
                    }
                    let findProp = findClass.properties[nameProp.toLowerCase()];
                    if (!findProp) {
                        findProp = {
                            name: nameProp,
                            alias: (postfix === "_en")
                                ? segment.properties[key].name
                                : segment.properties[key].name_en,
                            description: undefined,
                            oscript_description: segment.properties[key].description,
                        };
                        findClass.properties[nameProp.toLowerCase()] = findProp;
                    } else {
                        findProp.oscript_description = segment.properties[key].description;
                    }
                }
                for (const key in segment.constructors) {
                    if (!findClass.constructors) {
                        findClass.constructors = {};
                    }
                    let findCntr = findClass.constructors[key.toLowerCase()];
                    if (!findCntr) {
                        findCntr = {
                            description: undefined,
                            oscript_description: segment.constructors[key].description,
                            // TODO ?
                            signature: undefined,
                        };
                        findClass.constructors[key.toLowerCase()] = findCntr;
                    } else {
                        findCntr.oscript_description = segment.constructors[key].description;
                    }
                }
            } else {
                const newElement: IClass = {
                    name: newName,
                    alias: (postfix === "_en") ? segment.name : segment.name_en,
                    description: undefined,
                    oscript_description: segment.description,
                    methods: (segment.methods) ? {} : undefined,
                    properties: (segment.properties) ? {} : undefined,
                    constructors: (segment.constructors) ? {} : undefined,
                };
                for (const key in segment.constructors) {
                    const newCntr: IConstructorDefinition = {
                        signature: segment.constructors[key].signature,
                        description: undefined,
                        oscript_description: segment.constructors[key].description,
                    };
                    newElement.constructors[key.toLowerCase()] = newCntr;
                }
                for (const key in segment.properties) {
                    const newNameProp = segment.properties[key]["name" + postfix];
                    const newProp: IPropertyDefinition = {
                        name: newName,
                        alias: (postfix === "_en")
                            ? segment.properties[key].name
                            : segment.properties[key].name_en,
                        description: undefined,
                        oscript_description: segment.properties[key].description,
                    };
                    newElement.properties[newNameProp.toLowerCase()] = newProp;
                }
                for (const key in segment.methods) {
                    const newNameMethod = segment.methods[key]["name" + postfix];
                    const newMethod: IMethod = {
                        name: newName,
                        alias: (postfix === "_en") ? segment.methods[key].name : segment.methods[key].name_en,
                        description: undefined,
                        oscript_description: segment.methods[key].description,
                        // TODO ?
                        signature: undefined,
                    };
                    newElement.methods[newNameMethod.toLowerCase()] = newMethod;
                }
                this.classes[newName.toLowerCase()] = newElement;
            }
        }
    }

    public getCacheLocal(
        filename: string,
        word: string,
        source,
        update: boolean = false,
        allToEnd: boolean = true,
        fromFirst: boolean = true
    ) {
        const suffix = allToEnd ? "" : "$";
        const prefix = fromFirst ? "^" : "";
        const querystring = { name: { $regex: new RegExp(prefix + word + suffix, "i") } };
        const entries = new Parser().parse(source).getMethodsTable().find(querystring);
        return entries;
    }

    public getRefsLocal(filename: string, source: string) {
        const parsesModule = new Parser().parse(source);
        const entries = parsesModule.getMethodsTable().find();
        const collection = this.cache.addCollection(filename);
        this.updateReferenceCallsOld(collection, parsesModule.context.CallsPosition, "GlobalModuleText", filename);
        for (const item of entries) {
            this.updateReferenceCallsOld(collection, item._method.CallsPosition, item, filename);
        }
        return collection;
    }

    public getReplaceMetadata() {
        return {
            AccountingRegisters: "РегистрыБухгалтерии",
            AccumulationRegisters: "РегистрыНакопления",
            BusinessProcesses: "БизнесПроцессы",
            CalculationRegisters: "РегистрыРасчета",
            ChartsOfAccounts: "ПланыСчетов",
            ChartsOfCalculationTypes: "ПланыВидовРасчета",
            ChartsOfCharacteristicTypes: "ПланыВидовХарактеристик",
            Constants: "Константы",
            Catalogs: "Справочники",
            DataProcessors: "Обработки",
            DocumentJournals: "ЖурналыДокументов",
            Documents: "Документы",
            Enums: "Перечисления",
            ExchangePlans: "ПланыОбмена",
            InformationRegisters: "РегистрыСведений",
            Reports: "Отчеты",
            SettingsStorages: "ХранилищаНастроек",
            Tasks: "Задачи"
        };
    }

    public getMetadataForPath(fullpath: string, rootPath: string): any {
        const splitsymbol = "/";
        const moduleArray: string[] = fullpath.substr(
            rootPath.length + (rootPath.slice(-1) === "\\" ? 0 : 1)
        ).split(splitsymbol);
        const filepath = fullpath;
        const hierarchy = moduleArray.length;
        let result: any;
        if (hierarchy > 3) {
            if (moduleArray[hierarchy - 1].startsWith("ObjectModule.bsl")
                && moduleArray[hierarchy - 2].startsWith("Ext")) {
                const meta: IMetaData = {
                    type: "ObjectModule",
                    fullpath: filepath,
                    parenttype: moduleArray[hierarchy - 4],
                    module: moduleArray[hierarchy - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("ManagerModule.bsl")
                && hierarchy > 3
                && moduleArray[hierarchy - 2].startsWith("Ext")) {
                const meta: IMetaData = {
                    type: "ManagerModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy  - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("RecordSetModule.bsl")
                && hierarchy > 3
                && moduleArray[hierarchy - 2].startsWith("Ext")) {
                const meta: IMetaData = {
                    type: "RecordSetModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("CommandModule.bsl") && hierarchy > 5) {
                const meta: IMetaData = {
                    type: "CommandModule",
                    parenttype: moduleArray[hierarchy - 6],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 6] + "."
                            + moduleArray[hierarchy - 5] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 6).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("CommandModule.bsl")
                && moduleArray[hierarchy - 4].startsWith("CommonCommands")) {
                const meta: IMetaData = {
                    type: "CommandModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("Module.bsl")
                && moduleArray[hierarchy - 4].startsWith("CommonModules")) {
                const meta: IMetaData = {
                    type: "CommonModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("Module.bsl")
                && moduleArray[hierarchy - 2].startsWith("Form")) {
            const meta: IMetaData = {
                type: "FormModule",
                parenttype: moduleArray[hierarchy - 7],
                fullpath: filepath,
                module: moduleArray[hierarchy - 7] + "."
                        + moduleArray[hierarchy - 6] + "." + moduleArray[hierarchy - 4],
                project: moduleArray.slice(0, hierarchy - 7).join("/")
            };
            result = meta;
            } else if (moduleArray[hierarchy - 1].startsWith("Module.bsl")
                && moduleArray[hierarchy - 2].startsWith("Ext")
                && moduleArray[hierarchy - 4].startsWith("WebServices")) {
                const meta: IMetaData = {
                    type: "CommonModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 4]
                            + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                this.dbmodules.insert(meta);
            } else if (moduleArray[hierarchy - 1].startsWith("ValueManagerModule.bsl")
                && hierarchy > 3
                && moduleArray[hierarchy - 2].startsWith("Ext")) {
                const meta: IMetaData = {
                    type: "ValueManagerModule",
                    parenttype: moduleArray[hierarchy - 4],
                    fullpath: filepath,
                    module: moduleArray[hierarchy - 4] + "." + moduleArray[hierarchy - 3],
                    project: moduleArray.slice(0, hierarchy - 4).join("/")
                };
                result = meta;
            }  else {
               // console.error("error set metadata for " + fullpath);
            }
        }
        return result;
    }

    public getModuleForPath(fullpath: string, rootPath: string): string {
        const splitsymbol = "/";
        const moduleArray: string[] = fullpath.substr(
            rootPath.length + (rootPath.slice(-1) === "\\" ? 0 : 1)
        ).split(splitsymbol);
        let moduleStr: string = "";
        const hierarchy = moduleArray.length;
        if (hierarchy > 3) {
            if (moduleArray[hierarchy - 4].startsWith("CommonModules")) {
                moduleStr = moduleArray[hierarchy - 3];
            } else if (hierarchy > 3 && this.toreplaced[moduleArray[hierarchy - 4]] !== undefined) {
                moduleStr = this.toreplaced[moduleArray[hierarchy - 4]] + "." + moduleArray[hierarchy - 3];
            }
        }
        return moduleStr;
    }

    public getHumanMetadata(meta: any): string {
        const toReplacedPrefix = this.getReplaceMetadata();
        const toReplecedSuffix = {
            ObjectModule: "МодульОбъекта",
            ManagerModule: "МодульМенеджера",
            CommonModule: "МодульОбщий",
            CommandModule: "МодульКоманды",
            FormModule: "МодульФормы",
{'fraction_non_alphanumeric': 0.10070105920902232, 'fraction_numerical': 0.003390992913205822, 'mean_word_length': 1.476552179656539, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4687753', 'n_tokens_mistral': 12992, 'n_tokens_neox': 12489, 'n_words': 2514}