/*-
 * ~~~~~~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('entaxyProfileDiagram', {
        template:
        `
          <div id="leader-lines-container" class="profile-diagram-with-palette-container">
            <div class="profile-diagram-container">

              <div class="blocks-container">
                <entaxy-profile-diagram-external-system-points connectors="$ctrl.inConnectors" type="source">
                </entaxy-profile-diagram-external-system-points>
                <entaxy-profile-diagram-external-system-points connectors="$ctrl.outConnectors" type="target">
                </entaxy-profile-diagram-external-system-points>
              </div>

              <div droppable handle-drop-fn="$ctrl.handleDropFn(droppedElementId)" class="profile-block"
                    ng-class="{'has-changes': $ctrl.isProfileChanged}"
                    ng-click="$ctrl.editProfileProperties('general')">
                <div class="profile-title-container">
                  <span class="profile-diagram-support-span" ng-if="$ctrl.isProfileChanged"></span>
                  <span class="profile-title">{{$ctrl.profileTitle}}</span>
                  <span class="pficon pficon-save" ng-click="$ctrl.saveProfile($event)"
                        data-toggle="tooltip" title="Save profile changes" ng-if="$ctrl.isProfileChanged"></span>
                </div>

                <entaxy-connectors-with-flow direction="in" connectors="$ctrl.inConnectors"
                        profile-name="$ctrl.profileName" edit-customization-point-fn="$ctrl.editCustomizationPoint"
                        ng-if="$ctrl.inConnectors && $ctrl.inConnectors.length > 0" update-fn="$ctrl.update"
                        edit-profile-properties-fn="$ctrl.editProfileProperties"
                        edit-properties-fn="$ctrl.editProperties" save-connector-fn="$ctrl.save">
                </entaxy-connectors-with-flow>

                <entaxy-connectors-with-flow direction="out" connectors="$ctrl.outConnectors"
                        profile-name="$ctrl.profileName" edit-customization-point-fn="$ctrl.editCustomizationPoint"
                        ng-if="$ctrl.outConnectors && $ctrl.outConnectors.length > 0" update-fn="$ctrl.update"
                        edit-profile-properties-fn="$ctrl.editProfileProperties"
                        edit-properties-fn="$ctrl.editProperties" save-connector-fn="$ctrl.save">
                </entaxy-connectors-with-flow>
              </div>

              <div class="blocks-container">
                <div id="integrations-in-block" class="integrations-block"
                        ng-if="$ctrl.inConnectors && $ctrl.inConnectors.length > 0">
                  <span>integrations</span>
                </div>
                <div id="default-route-block" class="default-route-block"
                        ng-class="{'has-changes': $ctrl.isDefaultRouteChanged}"
                        ng-click="$ctrl.editDefaultRouteProperties()"
                        ng-if="$ctrl.inConnectors && $ctrl.inConnectors.length > 0">
                  <div class="default-route-title-container">
                    <span class="default-route-title">default-route</span>
                    <span class="pficon pficon-save" ng-click="$ctrl.saveDefaultRoute($event)"
                          data-toggle="tooltip" title="Save default route changes"
                          ng-if="$ctrl.isDefaultRouteChanged"></span>
                  </div>
                  <div class="customization-point-block"
                        ng-click="$ctrl.editDefaultRouteCustomizationPoint($event)">
                    route
                  </div>
                </div>
                <div id="integrations-out-block" class="integrations-block"
                        ng-if="$ctrl.outConnectors && $ctrl.outConnectors.length > 0">
                  <span>integrations</span>
                </div>
              </div>
            </div>
          
            <entaxy-profile-diagram-palette></entaxy-profile-diagram-palette>
          </div>
        `,
        controller: entaxyProfileDiagramController
    })
    .name;

    function entaxyProfileDiagramController($scope, workspace, jolokia, $location, $q,
                                            entaxyService, entaxyProfileDiagramService, entaxyAttributesCacheService,
                                            entaxyPrivateObjectsCacheService, $uibModal, $route, $cookies) {
        'ngInject';

        let ctrl = this;
        let selectedMBean = workspace.getSelectedMBean();
        let defaultRouteMbean = selectedMBean.findDescendant(child =>
            child.objectName && child.objectName.endsWith('route=default'));

        ctrl.$onInit = function () {

            ctrl.profileName = jolokia.getAttribute(selectedMBean.objectName, 'Name')
            ctrl.profileTitle = 'Profile: ' + ctrl.profileName;
            ctrl.isProfileChanged = entaxyProfileDiagramService.isProfileChanged();
            ctrl.isDefaultRouteChanged = entaxyProfileDiagramService.isDefaultRouteChanged();

            populateConnectors();
        }

        setTimeout(function () {
            let contentElement = document.getElementsByClassName("contents")[0];
            contentElement.style.setProperty("padding", "0", "important");
        }, 10);

        function populateConnectors() {
            let inConnectors = [];
            let outConnectors = [];

            if (selectedMBean && selectedMBean.isFolder) {
                entaxyService.getAllChildMBeansByRuntimeType(selectedMBean, Entaxy.RUNTIME_TYPE.CONNECTOR)
                .then((mbeans) => {
                    mbeans.forEach((mbean) => {
                        let direction = mbean.attributes.Direction;
                        let connectorMbeanName = mbean.mbean.objectName;
                        let isConnectorChanged = entaxyProfileDiagramService.isConnectorChanged(connectorMbeanName);
                        let connector = {
                            name: mbean.attributes.Name,
                            displayName: mbean.attributes.DisplayName,
                            classifier: mbean.attributes.Classifier,
                            protocol: mbean.attributes.Protocol,
                            mbeanName: connectorMbeanName,
                            isChanged: isConnectorChanged,
                            isCustom: mbean.attributes.ObjectLabel ? // fixme object label is bad attr for this purpose
                                mbean.attributes.ObjectLabel.split(',').includes('custom') : false
                        };
                        if (direction === 'in') {
                            inConnectors.push(connector);
                        } else if (direction === 'out') {
                            outConnectors.push(connector);
                        }
                        if (isConnectorChanged) {
                            entaxyProfileDiagramService.getChanges(connectorMbeanName).connector = connector;
                        }
                    });

                    ctrl.inConnectors = inConnectors.sort(Entaxy.compareBy('name'));
                    ctrl.outConnectors = outConnectors.sort(Entaxy.compareBy('name'));

                    setMarginForAdditionalBlocks();
                    if (ctrl.inConnectors.length > 0) {
                        drawLinesForInDirectedConnectors();
                    }
                    if (ctrl.outConnectors.length > 0) {
                        drawLinesForOutDirectedConnectors();
                    }
                });
            }
        }

        ctrl.handleDropFn = function (factoryName) {

            let factory = entaxyService.getFactoryByTitle(factoryName);

            let selectedMbeanName = workspace.getSelectedMBeanName();
            let parentName = jolokia.getAttribute(selectedMbeanName, 'Name');

            let resolve = {
                mode: () => Entaxy.MODAL_MODES.ADD,
                itemType: () => 'Connector',
                parentName: () => parentName,
                factories: () => [ factory ]
            };

            entaxyService.openModalAndProcessResults(resolve, false, null, () => ctrl.connectorAdded = true);
        }

        // sets top margin for source, target, default-route and integration blocks
        function setMarginForAdditionalBlocks() {
            setTimeout(function () {
                let sourceBlocksOccupiedHeight = 0;
                let defaultRouteBlockMarginPlusHeight = 0;
                let padding = 10;
                if (ctrl.inConnectors && ctrl.inConnectors.length > 0) {
                    let integrationsInBlock = document.getElementById("integrations-in-block");
                    let inFlowBlock = document.getElementById("in-flow-block");
                    let inFlowPreRouteBlock = document.getElementById("in-flow_pre-route");
                    let defaultRouteBlock = document.getElementById("default-route-block");

                    let integrationsInBlockHeight = integrationsInBlock.offsetHeight;

                    let integrationsInBlockMarginTop = inFlowBlock.offsetTop -
                        integrationsInBlockHeight - padding;
                    let defaultRouteBlockMarginTop = inFlowPreRouteBlock.offsetTop -
                        integrationsInBlockMarginTop - integrationsInBlockHeight - padding;

                    integrationsInBlock.style.marginTop = integrationsInBlockMarginTop + 'px';
                    defaultRouteBlock.style.marginTop = defaultRouteBlockMarginTop + 'px';
                    defaultRouteBlockMarginPlusHeight = integrationsInBlockMarginTop + integrationsInBlockHeight +
                        defaultRouteBlockMarginTop + defaultRouteBlock.offsetHeight;

                    sourceBlocksOccupiedHeight =
                        setMarginForSourceOrTargetBlocks(ctrl.inConnectors, true, sourceBlocksOccupiedHeight, padding);
                }
                if (ctrl.outConnectors && ctrl.outConnectors.length > 0) {
                    let outFlowPreRouteBlock = document.getElementById("out-flow_pre-route");
                    let integrationsBlock = document.getElementById("integrations-out-block");
                    let integrationsBlockMarginTop = outFlowPreRouteBlock.offsetTop -
                        defaultRouteBlockMarginPlusHeight - padding;
                    integrationsBlock.style.marginTop = integrationsBlockMarginTop + 'px';

                    setMarginForSourceOrTargetBlocks(ctrl.outConnectors, false, sourceBlocksOccupiedHeight, padding);
                }
            });
        };

        function setMarginForSourceOrTargetBlocks(connectors, isSource, previousBlocksOccupiedHeight, padding) {
            connectors.forEach(connector => {
                let manageableBlock = isSource ?
                    document.getElementById("source-" + connector.name + "-block") :
                    document.getElementById("target-" + connector.name + "-block");
                let connectorCustomizationPointBlock = isSource ?
                    document.getElementById(connector.name + "_pre-route") :
                    document.getElementById(connector.name + "_pre-output");
                let manageableBlockMarginTop = connectorCustomizationPointBlock.offsetTop -
                    previousBlocksOccupiedHeight - padding;
                manageableBlock.style.marginTop = manageableBlockMarginTop + 'px';
                previousBlocksOccupiedHeight += manageableBlockMarginTop + manageableBlock.offsetHeight;
            });
            return previousBlocksOccupiedHeight;
        }

        let lines = [];

        // draws lines for in-directed connector block
        function drawLinesForInDirectedConnectors () {
            setTimeout(function () {

                if (ctrl.inConnectors) {
                    ctrl.inConnectors.forEach((connector) => {

                        if (connector.isCustom) {
                            lines.push(new LeaderLine(
                                LeaderLine.pointAnchor(
                                    document.getElementById('source-' + connector.name + '-block'),
                                    {x: '100%', y: 11}
                                ),
                                document.getElementById(connector.name + '_custom-route'),
                                {color: 'green', size: 2, path: 'straight'}
                            ));
                            lines.push(new LeaderLine(
                                document.getElementById(connector.name + '_custom-route'),
                                document.getElementById(connector.name + '_pre-route'),
                                {color: 'green', size: 2, path: 'straight'}
                            ));
                        } else {
                            lines.push(new LeaderLine(
                                LeaderLine.pointAnchor(
                                    document.getElementById('source-' + connector.name + '-block'),
                                    {x: '100%', y: 11}
                                ),
                                document.getElementById(connector.name + '_pre-route'),
                                {color: 'green', size: 2, path: 'straight'}
                            ));
                        }

                        lines.push(new LeaderLine(
                            document.getElementById(connector.name + '_pre-route'),
                            document.getElementById('in-flow_pre-route'),
                            {color: 'green', size: 2, path: 'grid', startSocketGravity: [10, 0]}
                        ));

                        lines.push(new LeaderLine(
                            document.getElementById(connector.name + '_response'),
                            LeaderLine.pointAnchor(
                                document.getElementById('source-' + connector.name + '-block'),
                                {x: '100%', y: 43}
                            ),
                            {color: 'blue', size: 2, path: 'straight'}
                        ));

                        lines.push(new LeaderLine(
                            LeaderLine.pointAnchor(
                                document.getElementById('in-flow_response'),
                                {x: 0, y: '50%'}
                            ),
                            document.getElementById(connector.name + '_response'),
                            {color: 'blue', size: 2, path: 'grid', startSocketGravity: [-10, 0]}
                        ));
                    });

                    lines.push(new LeaderLine(
                        document.getElementById('in-flow_pre-route'),
                        LeaderLine.pointAnchor(
                            document.getElementById('default-route-block'),
                            {x: 0, y: 11}
                        ),
                        {color: 'green', size: 2, path: 'straight'}
                    ));

                    lines.push(new LeaderLine(
                        LeaderLine.pointAnchor(
                            document.getElementById('default-route-block'),
                            {x: 0, y: 43}
                        ),
                        document.getElementById('in-flow_response'),
                        {color: 'blue', size: 2, path: 'straight'}
                    ));

                    lines.push(new LeaderLine(
                        LeaderLine.pointAnchor(
                            document.getElementById('default-route-block'),
                            {x: 32.5, y: 0}
                        ),
                        LeaderLine.pointAnchor(
                            document.getElementById('integrations-in-block'),
                            {x: 32.5, y: '100%'}
                        ),
                        {color: 'green', size: 2, path: 'straight'}
                    ));

                    lines.push(new LeaderLine(
                        LeaderLine.pointAnchor(
                            document.getElementById('integrations-in-block'),
                            {x: 64.5, y: '100%'}
                        ),
                        LeaderLine.pointAnchor(
                            document.getElementById('default-route-block'),
                            {x: 64.5, y: 0}
                        ),
                        {color: 'blue', size: 2, path: 'straight'}
                    ));
                }

            }, 50);
        }

        // draws lines for out-directed connector block
        function drawLinesForOutDirectedConnectors() {
            setTimeout(function () {

                if (ctrl.outConnectors) {
                    ctrl.outConnectors.forEach((connector) => {

                        if (connector.isCustom) {
                            lines.push(new LeaderLine(
                                document.getElementById(connector.name + '_custom-route'),
                                LeaderLine.pointAnchor(
                                    document.getElementById('target-' + connector.name + '-block'),
                                    {x: '100%', y: 11}
                                ),
                                {color: 'green', size: 2, path: 'straight'}
                            ));
                            lines.push(new LeaderLine(
                                document.getElementById(connector.name + '_pre-output'),
                                document.getElementById(connector.name + '_custom-route'),
                                {color: 'green', size: 2, path: 'straight'}
                            ));
                        } else {
                            lines.push(new LeaderLine(
                                document.getElementById(connector.name + '_pre-output'),
                                LeaderLine.pointAnchor(
                                    document.getElementById('target-' + connector.name + '-block'),
                                    {x: '100%', y: 11}
                                ),
                                {color: 'green', size: 2, path: 'straight'}
                            ));
                        }

                        lines.push(new LeaderLine(
                            document.getElementById('out-flow_pre-route'),
                            document.getElementById('out-flow_connector-selector'),
                            {color: 'green', size: 2, path: 'straight'}
                        ));

                        lines.push(new LeaderLine(
                            LeaderLine.pointAnchor(
                                document.getElementById('out-flow_connector-selector'),
                                {x: 0, y: '50%'}
                            ),
                            document.getElementById(connector.name + '_pre-output'),
                            {color: 'green', size: 2, path: 'grid', startSocketGravity: [-10, 0]}
                        ));

                        lines.push(new LeaderLine(
                            LeaderLine.pointAnchor(
                                document.getElementById('target-' + connector.name + '-block'),
                                {x: '100%', y: 43}
                            ),
                            document.getElementById(connector.name + '_postprocess'),
                            {color: 'blue', size: 2, path: 'straight'}
                        ));

                        lines.push(new LeaderLine(
                            document.getElementById(connector.name + '_postprocess'),
                            document.getElementById('out-flow_postprocess'),
                            {color: 'blue', size: 2, path: 'grid', startSocketGravity: [10, 0]}
                        ));
                    })

                    lines.push(new LeaderLine(
                        LeaderLine.pointAnchor(
                            document.getElementById('integrations-out-block'),
                            {x: 0, y: 11}
                        ),
                        document.getElementById('out-flow_pre-route'),
                        {color: 'green', size: 2, path: 'straight'}
                    ));

                    lines.push(new LeaderLine(
                        document.getElementById('out-flow_postprocess'),
                        LeaderLine.pointAnchor(
                            document.getElementById('integrations-out-block'),
                            {x: 0, y: 43}
                        ),
                        {color: 'blue', size: 2, path: 'straight'}
                    ));
                }

            }, 50);
        }

        // reposition of lines while container size is changed without changing window size
        let resizeObserver = new ResizeObserver(entries => {
            for (let entry of entries) {
                if (entry.target.handleResize) {
                    entry.target.handleResize(entry);
                }
            }
        });

        setTimeout(function () {
            document.querySelector('#leader-lines-container').handleResize = entry => {
                lines.forEach(line => line.position());
            }

            resizeObserver.observe(document.querySelector('#leader-lines-container'));
        }, 10);

        // reposition of lines on scroll event
        setTimeout(function () {
            let leaderLinesContainerElement = document.getElementById("leader-lines-container");

            leaderLinesContainerElement.onscroll = (event) => {
                lines.forEach(line => line.position());
            };
        }, 10);

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

        $scope.$on('$destroy', function () {
            lines.forEach(line => line.remove());
            resizeObserver.disconnect();
            $cookies.remove('profile-properties-group');
        });

        ctrl.editProfileProperties = function (groupName) {
            $cookies.putObject('profile-properties-group', groupName);
            let selectedMbeanName = workspace.getSelectedMBeanName();
            let profile = createItem(selectedMbeanName);

            ctrl.editProperties(profile, Entaxy.RUNTIME_TYPE.PROFILE, 'Profile');
        }

        ctrl.editDefaultRouteProperties = function () {
            let defaultRouteMbeanName = defaultRouteMbean.objectName;
            let defaultRoute = createItem(defaultRouteMbeanName);

            ctrl.editProperties(defaultRoute, Entaxy.RUNTIME_TYPE.DEFAULT_ROUTE, 'Default Route');
        }

        function createItem(mbeanName) {
            let attributes = entaxyAttributesCacheService.getAttributes(mbeanName);
            return {
                name: attributes.Name,
                mbeanName: mbeanName
            };
        }

        ctrl.editProperties = function (item, runtimeType, itemType) {
            entaxyService.readObjectClusterState(item.mbeanName).then(objectClusterState => {
                let isNonClustered = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED;
                if (isNonClustered) {
                    Entaxy.notificationInfo(Entaxy.NON_CLUSTERED_MESSAGE.EDITING);
                }

                let mode = isNonClustered ? Entaxy.MODAL_MODES.VIEW : Entaxy.MODAL_MODES.EDIT;
                item.isLocal = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.LOCAL;
                let args = entaxyProfileDiagramService.hasChanges(item.mbeanName) ?
                    entaxyProfileDiagramService.getArgs(item.mbeanName) : undefined;
                let properties = args ? args.fields.filter(field => field.name !== 'routes') : undefined;

                entaxyService.openEditItemModalAndProcessResults(item, itemType, runtimeType, mode,
                    properties, ctrl.update);

            }).catch(e => Entaxy.notificationError(e));
        }

        ctrl.editDefaultRouteCustomizationPoint = function (event) {
            event.stopPropagation();

            if (defaultRouteMbean) {
                ctrl.editCustomizationPoint(defaultRouteMbean.objectName, 'routeContent');
            } else {
                Entaxy.notificationError('Default route is not found.');
            }
        }

        ctrl.editCustomizationPoint = function (mbeanName, propertyName, connector) {
            if (entaxyProfileDiagramService.hasChanges(mbeanName)) {
                let changes = entaxyProfileDiagramService.getChanges(mbeanName);

                processPropertyAndOpenXmlEditor(changes, propertyName, mbeanName, true);
            } else {
                entaxyService.readConfiguration(mbeanName)
                .then(objectInfo => {
                    let args = entaxyService.getArgumentsFromConfig(objectInfo);
                    let changes = entaxyProfileDiagramService.createChangesConfig(mbeanName, objectInfo.objectId,
                        args, objectInfo.configurableOnly, connector);

                    processPropertyAndOpenXmlEditor(changes, propertyName, mbeanName);

                }).catch(error => {
                    Entaxy.notificationError(error);
                    Entaxy.log.error(error);
                });
            }
        }

        function processPropertyAndOpenXmlEditor(changes, propertyName, mbeanName, isRoutesFieldResolved) {
            let args = changes.args;
            let property = args.fields.find(property => property.name === propertyName);

            if (property.value) {
                if (isRoutesFieldResolved) {
                    resolveConfirmationAndOpenXmlEditor(changes, property, propertyName, mbeanName);
                } else {
                    let selectedMbean = workspace.getSelectedMBean();
                    let mbean = selectedMbean.objectName === mbeanName ?
                        selectedMbean : selectedMbean.findDescendant(child => child.objectName === mbeanName);

                    entaxyService.resolveRoutesFieldValueAndAddNew(args, mbean)
                    .then(() => {
                        resolveConfirmationAndOpenXmlEditor(changes, property, propertyName, mbeanName);
                    });
                }
            } else {
                Entaxy.notificationError('Content is not found');
            }
        }

        function resolveConfirmationAndOpenXmlEditor(changes, property, propertyName, mbeanName) {
            entaxyService.readObjectClusterState(mbeanName).then(objectClusterState => {
                let isNonClustered = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED;
                if (isNonClustered) {
                    Entaxy.notificationInfo(Entaxy.NON_CLUSTERED_MESSAGE.EDITING);
                }

                if (changes.configurableOnly || isNonClustered) {
                    getXmlAndOpenEditor(property, mbeanName, true, changes);
                } else {
                    let args = changes.args;
                    let factoryMbeanName = args.factoryId.mbeanName;
                    entaxyService.getFields(factoryMbeanName).then(response => {
                        let fields = JSON.parse(response);
                        let currentField = fields.find(field => field.name === propertyName);
                        const UI = '@UI';
                        let managedByFieldName = currentField[UI] ? currentField[UI].managedBy : undefined;
                        if (managedByFieldName) {
                            let managingFieldProperty = args.fields
                                .find(field => field.name === managedByFieldName);
                            if (managingFieldProperty.value) {
                                getXmlAndOpenEditor(property, mbeanName, changes.configurableOnly, changes);
                            } else {
                                let managingField = fields.find(field => field.name === managedByFieldName);
                                let title = 'Confirm editing';
                                let message = managingField.displayName + ' is currently disabled. ' +
                                    'Do you want to enable it and edit the ' + currentField.displayName + '?';

                                entaxyService.openConfirmationWindow(title, message).then(() => {
                                    managingFieldProperty.value = true;
                                    getXmlAndOpenEditor(property, mbeanName, changes.configurableOnly, changes);
                                });
                            }
                        } else {
                            getXmlAndOpenEditor(property, mbeanName, changes.configurableOnly, changes);
                        }
                    });
                }
            }).catch(e => Entaxy.notificationError(e));
        }

        function getXmlAndOpenEditor(property, mbeanName, readOnly, changes) {
            entaxyService.getXmlFromConfigPropertyValue(property.value)
                .then(xml => openXmlEditor(xml, property, mbeanName, readOnly, changes));
        }

        function openXmlEditor(originXml, property, mbeanName, readOnly, changes) {

            $uibModal.open({
                component: 'entaxyXmlModal',
                resolve: {
                    xml: () => originXml,
                    mode: () => readOnly ? Entaxy.MODAL_MODES.VIEW : Entaxy.MODAL_MODES.EDIT
                },
                size: 'xl',
                backdrop: 'static',
                windowTopClass: 'modal-top-margin-override'
            })
            .result.then(xml => {
                if (xml && xml.trim().length > 0) { // fixme
                    property.value = Entaxy.stringToBase64(xml);
                    if (!entaxyProfileDiagramService.hasChanges(mbeanName)) {
                        entaxyProfileDiagramService.setChanges(mbeanName, changes);
                    }
                    if (entaxyProfileDiagramService.hasType(mbeanName, Entaxy.RUNTIME_TYPE.PROFILE)) {
                        entaxyProfileDiagramService.setProfileChanged();
                        ctrl.isProfileChanged = entaxyProfileDiagramService.isProfileChanged();
                    } else if (entaxyProfileDiagramService.hasType(mbeanName, Entaxy.RUNTIME_TYPE.DEFAULT_ROUTE)) {
                        entaxyProfileDiagramService.setDefaultRouteChanged();
                        ctrl.isDefaultRouteChanged = entaxyProfileDiagramService.isDefaultRouteChanged();
                    } else if (entaxyProfileDiagramService.hasType(mbeanName, Entaxy.RUNTIME_TYPE.CONNECTOR)) {
                        entaxyProfileDiagramService.setConnectorChanged(mbeanName, true);
                    }
                    entaxyProfileDiagramService.setDirty();
                } else {
                    Entaxy.notificationError('Value cannot be empty');
                }
            });
        }

        ctrl.saveProfile = function (event) {
            event.stopPropagation();

            ctrl.save(selectedMBean.objectName, true, true);
        }

        ctrl.saveDefaultRoute = function (event) {
            event.stopPropagation();

            ctrl.save(defaultRouteMbean.objectName, false);
        }

        ctrl.save = function (mbeanName, isConfirmationNeeded, isProfile) {
            if (entaxyPrivateObjectsCacheService.isChanged(mbeanName) && isConfirmationNeeded) {
                let title = 'Confirm Saving';
                let type = isProfile ? 'Profile' : 'Connector';
                let message = type + ' has unsaved changes of routes which will also be applied. ' +
                    'Do you want to continue?';
                entaxyService.openConfirmationWindow(title, message).then(() => save(mbeanName));
            } else {
                save(mbeanName);
            }
        }

        function save(mbeanName) {
            let args = entaxyProfileDiagramService.getArgs(mbeanName);
            entaxyService.resolveResourceRefFields(args.fields)
            .then(() => entaxyService.saveItem(args, false, ctrl.update));
        }

        ctrl.update = function (properties, objectId) {
            entaxyProfileDiagramService.resetChanges(objectId);
            ctrl.isProfileChanged = entaxyProfileDiagramService.isProfileChanged();
            ctrl.isDefaultRouteChanged = entaxyProfileDiagramService.isDefaultRouteChanged();
        }

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

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

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

    entaxyProfileDiagramController.$inject = ['$scope', 'workspace', 'jolokia', '$location', '$q',
        'entaxyService', 'entaxyProfileDiagramService', 'entaxyAttributesCacheService',
        'entaxyPrivateObjectsCacheService', '$uibModal', '$route', '$cookies'];

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