/*-
 * ~~~~~~licensing~~~~~~
 * entaxy-cicd-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~~~~~~
 */

var EntaxyCICD;
(function (EntaxyCICD) {
    EntaxyCICD._module.component('entaxyCiCdTreeHeader', {
        template:
        `
          <div class="tree-nav-sidebar-header">
            <form role="form" class="search-pf has-button">
              <div class="form-group has-clear">
                <div class="search-pf-input-group">
                  <label for="input-search" class="sr-only">Search Tree:</label>
                  <input id="input-search" type="search" class="form-control" placeholder="Search tree:"
                          ng-model="$ctrl.filter">
                  <button type="button" class="clear" aria-hidden="true"
                          ng-hide="$ctrl.filter.length === 0"
                          ng-click="$ctrl.filter = ''">
                    <span class="pficon pficon-close"></span>
                  </button>
                </div>
              </div>
              <div class="form-group tree-nav-buttons">
                <span class="badge" ng-class="{positive: $ctrl.result.length > 0}"
                        ng-show="$ctrl.filter.length > 0">
                  {{$ctrl.result.length}}
                </span>
                <i class="fa fa-plus-square-o" title="Expand All" ng-click="$ctrl.expandAll()"></i>
                <i class="fa fa-minus-square-o" title="Collapse All" ng-click="$ctrl.contractAll()"></i>
              </div>
            </form>
          </div>
        `,
        controller: EntaxyCICDTreeHeaderController
    }).component('entaxyCiCdTree', {
        template:
        `
          <div class="tree-nav-sidebar-content">
            <div id="entaxycicdtree" class="treeview-pf-hover treeview-pf-select"></div>
          </div>
        `,
        controller: EntaxyCICDTreeController
    })
    .name;
    entaxyCICDTreeElementId = '#entaxycicdtree';
    EntaxyCICD.log.debug("loaded tree" + EntaxyCICD.treeModule);

    function EntaxyCICDTreeHeaderController($scope, $element) {
        'ngInject';
        EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController ");
        this.$scope = $scope;
        this.$element = $element;
        this.filter = '';
        this.result = [];
        // it's not possible to declare classes to the component host tag in AngularJS
        $element.addClass('tree-nav-sidebar-header');

        EntaxyCICDTreeHeaderController.prototype.$onInit = function () {
            EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController init");
            var _this = this;
            this.$scope.$watch(angular.bind(this, function () { return _this.filter; }), function (filter, previous) {
                if (filter !== previous) {
                    _this.search(filter);
                }
            });
        };

        EntaxyCICDTreeHeaderController.prototype.search = function (filter) {
            EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController search");
            var _this = this;
            var doSearch = function (filter) {
                var result = _this.tree().search(filter, {
                    ignoreCase: true,
                    exactMatch: false,
                    revealResults: true
                });
                _this.result.length = 0;
                (_a = _this.result).push.apply(_a, result);
                Core.$apply(_this.$scope);
                var _a;
            };
            _.debounce(doSearch, 300, { leading: false, trailing: true })(filter);
        };

        EntaxyCICDTreeHeaderController.prototype.tree = function () {
            EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController tree");
            return $(entaxyCICDTreeElementId).treeview(true);
        };

        EntaxyCICDTreeHeaderController.prototype.expandAll = function () {
            EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController expand");
            return this.tree()
                .expandNode(this.tree().getNodes(), { levels: HawtioTree.getMaxTreeLevel(this.tree()), silent: true });
        };

        EntaxyCICDTreeHeaderController.prototype.contractAll = function () {
            EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController contract");
            return this.tree()
                .collapseNode(this.tree().getNodes(), { ignoreChildren: true, silent: true });
        };
    }
    EntaxyCICDTreeHeaderController.$inject = ['$scope', '$element'];

    function EntaxyCICDTreeController($scope, $location, workspace, $element, operationsService, $q) {
        'ngInject';
        this.$scope = $scope;
        this.$location = $location;
        this.workspace = workspace;
        this.$element = $element;
        // it's not possible to declare classes to the component host tag in AngularJS
        $element.addClass('tree-nav-sidebar-content');
        EntaxyCICD.log.debug("EntaxyCICDTreeController ");
        var entaxyCICDJmxDomain = localStorage['entaxyCICDJmxDomain'] || "ru.entaxy.cicd";

        EntaxyCICDTreeController.prototype.$onInit = function () {
            EntaxyCICD.log.debug("EntaxyCICDTreeController onInit");
            var _this = this;
            this.$scope.$on('$destroy', function () { return _this.removeTree(); });
            this.$scope.$on('$routeChangeStart', function () {
                return Jmx.updateTreeSelectionFromURL(_this.$location, $(entaxyCICDTreeElementId));
            });
            this.$scope.$on('jmxTreeUpdated', function (event, opts) {
                let updateSelectionNode = opts ? opts.updateSelectionNode : false;
                return _this.populateTree(updateSelectionNode);
            });
            this.populateTree();
        };
        EntaxyCICDTreeController.prototype.updateSelectionFromURL = function () {
            Jmx.updateTreeSelectionFromURLAndAutoSelect(this.$location, $(entaxyCICDTreeElementId), null, true);
        };
        EntaxyCICDTreeController.prototype.populateTree = function (updateSelectionNode) {

            let tree = this.workspace.tree;

            if (tree) {
                let domain = tree.get(entaxyCICDJmxDomain);

                if (domain && domain.children && domain.children.length > 0) {
                    let promises = [];
                    domain.children.forEach(child => {
                        child.class = createClassName(child.title);
                        promises.push(
                            operationsService.executeOperation(child.objectName, {name: 'readAsTree'}, [])
                            .then(result => {
                                let nodes = JSON.parse(result);

                                let folderNames = child.key.split('-');
                                folderNames.shift();
                                let cicdTree = createTree(nodes, child.key, folderNames);
                                cicdTree.forEach(cicdChild => {
                                    cicdChild.parent = child;
                                });
                                child.children = cicdTree;
                            })
                        );
                    });

                    $q.all(promises).then(() => {
                        this.removeTree();
                        Jmx.enableTree(this.$scope, this.$location, this.workspace,
                            $(entaxyCICDTreeElementId), domain.children);
                        this.updateSelectionFromURL();
                        if (updateSelectionNode) {
                            workspace.updateSelectionNode(workspace.selection);
                        }
                    });
                }
            }
        };
        function createTree(children, keyPrefix, folderNames) {
            let folders = [];
            if (children && children.length > 0) {
                children.forEach(child => {
                    let folder = new Jmx.Folder(child.title);
                    let index = child.title.indexOf('[');
                    if (index > 0) {
                        folder.key = keyPrefix + '-' + child.title.slice(0, index - 1).toLowerCase();
                    } else {
                        folder.key = keyPrefix + '-' + child.title.toLowerCase();
                    }
                    let folderNamesCopy = folderNames.map(folderName => folderName);
                    folderNamesCopy.push(index > 0 ? child.title.slice(0, index - 1) : child.title);
                    folder.folderNames = folderNamesCopy;
                    addClass(folder);
                    folder.tooltip = folder.title;
                    folder.domain = entaxyCICDJmxDomain;
                    folder.children = createTree(child.children, folder.key, folderNamesCopy);
                    if (folder.children && folder.children.length > 0) {
                        folder.children.forEach(child => {
                            child.parent = folder;
                        })
                    }
                    folder.sortChildren();
                    folders.push(folder);
                });
            }
            return folders;
        }
        function addClass(folder) {
            switch (folder.folderNames.length) {
                case 3:
                    folder.class = createClassName('storages');
                    break;
                case 4:
                    folder.class = createClassName(folder.folderNames[1]);
                    break;
                case 5:
                    folder.class = createClassName('versions');
                    break;
                case 6:
                    folder.class = createClassName(folder.folderNames[1] === 'applications' ?
                        'revisions' : 'build-info');
                    break;
            }
        }
        function createClassName(folderName) {
            return 'entaxy-cicd-' + folderName + '-icon';
        }
        EntaxyCICDTreeController.prototype.removeTree = function () {
            var tree = $(entaxyCICDTreeElementId).treeview(true);
            // There is no exposed API to check whether the tree has already been initialized,
            // so let's just check if the methods are present
            if (tree.clearSearch) {
                tree.clearSearch();
                // Bootstrap tree view leaks the node elements into the data structure
                // so let's clean this up when the user leaves the view
                var cleanTreeFolder_1 = function (node) {
                    delete node['$el'];
                    if (node.nodes)
                        node.nodes.forEach(cleanTreeFolder_1);
                };
                cleanTreeFolder_1(this.workspace.tree);
                // Then call the tree clean-up method
                tree.remove();
            }
        }
    }
    EntaxyCICDTreeController.$inject = ['$scope', '$location', 'workspace', '$element', 'operationsService', '$q'];

})(EntaxyCICD || (EntaxyCICD = {}));
