/*-
 * ~~~~~~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.factory('entaxyPrivateObjectsCacheService', ['workspace', 'entaxyAttributesCacheService',
        function(workspace, entaxyAttributesCacheService) {
            let changedObjectsInfo = {};
            let changedMbeanNames = {};
            let addedObjectsInfo = {};

            return {
                addChanges: function (privateObjectMbean, id, owner, config) {
                    return addChanges(privateObjectMbean, id, owner, config);
                },
                isChanged: function (mbeanName) {
                    return isChanged(mbeanName);
                },
                isOwnerChanged: function (privateObjectMbean, owner) {
                    return isOwnerChanged(privateObjectMbean, owner);
                },
                getChangedObjectInfo: function (id) {
                    return getChangedObjectInfo(id);
                },
                getChangedObjectConfig: function (id) {
                    return getChangedObjectConfig(id);
                },
                setObjectToRemoval: function (id, privateObjectMbeanName, config) {
                    return setObjectToRemoval(id, privateObjectMbeanName, config);
                },
                isObjectSetToRemoval: function (id) {
                    return isObjectSetToRemoval(id);
                },
                restoreObject: function (id) {
                    return restoreObject(id);
                },
                addNew: function (parentMbean, privateObjectInfo) {
                    return addNew(parentMbean, privateObjectInfo);
                },
                hasAddedChildren: function (parentMbeanName) {
                    return hasAddedChildren(parentMbeanName);
                },
                getAddedObjectsInfo: function (parentMbeanName) {
                    return getAddedObjectsInfo(parentMbeanName);
                },
                setAddedObjectToRemoval: function (parentMbeanName, id) {
                    return setAddedObjectToRemoval(parentMbeanName, id);
                },
                isAddedObjectSetToRemoval: function (parentMbeanName, id) {
                    return isAddedObjectSetToRemoval(parentMbeanName, id);
                },
                restoreAddedObject: function (parentMbeanName, id) {
                    return restoreAddedObject(parentMbeanName, id);
                },
                removeFromCache: function (owner) {
                    return removeFromCache(owner);
                },
                findOwnerMbean(descendantMbean, owner) {
                    return findOwnerMbean(descendantMbean, owner);
                }
            };

            function addChanges(privateObjectMbean, id, owner, config) {
                setChangedMbeanNamesAndUpdateTree(privateObjectMbean, owner);
                setChangedObjectInfo(id, owner, config);
            }

            function setChangedMbeanNamesAndUpdateTree(privateObjectMbean, owner) {
                if (!changedMbeanNames[owner]) {
                    let ownerMbean = findOwnerMbean(privateObjectMbean, owner);

                    changedMbeanNames[owner] = [ ownerMbean.objectName, privateObjectMbean.objectName ];

                    workspace.loadTree();
                } else {
                    if (!changedMbeanNames[owner].includes(privateObjectMbean.objectName)) {
                        changedMbeanNames[owner].push(privateObjectMbean.objectName);

                        workspace.loadTree();
                    }
                }
            }

            function setChangedObjectInfo(id, owner, config) {
                changedObjectsInfo[id] = {
                    owner: owner,
                    config: config
                }
            }

            function isChanged(mbeanName) {
                return Object.values(changedMbeanNames).flat().includes(mbeanName);
            }

            function isOwnerChanged(privateObjectMbean, owner) {
                let ownerMbean = findOwnerMbean(privateObjectMbean, owner);
                return isChanged(ownerMbean.objectName);
            }

            function getChangedObjectInfo(id) {
                return changedObjectsInfo[id];
            }

            function getChangedObjectConfig(id) {
                let object = getChangedObjectInfo(id);
                return object ? object.config : null;
            }

            function setObjectToRemoval(id, privateObjectMbeanName, config) {
                if (changedObjectsInfo[id]) {
                    changedObjectsInfo[id].toRemoval = true;
                } else {
                    let selectedMbean = workspace.getSelectedMBean();

                    let privateObjectMbean = selectedMbean
                        .findDescendant(child => child.objectName === privateObjectMbeanName);
                    let attributes = entaxyAttributesCacheService.getAttributes(privateObjectMbeanName);

                    addChanges(privateObjectMbean, id, attributes.Owner, config);

                    changedObjectsInfo[id].toRemoval = true;
                }
            }

            function isObjectSetToRemoval(id) {
                let object = getChangedObjectInfo(id);
                return object ? object.toRemoval : undefined;
            }

            function restoreObject(id) {
                if (changedObjectsInfo[id]) {
                    delete changedObjectsInfo[id].toRemoval;
                }
            }

            function addNew(parentMbean, privateObjectInfo) {
                let parentMbeanName = parentMbean.objectName;
                if (!addedObjectsInfo[parentMbeanName]) {
                    addedObjectsInfo[parentMbeanName] = [ privateObjectInfo ];
                } else {
                    addedObjectsInfo[parentMbeanName].push(privateObjectInfo);
                }

                let owner = privateObjectInfo.ui.owner;
                let ownerMbean = findOwnerMbean(parentMbean, owner);

                if (!changedMbeanNames[owner]) {
                    changedMbeanNames[owner] = [ownerMbean.objectName];
                }
            }

            function hasAddedChildren(parentMbeanName) {
                return addedObjectsInfo[parentMbeanName] ? true : false;
            }

            function getAddedObjectsInfo(parentMbeanName) {
                return addedObjectsInfo[parentMbeanName];
            }

            function setAddedObjectToRemoval(parentMbeanName, id) {
                if (addedObjectsInfo[parentMbeanName]) {
                    let objectToRemoval = addedObjectsInfo[parentMbeanName]
                        .find(privateObjInfo => privateObjInfo.ui.id === id);
                    objectToRemoval.toRemoval = true;
                }
            }

            function isAddedObjectSetToRemoval(parentMbeanName, id) {
                if (addedObjectsInfo[parentMbeanName]) {
                    let objectToRemoval = addedObjectsInfo[parentMbeanName]
                        .find(privateObjInfo => privateObjInfo.ui.id === id);
                    return objectToRemoval.toRemoval;
                }
            }

            function restoreAddedObject(parentMbeanName, id) {
                if (addedObjectsInfo[parentMbeanName]) {
                    let objectToRestore = addedObjectsInfo[parentMbeanName]
                        .find(privateObjInfo => privateObjInfo.ui.id === id);
                    delete objectToRestore.toRemoval;
                }
            }

            function removeFromCache(owner) {
                delete changedMbeanNames[owner];
                removeAddedByOwner(owner);
                removeByOwner(owner);
            }

            function removeAddedByOwner(owner) {
                addedObjectsInfo = Object.fromEntries(Object.entries(addedObjectsInfo)
                    .filter(([key, value]) => value && value.length > 0 ? value[0].ui.owner !== owner : false));
            }

            function removeByOwner(owner) {
                changedObjectsInfo = Object.fromEntries(Object.entries(changedObjectsInfo)
                    .filter(([key, value]) => value.owner !== owner));
            }

            function findOwnerMbean(descendantMbean, owner) {
                return descendantMbean.findAncestor(mbean => {
                    if (mbean.objectName) {
                        let attributes = entaxyAttributesCacheService.getAttributes(mbean.objectName);
                        return attributes.Id === owner;
                    }
                });
            }
        }
    ])
})(Entaxy || (Entaxy = {}));
