/*-
 * ~~~~~~licensing~~~~~~
 * entaxy-management-plugin
 * ==========
 * Copyright (C) 2020 - 2025 EmDev LLC
 * ==========
 * You may not use this file except in accordance with the License Terms of the Copyright
 * Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
 * rights to the Software and any copies are the property of the Copyright Holder. Unless
 * it is explicitly allowed the Copyright Holder, the User is prohibited from using the
 * Software for commercial purposes to provide services to third parties.
 * 
 * The Copyright Holder hereby declares that the Software is provided on an "AS IS".
 * Under no circumstances does the Copyright Holder guarantee or promise that the
 * Software provided by him will be suitable or not suitable for the specific purposes
 * of the User, that the Software will meet all commercial and personal subjective
 * expectations of the User, that the Software will work properly, without technical
 * errors, quickly and uninterruptedly.
 * 
 * Under no circumstances shall the Copyright Holder or its Affiliates is not liable
 * to the User for any direct or indirect losses of the User, his expenses or actual
 * damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
 * or damage to data, property, etc.
 * ~~~~~~/licensing~~~~~~
 */
/**
 * The main entry point for the Simple module
 */
var Entaxy = (function (Entaxy) {

    /**
    * The name of this plugin
    */
    Entaxy.pluginName = 'entaxy-plugin';

    /**
    * This plugin's logger instance
    */
    Entaxy.log = Logger.get('entaxy-plugin');

    /**
    * The top level path of this plugin on the server
    */
    Entaxy.contextPath = "/entaxy-plugin/";

    Entaxy.log.info("loading entaxy plugin")
    Entaxy._module = angular.module(Entaxy.pluginName, [
        'angularResizable',
        'jsonFormatter',
        'ui.sortable',
        'cfp.hotkeys'
    ])
    .component('entaxy', {
        template:
           `<div class="tree-nav-layout">
                <div class="sidebar-pf sidebar-pf-left" resizable r-directions="['right']">
                  <entaxy-tree-header></entaxy-tree-header>
                  <entaxy-tree></entaxy-tree>
                </div>
                <div class="tree-nav-main">
                  <entaxy-header></entaxy-header>
                  <entaxy-extended-data></entaxy-extended-data>
                  <entaxy-navigation></entaxy-navigation>
                  <div class="contents" ng-view></div>
                </div>
           </div>
          `
          })
    .run(configurePlugin);

    function configurePlugin(mainNavService, workspace, helpRegistry, preferencesRegistry, localStorage, preLogoutTasks,
                             documentBase, $templateCache, $rootScope, jolokia, entaxyAttributesCacheService,
                             entaxyPrivateObjectsCacheService, operationsService, $q) {
        var entaxyJmxDomain = localStorage['entaxyJmxDomain'] || "ru.entaxy.esb";
        mainNavService.addItem({
            title: 'Entaxy ION',
            basePath: '/entaxy-management',
            template: '<entaxy></entaxy>',
            isValid: function () { return workspace.treeContainsDomainAndProperties(entaxyJmxDomain); },
            rank: 3
        });

        workspace.addNamedTreePostProcessor('addPrivateObjectsToTree', (tree) => {
            if (tree) {
                let domain = tree.get(entaxyJmxDomain);

                if (domain) {
                    let localNode = domain.children ?
                        domain.children.find(node =>
                            node.objectName && Core.parseMBean(node.objectName).attributes.localNode) : undefined;

                    if (localNode) {
                        let runtimeFolder = localNode.findDescendant(child => child.title === 'runtime');

                        addPrivateObjectsRecursive(runtimeFolder);
                    }
                }
            }
        });

        function addPrivateObjectsRecursive(folder) {
            if (folder) {
                if (folder.objectName && entaxyPrivateObjectsCacheService.hasAddedChildren(folder.objectName)) {
                    entaxyPrivateObjectsCacheService.getAddedObjectsInfo(folder.objectName).forEach(objectInfo => {
                        addPrivateObject(folder, objectInfo);
                    });
                    // folder.sortChildren();
                }
                if (folder.children && folder.children.length > 0) {
                    folder.children.forEach(child => addPrivateObjectsRecursive(child));
                }
            }
        }

        function addPrivateObject(folder, objectInfo) {
            let childFolder = new Jmx.Folder(objectInfo.ui.id);
            childFolder.key = folder.key + '-' + childFolder.title;
            if (objectInfo.properties.displayName) {
                childFolder.title = objectInfo.properties.displayName;
            }
            childFolder.domain = entaxyJmxDomain;
            childFolder.parent = folder;
            childFolder.class = runtimeTypeToClassName[objectInfo.type];
            if (objectInfo.type === Entaxy.RUNTIME_TYPE.ROUTE) {
                childFolder.class += ' ' + objectInfo.ui.routeType.toLowerCase();
            }
            childFolder.class += objectInfo.toRemoval ? ' to-removal' : ' changed';
            if (folder.children) {
                folder.children.push(childFolder);
            } else {
                folder.children = [childFolder];
            }
        }

        workspace.addNamedTreePostProcessor('addIconClass', (tree) => {
            if (tree) {
                let domain = tree.get(entaxyJmxDomain);

                if (domain) {
                    angular.forEach(domain.children, (node) => {
                        node.class = 'entaxy-node-icon';

                        angular.forEach(['platform', 'runtime'], (folderName) => {
                            let folder = domain.findDescendant(child => child.title === folderName);
                            if (folder) {
                                folder.class = createClassName(folderName);
                            }
                        });

                        angular.forEach(
                            ['factories', 'search', 'route-component-libraries', 'data-management',
                                'resource', 'connectors', 'security', 'configs', 'objects'],
                            (folderName) => {
                                addClassRecursive(
                                    domain.findDescendant(child => child.title === folderName),
                                    createClassName(folderName)
                                );
                            }
                        );

                        angular.forEach(
                            ['connections', 'profiles', 'services', 'repositories', 'route-libraries'],
                            (folderName) => {
                                addClassToParentAndItsChildrenUsingRuntimeType(domain
                                    .findDescendant(child => child.title === folderName));
                            }
                        )
                    });
                }
            }
        });

        function addClassRecursive(folder, className) {
            if (folder) {
                folder.class = className;
                angular.forEach(folder.children, (child) => {
                    if (child.children && child.children.length > 0) {
                        addClassRecursive(child, className);
                    } else {
                        child.class = className;
                    }
                });
            }
        }

        function addClassToParentAndItsChildrenUsingRuntimeType(folder) {
            if (folder) {
                if (folder.objectName) {
                    let attributes = entaxyAttributesCacheService.getAttributes(folder.objectName);
                    if (attributes.RuntimeType) {
                        folder.class = runtimeTypeToClassName[attributes.RuntimeType];

                        if (attributes.RuntimeType === Entaxy.RUNTIME_TYPE.CONNECTOR && attributes.Direction) {
                            folder.class += ' ' + attributes.Direction;
                        }

                        if (attributes.RuntimeType === Entaxy.RUNTIME_TYPE.ROUTE && attributes.RouteType) {
                            folder.class += ' ' + attributes.RouteType.toLowerCase();
                        }
                    } else {
                        folder.class = createClassName(folder.title);
                    }

                    if (entaxyPrivateObjectsCacheService.isChanged(folder.objectName)) {
                        let privateObject = entaxyPrivateObjectsCacheService.getChangedObjectInfo(attributes.ObjectFullId);
                        if (privateObject && privateObject.toRemoval) {
                            folder.class += ' to-removal';
                        } else {
                            folder.class += ' changed';
                        }
                    }
                } else {
                    if (!folder.class.startsWith('entaxy')) {
                        folder.class = folder.title === 'bound' ? 'entaxy-routes-icon' : createClassName(folder.title);
                    }
                }

                folder.children.forEach((child) => {
                    addClassToParentAndItsChildrenUsingRuntimeType(child);
                });
            }
        }

        const runtimeTypeToClassName = {
            [Entaxy.RUNTIME_TYPE.PROFILE]: 'entaxy-profiles-icon',
            [Entaxy.RUNTIME_TYPE.CONNECTOR]: 'entaxy-connectors-icon',
            [Entaxy.RUNTIME_TYPE.ROUTE_CONTAINER]: 'entaxy-routes-icon',
            [Entaxy.RUNTIME_TYPE.DEFAULT_ROUTE]: 'entaxy-routes-icon',
            [Entaxy.RUNTIME_TYPE.ROUTE]: 'entaxy-routes-icon',
            [Entaxy.RUNTIME_TYPE.CONNECTION]: 'entaxy-connections-icon',
            [Entaxy.RUNTIME_TYPE.REPOSITORY]: 'entaxy-repositories-icon',
            [Entaxy.RUNTIME_TYPE.SERVICE]: 'entaxy-services-icon',
            [Entaxy.RUNTIME_TYPE.CONFIG]: 'entaxy-configs-icon',
            [Entaxy.RUNTIME_TYPE.ROUTE_LIBRARY]: 'entaxy-route-libraries-icon'
        }

        function createClassName(folderName) {
            return 'entaxy-' + folderName + '-icon';
        }

        function mBeansTreeLocalization(children) {
        	if (children && children.length >0) {
        		for (var i=0; i<children.length; i++) {
        			let c = children[i];
        			if (L10N.hasOwnProperty(c.title)) {
        				c.title = L10N[c.title];
        			}
        			if (c.children && c.children.length > 0) {
        				mBeansTreeLocalization(c.children);
        			}
        		}
        	}
        }

//      global event for entaxy extras
        $rootScope.$emit('entaxyWorkspacePreparing', workspace);

        workspace.addNamedTreePostProcessor('localize', (tree) => {
        	if (tree) {
        		let domain = tree.get(entaxyJmxDomain);
        		if (domain) {
        		    console.log('domain ');
        			console.log(domain.children);
        			mBeansTreeLocalization(domain.children);
        		}
        	}
        });

        workspace.addNamedTreePostProcessor('useDisplayName', (tree) => {
        	if (tree) {
        		let domain = tree.get(entaxyJmxDomain);
        		if (domain) {
        			useDisplayName(domain.children);
        		}
        	}
        });

        function useDisplayName(children) {
            children.forEach(child => {
                if (child.objectName) {
                    let attributes = entaxyAttributesCacheService.getAttributes(child.objectName);
                    if (attributes.RuntimeType && attributes.DisplayName &&
                            attributes.RuntimeType !== Entaxy.RUNTIME_TYPE.ROUTE_CONTAINER) {
                        child.title = attributes.DisplayName;
                    }
                }
                useDisplayName(child.children);
            });
        }

        workspace.addNamedTreePostProcessor('addTooltips', (tree) => {
            if (tree) {
                setTooltips(tree.children);
            }
        });

        function setTooltips(children) {
            children.forEach(child => {
                child.tooltip = child.text;
                if (child.children) {
                    setTooltips(child.children);
                }
            });
        }

        let osgiCompendiumDomain = 'osgi.compendium';
        jolokia.list(osgiCompendiumDomain,
            Core.onSuccess((response) => {
                let mbeanName = osgiCompendiumDomain + ':' + Object.keys(response)[0];
                jolokia.execute(mbeanName, 'getProperties', 'ru.entaxy.esb.ui.hawtio', {
                    success: (response) => {
                        if (response === null || response === 'null') {
                            let errorMessage = 'Configuration file ru.entaxy.esb.ui.hawtio is empty or not found';
                            Entaxy.log.error(errorMessage);
                            Core.notification(Entaxy.NOTIFICATION_TYPE.DANGER, errorMessage);
                            Entaxy.setDefaultConfiguration();
                        } else {
                            let configuration = response;
                            delete configuration['felix.fileinstall.filename'];
                            delete configuration['service.pid'];
                            Object.keys(configuration).forEach(key => {
                                configuration[key] = JSON.parse(configuration[key].Value);
                            })
                            Entaxy.setConfiguration(configuration);
                        }
                    },
                        error: (response) =>
                            Entaxy.log.error(response.stacktrace ? response.stacktrace : response.error)
                    });
                },
                {
                    error: (response) => Entaxy.log.info('ERROR ' + JSON.stringify(response))
                })
        );

        Osgi.runWhenTreeReady(() => getTagDescriptors(), workspace, $q);
        function getTagDescriptors() {
            let domain = workspace.tree.get(entaxyJmxDomain);
            let routeComponentLibrariesMbean = domain.findDescendant(child =>
                child.objectName && child.objectName.endsWith('util=route-component-libraries'));
            let routeComponentLibrariesMbeanName = routeComponentLibrariesMbean.objectName;

            operationsService
            .executeOperation(routeComponentLibrariesMbeanName, {name: 'readAllTagDescriptors'}, [])
            .then(result => {
                let tagList = JSON.parse(result);
                Entaxy.setEntaxyLibrariesTagList(tagList);
                let topChildrenTags = [];
                tagList.forEach(tags => {
                    Object.keys(tags).forEach(tag => {
                        if (tags[tag].topChild && !topChildrenTags.includes(tag)) {
                            topChildrenTags.push(tag);
                        }
                    });
                });
                Entaxy.enrichEntaxyTags(topChildrenTags);
                Entaxy.enrichCamelTags(topChildrenTags);
            })
            .catch(error => Entaxy.log.error(error));
        }

        // clean up local storage upon logout
/*        preLogoutTasks.addTask('CleanupArtemisCredentials', function () {
            Artemis.log.debug("Clean up Artemis credentials in local storage");
            localStorage.removeItem('artemisUserName');
            localStorage.removeItem('artemisPassword');
        }); */
    }
    configurePlugin.$inject = ['mainNavService', 'workspace', 'helpRegistry', 'preferencesRegistry', 'localStorage',
        'preLogoutTasks', 'documentBase', '$templateCache', '$rootScope', 'jolokia', 'entaxyAttributesCacheService',
        'entaxyPrivateObjectsCacheService', 'operationsService', '$q'];

    return Entaxy;

})(Entaxy || {});

// tell the Hawtio plugin loader about our plugin so it can be
// bootstrapped with the rest of AngularJS
hawtioPluginLoader.addModule(Entaxy.pluginName);

const L10N = {
	platform: 'Платформа',
	adapters: 'Адаптеры',
	factories: 'Фабрики',
	runtime: 'Состояние',
	connections: 'Коннекции',
	profiles: 'Профили',
    in: 'Входные',
    out: 'Выходные',
	connectors: 'Коннекторы',
	routes: 'Маршруты',
    bound: 'Связанные',
	resource: 'Ресурсы',
	services: 'Сервисы и Клиенты',
    security: 'Безопасность',
    repositories: 'Репозитории',
    objects: 'Объекты',
    configs: 'Конфигурации',
    search: 'Поиск',
    ['route-libraries']: 'Библиотеки маршрутов',
    ['route-component-libraries']: 'Библиотеки компонентов маршрутов',
    ['data-management']: 'Управление данными',
    ['data-mappers']: 'Маппинг данных'
};
