/*-
 * ~~~~~~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('entaxyProperties', {
        bindings: {
            itemName: '@',
            useGrandParentMbean: '<'
        },
        template:
        `
          <div class="properties-header-container">
            <div>
              <h2>
                {{$ctrl.title}}
              </h2>
              <span ng-if="$ctrl.isFormDirty || $ctrl.hasChangedPrivateObjects">
                There are unsaved changes
              </span>
            </div>
            
            <button type="submit" class="btn btn-primary" ng-click="$ctrl.saveAll()"
                    ng-if="$ctrl.private && !$ctrl.isReadOnly()"
                    ng-disabled="!$ctrl.isOwnerChanged && !$ctrl.isFormDirty">Save all</button>
            <button type="submit" class="btn btn-primary" ng-click="$ctrl.save()" ng-if="!$ctrl.isReadOnly()">
              {{$ctrl.submitBtnTitle}}
            </button>
          </div>
          
          <div class="properties-container">
            <entaxy-modal-group-fields groups="$ctrl.groups" fields="$ctrl.formFields"
                  use-form-dirty="true" is-form-dirty="$ctrl.isFormDirty" errors="$ctrl.errors"
                  mode="$ctrl.mode" ng-if="$ctrl.groups && $ctrl.formFields"></entaxy-modal-group-fields>
          </div>
        `,
        controller: entaxyPropertiesController
    })
    .name;

    function entaxyPropertiesController($scope, workspace, entaxyService, jolokia, $location, $route, entaxyHotkeysService,
                                        entaxyAttributesCacheService, entaxyPrivateObjectsCacheService) {
        'ngInject';

        let ctrl = this;

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

            ctrl.mode = Entaxy.MODAL_MODES.EDIT;

            let selectedMbean = workspace.getSelectedMBean();
            ctrl.title = 'Properties of ' + selectedMbean.title;
            ctrl.submitBtnTitle = Entaxy.getButtonTitleByMode(ctrl.mode);
            let selectedMbeanName = selectedMbean.objectName;

            if (selectedMbeanName) {
                populateExistentObjectInfo(selectedMbeanName);
            } else {
                populateAddedObjectInfo(selectedMbean);
            }
        }

        function populateExistentObjectInfo(mbeanName) {
            let attributes = entaxyAttributesCacheService.getAttributes(mbeanName);

            if (attributes.Scope === Entaxy.SCOPE.PRIVATE) {
                ctrl.private = true;
                ctrl.objectFullId = attributes.ObjectFullId;
                ctrl.owner = attributes.Owner;
                setOwnerChanged();
                ctrl.itemInfo = entaxyPrivateObjectsCacheService.getChangedObjectConfig(ctrl.objectFullId);
                if (entaxyPrivateObjectsCacheService.isObjectSetToRemoval(ctrl.objectFullId)) {
                    ctrl.isToRemoval = true;
                    ctrl.mode = Entaxy.MODAL_MODES.VIEW;
                }
            } else if (entaxyPrivateObjectsCacheService.isChanged(mbeanName)) {
                ctrl.hasChangedPrivateObjects = true;
            }

            if (attributes.RuntimeType === Entaxy.RUNTIME_TYPE.CONNECTION && attributes.Platform) {
                ctrl.mode = Entaxy.MODAL_MODES.VIEW;
            }

            if (ctrl.mode !== Entaxy.MODAL_MODES.VIEW) {
                entaxyService.readObjectClusterState(mbeanName).then(objectClusterState => {
                    if (objectClusterState !== Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED) {
                        ctrl.local = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.LOCAL;
                    } else {
                        ctrl.mode = Entaxy.MODAL_MODES.VIEW;
                    }
                }).catch(e => Entaxy.notificationError(e));
            }

            if (!ctrl.itemInfo) {
                entaxyService.readConfiguration(mbeanName)
                .then(result => {
                    ctrl.itemInfo = result;
                    ctrl.factories = [ entaxyService.getFactoryByTitle(ctrl.itemInfo.factoryId) ];
                    makeFormFieldsAndGroups();
                }).catch(error => {
                    Entaxy.notificationError(error);
                    Entaxy.log.error(error);
                });
            } else {
                ctrl.factories = [ entaxyService.getFactoryByTitle(ctrl.itemInfo.factoryId) ];
                makeFormFieldsAndGroups();
            }
        }

        function populateAddedObjectInfo(mbean) {
            ctrl.private = true;

            let parentMbeanName = mbean.parent.objectName;
            let objectsInfo = entaxyPrivateObjectsCacheService.getAddedObjectsInfo(parentMbeanName);
            let objectInfo = objectsInfo.find(objInfo => mbean.key === mbean.parent.key + '-' + objInfo.ui.id);

            ctrl.itemInfo = objectInfo;
            ctrl.owner = ctrl.itemInfo.ui.owner;
            setOwnerChanged();
            ctrl.isToRemoval = ctrl.itemInfo.toRemoval;
            if (ctrl.isToRemoval) {
                ctrl.mode = Entaxy.MODAL_MODES.VIEW;
            }
            ctrl.factories = [ entaxyService.getFactoryByTitle(ctrl.itemInfo.factoryId) ];

            makeFormFieldsAndGroups();
        }

        function makeFormFieldsAndGroups() {

            ctrl.formFields = [];

            ctrl.formFields.push({
                label: 'Factory',
                name: 'factoryId',
                type: 'text',
                description: ctrl.factories[0].description,
                value: ctrl.factories[0].displayName,
                originalValue: ctrl.factories[0].name,
                readOnly: true,
                required: true,
                group: 'general'
            });

            let mbeanName = ctrl.factories[0].mbeanName;

            entaxyService.getFields(mbeanName)
            .then((response) => {

                let groups = new Set();
                groups.add('general');

                _.forEach(JSON.parse(response), (field) => {

                    let formField = entaxyService
                        .makeFormField(field, ctrl.itemInfo.objectId, ctrl.itemInfo.properties,
                            ctrl.itemInfo.configurableOnly, ctrl.mode);
                    if (formField) {
                        ctrl.formFields.push(formField);
                        if (!formField.isBackRef && !formField.isHidden) {
                            groups.add(formField.group);
                        }
                    }
                });

                if (ctrl.mode !== Entaxy.MODAL_MODES.VIEW) {
                    processDependencies();
                }

                ctrl.groups = Array.from(groups).map((group) => { return { name: group, displayName: group }; });
            });
        }

        function processDependencies() {
            let dependentFormFields = entaxyService
                .getDependentFormFields(ctrl.formFields, ctrl.itemInfo.configurableOnly);
            ctrl.definingFormFields = entaxyService.getDefiningFormFields(dependentFormFields, ctrl.formFields);

            for (let i = 0; i < ctrl.definingFormFields.length; i++) {
                if (ctrl.definingFormFields[i].value) {
                    let dependentFormFieldsWithListType = dependentFormFields
                            .filter(field => (field.typeInfo && field.typeInfo.type === 'list'));
                    entaxyService.processDependencies(dependentFormFieldsWithListType,
                                                      ctrl.definingFormFields,
                                                      ctrl.definingFormFields[i].name,
                                                      ctrl.definingFormFields[i].value,
                                                      undefined);
                }
                $scope.$watch('$ctrl.definingFormFields[' + i + '].value', function(newValue, oldValue) {
                    if (newValue !== oldValue) {
                        Entaxy.changingFieldValueNotification('defining');

                        entaxyService.processDependencies(dependentFormFields,
                                                          ctrl.definingFormFields,
                                                          ctrl.definingFormFields[i].name,
                                                          newValue,
                                                          oldValue);
                    }
                });
            }
        }

        setTimeout( function () {
            ctrl.activeTabIndex = entaxyService.getActiveTabIndex();
        })

        $scope.$on("$locationChangeStart", function(event) {
            if (ctrl.isFormDirty && !confirm(Entaxy.CONFIRMATION.UNSAVED_CHANGES)) {
                event.preventDefault();
                ctrl.isTreeOrTabSelectionUpdateNeeded = true;
            }
        });

        $scope.$watch('$ctrl.isTreeOrTabSelectionUpdateNeeded', function (newValue) {
            if (newValue) {
                setTimeout(function () {
                    entaxyService.updateTabSelection(ctrl.activeTabIndex);
                });
                Jmx.updateTreeSelectionFromURL($location, $(entaxyTreeElementId));
                ctrl.isTreeOrTabSelectionUpdateNeeded = false;
            }
        });

        ctrl.save = function() {
            let isConfirmationNeeded = !ctrl.isFormDirty && !ctrl.hasChangedPrivateObjects;
            entaxyService.requestConfirmationForSavingIfNeededAndProceed(isConfirmationNeeded, save);
        }

        ctrl.saveAll = function () {
            entaxyService.requestConfirmationForSavingOwnerAndProceed(saveAll);
        }

        function save() {
            entaxyService.validateFields(ctrl.formFields, ctrl.factories[0])
            .then(errors => {
                ctrl.errors = errors;

                if (Object.keys(ctrl.errors).length === 0) {
                    let selectedMBeanName = workspace.getSelectedMBeanName();
                    entaxyAttributesCacheService.setToUpdate(selectedMBeanName);

                    let args = entaxyService.getArguments(ctrl.formFields, ctrl.factories);

                    if (!ctrl.private) {
                        args.configProperties = ctrl.itemInfo.properties;
                        args.configurableOnly = ctrl.itemInfo.configurableOnly;

                        entaxyService.saveItem(args, ctrl.local);
                    } else {

                        let reloadTreeNeeded = false;
                        let selectedMbean = workspace.getSelectedMBean();

                        updateFields(args, selectedMbean, reloadTreeNeeded);

                        if (selectedMbean.objectName) {
                            entaxyPrivateObjectsCacheService
                                .addChanges(selectedMbean, ctrl.objectFullId, ctrl.owner, ctrl.itemInfo);
                        }

                        Entaxy.notificationSuccess('Operation Succeeded');

                        if (reloadTreeNeeded) {
                            reloadTreeAndUpdateLocation();
                        }
                    }

                    ctrl.isFormDirty = false;
                }
            });
        }

        function saveAll() {
            entaxyService.validateFields(ctrl.formFields, ctrl.factories[0])
            .then(errors => {
                ctrl.errors = errors;

                if (Object.keys(ctrl.errors).length === 0) {
                    let selectedMBeanName = workspace.getSelectedMBeanName();
                    entaxyAttributesCacheService.setToUpdate(selectedMBeanName);

                    let args = entaxyService.getArguments(ctrl.formFields, ctrl.factories);

                    let reloadTreeNeeded = false;
                    let selectedMbean = workspace.getSelectedMBean();

                    updateFields(args, selectedMbean, reloadTreeNeeded);

                    if (selectedMbean.objectName) {
                        entaxyPrivateObjectsCacheService
                            .addChanges(selectedMbean, ctrl.objectFullId, ctrl.owner, ctrl.itemInfo);
                    }

                    let ownerMbean = entaxyPrivateObjectsCacheService.findOwnerMbean(selectedMbean, ctrl.owner);
                    let ownerMbeanName = ownerMbean.objectName;

                    entaxyService.readObjectClusterState(ownerMbeanName).then(objectClusterState => {
                        if (objectClusterState !== Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED) {
                            let local = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.LOCAL;

                            entaxyService.readConfiguration(ownerMbeanName)
                            .then(objectInfo => {
                                let args = entaxyService.getArgumentsFromConfig(objectInfo);

                                entaxyService.resolveRoutesFieldValueAndAddNew(args, ownerMbean)
                                .then(() => {
                                    entaxyService.resolveResourceRefFields(args.fields)
                                    .then(() => entaxyService.saveItem(args, local, updateLocation));
                                });
                            }).catch(error => {
                                Entaxy.notificationError(error);
                                Entaxy.log.error(error);
                            });
                        } else {
                            Entaxy.notificationError(Entaxy.NON_CLUSTERED_MESSAGE.EDITING);
                        }
                    }).catch(e => Entaxy.notificationError(e));
                }
            });
        }

        function updateFields(args, selectedMbean, reloadTreeNeeded) {
            args.fields.forEach(field => {
                if (field.changed) {
                    if (!selectedMbean.objectName && field.name === ctrl.itemInfo.ui.identifierFieldName) {
                        reloadTreeNeeded = true;
                    }
                    if (field.configured && field.valueToConfig !== undefined) {
                        ctrl.itemInfo.properties[field.name] = field.valueToConfig;
                    } else {
                        ctrl.itemInfo.properties[field.name] = field.value;
                    }
                    if (!selectedMbean.objectName) {
                        let formField = ctrl.itemInfo.ui.formFields
                            .find(formField => formField.name === field.name);
                        if (formField) {
                            formField.value = field.value;
                        }
                    }
                }
            });
        }

        ctrl.isReadOnly = function () {
            return ctrl.mode === Entaxy.MODAL_MODES.VIEW;
        }

        function updateLocation(properties, objectId) {
            if (ctrl.private && objectId && !ctrl.objectFullId) {
                let nid = $location.search().nid;
                let oldId = ctrl.itemInfo.ui.id;
                $location.search('nid', nid.replace('-' + oldId, ''));
            }
        }

        function setOwnerChanged() {
            if (ctrl.private) {
                ctrl.isOwnerChanged = entaxyPrivateObjectsCacheService
                    .isOwnerChanged(workspace.getSelectedMBean(), ctrl.owner);
            }
        }

        function reloadTreeAndUpdateLocation() {
            let nid = $location.search().nid;
            let oldId = ctrl.itemInfo.ui.id;
            ctrl.itemInfo.ui.id = ctrl.itemInfo.properties[ctrl.itemInfo.ui.identifierFieldName];
            workspace.loadTree();
            $location.search('nid', nid.replace(oldId, ctrl.itemInfo.ui.id));
        }

        $scope.$on(Jmx.TreeEvent.Updated, () => {
            $route.reload();
        });

        function getHotkeysConfigs() {
            return [
                {
                    ...Entaxy.getSaveHotkeyDescription(),
                    callback: function (event) {
                        event.preventDefault();
                        if (!ctrl.isReadOnly()) {
                            ctrl.save();
                        }
                    }
                },
                {
                    ...Entaxy.getSaveAllHotkeyDescription(),
                    callback: function(event) {
                        event.preventDefault();
                        if (ctrl.private && !ctrl.isReadOnly() && (ctrl.isOwnerChanged || ctrl.isFormDirty)) {
                            ctrl.saveAll();
                        }
                    }
                }
            ];
        }
    }
    entaxyPropertiesController.$inject = ['$scope', 'workspace', 'entaxyService', 'jolokia', '$location', '$route',
        'entaxyHotkeysService', 'entaxyAttributesCacheService', 'entaxyPrivateObjectsCacheService'];

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