/*-
 * ~~~~~~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~~~~~~
 */
var Entaxy;
(function (Entaxy) {
    Entaxy._module
    .component('entaxyResources', {
        template:
        `
          <div class="resources-header-container">
            <h2>
              Resources
            </h2>
            <p class="text-muted">{{$ctrl.location}}</p>
            <entaxy-copy-to-clipboard-button title="Copy location to clipboard"
                    text-to-copy="$ctrl.location"></entaxy-copy-to-clipboard-button>
            <button type="button" data-toggle="tooltip" title="Change location view"
                    ng-click="$ctrl.changeLocationView()">
              <span class="fa pficon-optimize"></span>
            </button>
            <div class="divider"></div>
            <button type="button" data-toggle="tooltip" title="Upload resource" ng-click="$ctrl.triggerUpload()">
              <span class="fa fa-upload"></span>
              <input type="file" id="file-input" name="file-input" set-file-model
                    ng-model="$ctrl.file" ng-change="$ctrl.upload($ctrl.file)">
            </button>
            <button type="button" data-toggle="tooltip" title="Change to list" ng-click="$ctrl.changeView('list')"
                    ng-if="$ctrl.view === 'tiles'">
              <span class="fa fa-list"></span>
            </button>
            <button type="button" data-toggle="tooltip" title="Change to tiles" ng-click="$ctrl.changeView('tiles')"
                    ng-if="$ctrl.view === 'list'">
              <span class="fa fa-th"></span>
            </button>
          </div>

          <entaxy-crumbs root-crumb="$ctrl.protocol" crumbs="$ctrl.crumbs"></entaxy-crumbs>

          <div class="resources-file-drop-zone" entaxy-file-drop ng-model="$ctrl.file"
                process-fn="$ctrl.upload($ctrl.file)">
            <div class="file-panel-container" context-menu context-menu-options="$ctrl.contextMenuOptions">
              <entaxy-file-panel items="$ctrl.items" selected-items="$ctrl.selectedItems" view="$ctrl.view"
                    change-selection-fn="$ctrl.changeSelection" open-fn="$ctrl.open"
                    resource-context-menu-options="$ctrl.resourceContextMenuOptions"
                    adm-resource-context-menu-options="$ctrl.admResourceContextMenuOptions"
                    folder-context-menu-options="$ctrl.folderContextMenuOptions"></entaxy-file-panel>
            </div>
            <div class="meta-info" resizable r-directions="['left']"
                    ng-if="$ctrl.selectedItems && $ctrl.selectedItems.length == 1 && $ctrl.selectedItems[0].metadata">
              <uib-tabset active="$ctrl.activeTab" class="meta-tabs">
                <uib-tab ng-repeat="(section, info) in $ctrl.selectedItems[0].metadata track by $index"
                        heading="{{section}}">
                  <div class="json-formatter">
                    <json-formatter json="info" open="1"></json-formatter>
                  </div>
                </uib-tab>
              </uib-tabset>
            </div>
          </div>
        `,
        controller: entaxyResourcesController
    })
    .name;

    function entaxyResourcesController(workspace, $scope, jolokia, entaxyService, entaxyResourcesService, $timeout,
                                       $uibModal, $cookies, entaxyHotkeysService, $q, $window, $location, $route) {
        'ngInject';

        let ctrl = this;
        let selectedMbeanName = workspace.getSelectedMBeanName();
        let clientFolders = [];
        const ENTAXY_RESOURCE_PREFIX = 'entaxy-resource://';
        ctrl.isFullLocationView = true;

        ctrl.contextMenuOptions = [
            {
                name: 'Create folder',
                actionFn: createFolder
            },
            {
                name: 'Create resource',
                actionFn: createResource
            },
            {
                name: 'Upload',
                actionFn: uploadResource
            },
            {
                name: 'Paste',
                actionFn: pasteResources
            }
        ];

        let commonContextMenuOptions = [
            {
                name: 'Copy',
                actionFn: copyResources
            },
            {
                name: 'Cut',
                actionFn: cutResources
            },
            {
                name: 'Remove',
                actionFn: removeResources
            },
            {
                divider: true
            }
        ];

        ctrl.resourceContextMenuOptions = [
            {
                name: 'Download',
                actionFn: downloadResources
            }
        ].concat(commonContextMenuOptions).concat(ctrl.contextMenuOptions);

        ctrl.admResourceContextMenuOptions = [
            {
                name: 'Open in new tab',
                actionFn: openTransformationEditorInTab
            }
        ].concat(ctrl.resourceContextMenuOptions);

        ctrl.folderContextMenuOptions = [
            {
                name: 'Paste to folder',
                actionFn: pasteResourceToFolder
            }
        ].concat(commonContextMenuOptions).concat(ctrl.contextMenuOptions);

        ctrl.$onInit = function () {
            entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());

            ctrl.view = 'list';
            ctrl.protocol = jolokia.getAttribute(selectedMbeanName, 'Protocol');
            let path = $cookies.getObject(ctrl.protocol);
            ctrl.crumbs = path ? path.split('/') : [];
        }

        let locationNid = $location.search() ? $location.search().nid : undefined;
        $scope.$on('jmxTreeClicked', function () {
            const currentLocationNid = $location.search() ? $location.search().nid : undefined;
            if (locationNid !== currentLocationNid) {
                locationNid = currentLocationNid;
                $route.reload();
            }
        });

        $scope.$watchCollection('$ctrl.crumbs', function() {
            ctrl.selectedItems = [];
            ctrl.location = ctrl.isFullLocationView ? getFullLocation() : getLocation();

            $cookies.putObject(ctrl.protocol, getPath());

            updateItems();
        })

        ctrl.changeView = function (view) {
            ctrl.view = view;
        }

        ctrl.changeLocationView = function () {
            ctrl.location = ctrl.isFullLocationView ? getLocation() : getFullLocation();
            ctrl.isFullLocationView = !ctrl.isFullLocationView;
        }

        ctrl.changeSelection = function (item, isMultiple) {
            if (!isMultiple) {
                ctrl.selectedItems = [ item ];
            } else {
                if (ctrl.selectedItems && ctrl.selectedItems.length > 0) {
                    if (ctrl.selectedItems.includes(item)) {
                        ctrl.selectedItems = ctrl.selectedItems.filter(it => it.name !== item.name);
                    } else {
                        ctrl.selectedItems.push(item);
                    }
                } else {
                    ctrl.selectedItems = [ item ];
                }
            }

            ctrl.location = ctrl.isFullLocationView ? getFullLocation() : getLocation();
            $timeout(function () {
                ctrl.activeTab = 0;
            });
        }

        function createResource () {
            entaxyResourcesService.openResourceNameInputModal({ isFolder: false },
                ctrl.items.map((item) => item.name), false, false)
            .then((name) => {
                saveResource(
                    getPath() + '/' + name,
                    '',
                    'Resource ' + name + ' was successfully added',
                    true,
                    name);
            });
        }

        ctrl.open = function (item) {
            if (item.isFolder === true) {
                ctrl.crumbs.push(item.name);
            } else {
                let splitName = item.name.split('.');
                let extension = splitName.length > 1 ? splitName.pop() : undefined;
                if (extension === 'adm') {
                    openTransformationEditor(item);
                } else {
                    openEditor(item, extension);
                }
            }
        }

        function openEditor(item, extension) {
            let location = getFullLocation();
            entaxyResourcesService.getResource(location, true).then(resourceContent => {
                $uibModal.open({
                    component: 'entaxyEditorModal',
                    resolve: {
                        resourceName: () => item.name,
                        resourceContent: () => resourceContent,
                        extension: () => extension,
                        names: () => ctrl.items.map((item) => item.name)
                    },
                    size: 'xl',
                    backdrop: 'static'
                })
                .result.then(data => {
                    if (data.writeIntoSource) {
                        saveResource(
                            getLocationWithoutProtocol(),
                            data.content,
                            'Resource ' + item.name + ' was successfully edited',
                            false);
                    } else {
                        let path = getPath();
                        let separator = path.length > 0 ? '/' : '';
                        saveResource(
                            path + separator + data.name,
                            data.content,
                            'Resource ' + data.name + ' was successfully added',
                            true,
                            data.name);
                    }
                });
            });
        }

        function openTransformationEditor(item) {

            let location = getLocation();
            $location.search('location', location);

            $uibModal.open({
                component: 'entaxyAtlasmapConsoleModal',
                resolve: {
                    resourceName: () => item.name,
                    names: () => ctrl.items.map((item) => item.name),
                    location: () => location
                },
                size: 'xxl',
                backdrop: 'static'
            }).result
            .then((newName) => {
                $location.search('location', null);
                if (newName) {
                    Entaxy.notificationSuccess('Resource ' + newName + ' was successfully added');
                    updateItems(newName);
                } else {
                    Entaxy.notificationSuccess('Resource ' + item.name + ' was successfully edited');
                }
            })
            .catch((reason) => {
                $location.search('location', null);
                if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
                    Entaxy.notificationError(reason);
                }
            });
        }

        function openTransformationEditorInTab() {
            let currentLocation = $location.absUrl();
            let finalLocation = currentLocation.substring(0, currentLocation.indexOf('entaxy-management'))
                .concat('entaxy-transformation?location=').concat(getLocation());
            $window.open(finalLocation, '_blank');
        }

        function saveResource(path, content, notificationMessage, isUpdateNeeded, selectAfterSavingByName) {
            entaxyResourcesService
            .saveResource(selectedMbeanName, path, content)
            .then(() => {
                Entaxy.notificationSuccess(notificationMessage);
                if (isUpdateNeeded) {
                    updateItems(selectAfterSavingByName);
                }
            }).catch(error => {
                Entaxy.notificationError(error);
                Entaxy.log.error(error);
            });
        }

        function updateItems(selectByName) {
            let path = getPath();

            entaxyResourcesService.getResourcesInfo(selectedMbeanName, path)
            .then(originItems => {
                let items = originItems
                    .concat(entaxyResourcesService.getClientFoldersToAdd(clientFolders, originItems, ctrl.crumbs));
                ctrl.items = items.sort(Entaxy.compareBy('name')).sort((a, b) => b.isFolder - a.isFolder);

                if (selectByName) {
                    let itemToSelect = ctrl.items.find(item => item.name === selectByName);
                    ctrl.changeSelection(itemToSelect);
                    scrollToItem();
                }
            })
        }

        function scrollToItem() {
            setTimeout(function () {

                let element = ctrl.view === 'tiles' ?
                    document.getElementsByClassName('tile active')[0] :
                    document.getElementsByClassName('list active')[0];

                element.scrollIntoView();
            });
        }

        function getPath() {
            return entaxyResourcesService.getPath(ctrl.crumbs);
        }

        function getLocationWithoutProtocol(folderSelectionEnabled) {
            let isItemSelected = ctrl.selectedItems && ctrl.selectedItems.length == 1 &&
                (!ctrl.selectedItems[0].isFolder || (folderSelectionEnabled && ctrl.selectedItems[0].isFolder));
            let separator = getPath().length > 0 && isItemSelected ? '/' : '';
            let selectedItemName = isItemSelected ? ctrl.selectedItems[0].name : '';
            return getPath() + separator + selectedItemName;
        }

        function getLocation(folderSelectionEnabled) {
            return ctrl.protocol + ':' + getLocationWithoutProtocol(folderSelectionEnabled);
        }

        function getFullLocation() {
            return ENTAXY_RESOURCE_PREFIX + ctrl.protocol + '/' + getLocationWithoutProtocol();
        }

        function createFolder() {
            entaxyResourcesService.addFolder(ctrl.items, clientFolders, ctrl.crumbs);
        }

        function uploadResource() {
            ctrl.triggerUpload();
        }

        function downloadResources() {
            let path = getLocationWithoutProtocol(true);

            ctrl.selectedItems.forEach(item => {
                let fullPath = ctrl.selectedItems.length > 1 ? path + '/' + item.name : path;
                entaxyResourcesService.downloadResource(selectedMbeanName, fullPath)
                .then(result => {
                    entaxyService.downloadFileFromBase64StringContent(result, item.name);
                }).catch(error => {
                    Entaxy.notificationError(error);
                    Entaxy.log.error(error);
                });
            });
        }

        function copyResources() {
            processCopyCut(false);
        }

        function cutResources() {
            processCopyCut(true);
        }

        function processCopyCut(removeSource) {
            if (ctrl.selectedItems && ctrl.selectedItems.length > 0) {
                Entaxy.resourceCopyConfigs = {};
                ctrl.selectedItems.forEach(item => {
                    setCopyConfig(item, removeSource);
                });
            }
        }

        function setCopyConfig(item, removeSource) {
            let sourceResourcePath = ctrl.selectedItems && ctrl.selectedItems.length == 1 ?
                getLocation(true) : getLocation(true) + '/' + item.name;
            Entaxy.resourceCopyConfigs[item.name] = {
                sourceResourcePath: sourceResourcePath,
                removeSource: removeSource
            };
        }

        function pasteResources() {
            if (Object.keys(Entaxy.resourceCopyConfigs).length > 0) {
                let path = getPath();
                pasteWithUniquenessCheck(ctrl.items, path);
            }
        }

        function pasteResourceToFolder() {
            if (Object.keys(Entaxy.resourceCopyConfigs).length > 0) {
                let path = getLocationWithoutProtocol(true);

                entaxyResourcesService.getResourcesInfo(selectedMbeanName, path)
                .then(items => {
                    pasteWithUniquenessCheck(items, path);
                })
                .catch((error) => {
                    Entaxy.log.error(error);
                    Entaxy.notificationError('An error occurred while getting resources.');
                });
            }
        }

        function pasteWithUniquenessCheck(items, path) {
            let copiedDuplicateItems = [];
            let namesToPaste = Object.keys(Entaxy.resourceCopyConfigs);
            items.forEach(item => {
                if (namesToPaste.includes(item.name)) {
                    copiedDuplicateItems.push(item);
                }
            });
            if (copiedDuplicateItems.length > 0) {
                for (let i = copiedDuplicateItems.length - 1; i >= 0; i--) {
                    renameResourceAndPaste(copiedDuplicateItems[i], path);
                }
            }
            let copiedDuplicateItemsNames = copiedDuplicateItems.map(item => item.name);
            namesToPaste.filter(name => !copiedDuplicateItemsNames.includes(name)).forEach(name => {
                paste(Entaxy.resourceCopyConfigs[name].sourceResourcePath, path, name,
                    Entaxy.resourceCopyConfigs[name].removeSource);
            });
        }

        function renameResourceAndPaste(item, path) {
            entaxyResourcesService.openResourceNameInputModal(item, ctrl.items.map((item) => item.name), true, false)
            .then(name => {
                paste(Entaxy.resourceCopyConfigs[item.name].sourceResourcePath, path, name,
                    Entaxy.resourceCopyConfigs[item.name].removeSource);
            });
        }

        function paste(from, to, name, removeSource) {
            const fullToPath = to + '/' + name;
            entaxyResourcesService.pasteResource(selectedMbeanName, from, fullToPath)
            .then(result => {
                if (removeSource) {
                    entaxyResourcesService.removeResource(selectedMbeanName, from)
                    .then(result => {
                        let configToRemove = Object.entries(Entaxy.resourceCopyConfigs)
                            .find(([name, config]) => config.sourceResourcePath === from);
                        delete Entaxy.resourceCopyConfigs[configToRemove[0]];
                        updateItems();
                    }).catch(error => {
                        Entaxy.notificationError(error);
                        Entaxy.log.error(error);
                    });
                } else {
                    updateItems();
                }
            }).catch(error => {
                Entaxy.notificationError(error);
                Entaxy.log.error(error);
            });
        }

        function removeResources() {
            if (ctrl.selectedItems && ctrl.selectedItems.length > 0) {
                removeSelectedResources();
            }
        }

        function removeSelectedResources() {
            let title = 'Confirm Removing Resources';
            let message = 'Do you want to remove selected resources?';

            entaxyService.openConfirmationWindow(title, message)
            .then(() => {
                let promises = [];
                let failedResources = [];
                let path = getLocationWithoutProtocol(true);
                ctrl.selectedItems.forEach(item => {
                    let fullPath = ctrl.selectedItems.length > 1 ? path + '/' + item.name : path;
                    promises.push(
                        entaxyResourcesService
                            .removeResource(selectedMbeanName, fullPath)
                            .catch((error) => {
                                failedResources.push(fullPath);
                                Entaxy.log.error(error);
                            })
                    );
                });
                $q.all(promises).then(result => {
                    if (failedResources.length > 0) {
                        let message = 'Errors occurred while removing resources';
                        Entaxy.notificationError(message);
                    } else {
                        Entaxy.notificationSuccess('Resources were successfully removed');
                    }
                    ctrl.selectedItems = [];
                    updateItems();
                }).catch(error => {
                    Entaxy.notificationError(error);
                    EntaxyCICD.log.error(error);
                });
            });
        }

        function isItemSelected(item) {
            return ctrl.selectedItems && ctrl.selectedItems.includes(item);
        }

        ctrl.triggerUpload = function () {
            document.getElementById('file-input').click();
        }

        ctrl.upload = function (file) {
            let separator = getPath().length > 0 ? '/' : '';
            let uploadPromise = entaxyResourcesService
                .uploadFile(file, ctrl.protocol, getPath() + separator + file.name);

            if (uploadPromise) {
                uploadPromise.then((response) => {
                    Entaxy.notificationSuccess('File ' + response.data + ' was successfully uploaded.');
                    updateItems();
                })
                .catch((error) => {
                    Entaxy.log.error(error);
                    Entaxy.notificationError('An error occurred while uploading the file.');
                });
            }
        }

        function getHotkeysConfigs() {
            return [
                {
                    ...Entaxy.getCopyHotkeyDescription(),
                    callback: function (event) {
                        event.preventDefault();
                        copyResources();
                    }
                },
                {
                    ...Entaxy.getCutHotkeyDescription(),
                    callback: function(event) {
                        event.preventDefault();
                        cutResources();
                    }
                },
                {
                    ...Entaxy.getPasteHotkeyDescription(),
                    callback: function(event) {
                        event.preventDefault();
                        pasteResources();
                    }
                },
                {
                    ...Entaxy.getRemoveHotkeyDescription(),
                    callback: function(event) {
                        event.preventDefault();
                        removeResources();
                    }
                }
            ];
        }
    }
    entaxyResourcesController.$inject = ['workspace', '$scope', 'jolokia', 'entaxyService', 'entaxyResourcesService',
        '$timeout', '$uibModal', '$cookies', 'entaxyHotkeysService', '$q', '$window', '$location', '$route'];

})(Entaxy || (Entaxy = {}));
