import { MenuItemShowPopup, MenuItemDoReduxAction, MenuItemDoClickFunction, } from '../Utilities/MenuItem';
import ArrayExtensions from '../Utilities/Extensions/ArrayExtensions';
/**
 * Base class for all strategies and does most of the work of creating menus
 */
export class AdaptableModuleBase {
    constructor(module, friendlyName, glyph, popup, description, api) {
        this.api = api;
        this.moduleInfo = {
            ModuleName: module,
            FriendlyName: this.getFriendlyName(module, friendlyName),
            Description: description,
            HelpPage: this.api.internalApi.getModuleService().getModuleDocumentationPageByModule(module),
            Glyph: glyph,
            Popup: popup,
        };
        this.api = api;
        this.api.eventApi.on('AdaptableReady', () => {
            this.onAdaptableReady();
            this.api.stateApi.dispatchStateReadyAction(this.moduleInfo.ModuleName);
        });
        this.api.eventApi.on('AdaptableStateReloaded', (adaptableStateReloadedInfo) => {
            this.onAdaptableStateReloaded(adaptableStateReloadedInfo);
        });
    }
    getViewAccessLevel() {
        // override where necessary (ex. only 'Full' accessLevel should be displayed)
        return 'ReadOnly';
    }
    getEditAccessLevel() {
        // override where necessary
        return 'Full';
    }
    getAgGridModuleDependencies() {
        // override where necessary
        return [];
    }
    isModuleEnabled() {
        // by default all modules are enabled; some modules may override this to check specific flags, configs, etc.
        return true;
    }
    isModuleAvailable() {
        return this.agGridModuleDepsInfo?.hasRequiredAgGridModuleDependencies;
    }
    isModuleVisible() {
        return (this.isModuleEnabled() &&
            this.isModuleAvailable() &&
            this.hasRequiredAccessLevel(this.getViewAccessLevel()));
    }
    isModuleEditable() {
        return (this.isModuleEnabled() &&
            this.isModuleAvailable() &&
            this.hasRequiredAccessLevel(this.getEditAccessLevel()));
    }
    setAgGridDepsInfo() {
        const agGridModulesAdapter = this.api.internalApi.getAgGridModulesAdapter();
        const missingAgGridModuleDependencies = this.getAgGridModuleDependencies().filter((agGridModule) => !agGridModulesAdapter.isAgGridModuleRegistered(agGridModule));
        if (missingAgGridModuleDependencies.length) {
            this.agGridModuleDepsInfo = {
                hasRequiredAgGridModuleDependencies: false,
                missingAgGridModuleDependencies,
            };
        }
        else {
            this.agGridModuleDepsInfo = {
                hasRequiredAgGridModuleDependencies: true,
            };
        }
    }
    logMissingAgGridDepsInfos() {
        if (this.isModuleEnabled() &&
            this.hasRequiredAccessLevel(this.getViewAccessLevel()) &&
            !this.isModuleAvailable()) {
            this.api.logWarn(`Module '${this.moduleInfo.ModuleName}' is not available -  missing required AG Grid modules: ${this.agGridModuleDepsInfo.missingAgGridModuleDependencies.join(', ')}`);
        }
    }
    /**
     * Used inside the unified UI to show the share button
     */
    isModuleObjectsShareable() {
        return true;
    }
    getModuleAdaptableObjects() {
        // override where necessary in base classes
        return [];
    }
    getExplicitlyReferencedColumnIds(adaptableObject) {
        // override where necessary in base classes
        return [];
    }
    getReferencedNamedQueryNames(adaptableObject) {
        // override where necessary in base classes
        return [];
    }
    hasNamedQueryReferences() {
        // override where necessary in base classes
        // this will skip the unnecessary evaluation of modules which do not have Named Query references
        return true;
    }
    onAdaptableReady() {
        // override where necessary in base classes
    }
    onAdaptableStateReloaded(adaptableStateReloadedInfo) {
        // override where necessary in base classes
    }
    setModuleEntitlement() {
        this.AccessLevel = this.api.entitlementApi.getEntitlementAccessLevelForModule(this.moduleInfo.ModuleName);
    }
    createModuleMenuItem(source) {
        if (this.isModuleVisible() && this.moduleInfo.Popup) {
            const moduleParams = {
                source: source,
                maxWidth: this.getPopupMaxWidth(),
            };
            return this.createMainMenuItemShowPopup({
                Name: '_navbar',
                Label: this.moduleInfo.FriendlyName,
                ComponentName: this.moduleInfo.Popup,
                Icon: this.moduleInfo.Glyph,
                PopupParams: moduleParams,
            });
        }
    }
    createColumnMenuItems(column) {
        // base class implementation which is empty
        return undefined;
    }
    createContextMenuItems(menuContext) {
        // base class implementation which is empty
        return undefined;
    }
    // creates the module menu items in the navbar
    createMainMenuItemShowPopup({ Name, Label, ComponentName, Icon, PopupParams, }) {
        return new MenuItemShowPopup(Name, Label, this.moduleInfo.ModuleName, ComponentName, Icon, true, PopupParams);
    }
    // creates a menu item for the column menu to perform a function
    createMenuItemClickFunction(Name, Label, Icon, ClickFunction) {
        return new MenuItemDoClickFunction(Name, Label, this.moduleInfo.ModuleName, ClickFunction, Icon, true);
    }
    // creates a menu item for the column menu to enact a Redux action
    createMenuItemReduxAction(Name, Label, Icon, Action) {
        return new MenuItemDoReduxAction(Name, Label, this.moduleInfo.ModuleName, Action, Icon, true);
    }
    // popups called by the column menu - invisible if module is hidden or readonly
    createMenuItemShowPopup(Name, Label, ComponentName, Icon, PopupParams) {
        return new MenuItemShowPopup(Name, Label, this.moduleInfo.ModuleName, ComponentName, Icon, true, PopupParams);
    }
    getTeamSharingAction() {
        return undefined;
    }
    getModuleNamedQueryReferences() {
        if (!this.hasNamedQueryReferences()) {
            return [];
        }
        const references = [];
        this.getModuleAdaptableObjects().forEach((adaptableObject) => references.push(...this.getReferencedNamedQueryNames(adaptableObject)));
        return references;
    }
    getModuleCalculatedColumnReferences() {
        const references = [];
        const allCalculatedColumns = this.api.calculatedColumnApi.getCalculatedColumns();
        this.getModuleAdaptableObjects().forEach((adaptableObject) => {
            const referencedColumnIds = this.getExplicitlyReferencedColumnIds(adaptableObject);
            referencedColumnIds.forEach((referencedColumnId) => {
                // check for calculated column
                const referencedCalculatedColumn = allCalculatedColumns.find((calculatedColumn) => calculatedColumn.ColumnId === referencedColumnId);
                if (referencedCalculatedColumn) {
                    references.push(referencedCalculatedColumn);
                }
            });
        });
        return references;
    }
    getModuleFreeTextColumnReferences() {
        const references = [];
        const allFreeTextColumns = this.api.freeTextColumnApi.getFreeTextColumns();
        this.getModuleAdaptableObjects().forEach((adaptableObject) => {
            const referencedColumnIds = this.getExplicitlyReferencedColumnIds(adaptableObject);
            referencedColumnIds.forEach((referencedColumnId) => {
                // check for calculated column
                const referencedFreeTextColumn = allFreeTextColumns.find((freeTextColumn) => freeTextColumn.ColumnId === referencedColumnId);
                if (referencedFreeTextColumn) {
                    references.push(referencedFreeTextColumn);
                }
            });
        });
        return references;
    }
    getTeamSharingReferences(adaptableObject) {
        const result = [];
        // extract special column references
        const referencedColumnIds = this.getExplicitlyReferencedColumnIds(adaptableObject);
        if (referencedColumnIds.length) {
            const allCalculatedColumns = this.api.calculatedColumnApi.getCalculatedColumns();
            const allFreeTextColumns = this.api.freeTextColumnApi.getFreeTextColumns();
            referencedColumnIds.forEach((referencedColumnId) => {
                // check for calculated column
                const referencedCalculatedColumn = allCalculatedColumns.find((calculatedColumn) => calculatedColumn.ColumnId === referencedColumnId);
                if (referencedCalculatedColumn) {
                    result.push({
                        Module: 'CalculatedColumn',
                        Reference: referencedCalculatedColumn,
                    });
                }
                // check for freeText column
                const referencedFreeTextColumn = !referencedCalculatedColumn &&
                    allFreeTextColumns.find((freeTextColumn) => freeTextColumn.ColumnId === referencedColumnId);
                if (referencedFreeTextColumn) {
                    result.push({
                        Module: 'FreeTextColumn',
                        Reference: referencedFreeTextColumn,
                    });
                }
            });
        }
        // extract Named Query references
        const referencedNamedQueries = this.getReferencedNamedQueryNames(adaptableObject).map((namedQueryName) => this.api.namedQueryApi.getNamedQueryByName(namedQueryName));
        referencedNamedQueries.forEach((referencedNamedQuery) => {
            result.push({
                Module: 'NamedQuery',
                Reference: referencedNamedQuery,
            });
        });
        return result;
    }
    getPopupMaxWidth() {
        // override where necessary in base classes
        // it allows every module to define a specific popup width
        return undefined;
    }
    /**
     * TRUE for objects of type {@link LayoutExtensionObject}
     */
    containsLayoutExtensions() {
        return false;
    }
    showLayoutNonExtendedObjects() {
        return this.api.layoutApi.internalApi.showLayoutNonExtendedObjects();
    }
    getFriendlyName(module, friendlyName) {
        let returnValue = friendlyName;
        let userInterfaceOptions = this.api.optionsApi.getUserInterfaceOptions();
        if (userInterfaceOptions &&
            ArrayExtensions.IsNotNullOrEmpty(userInterfaceOptions.alternativeModuleNames)) {
            userInterfaceOptions.alternativeModuleNames.forEach((af) => {
                if (module == af.adaptableModule) {
                    returnValue = af.newName;
                }
            });
        }
        return returnValue;
    }
    hasRequiredAccessLevel(requiredAccessLevel) {
        if (this.AccessLevel === 'Hidden') {
            return false;
        }
        if (requiredAccessLevel === 'ReadOnly') {
            return this.AccessLevel === 'ReadOnly' || this.AccessLevel === 'Full';
        }
        if (requiredAccessLevel === 'Full') {
            return this.AccessLevel === 'Full';
        }
        // else requiredAccessLevel === 'Hidden' -- does NOT make sense unless a Module is programmatically disabled
        return false;
    }
}
