/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var App = require('app');

App.MainAdminServiceAutoStartController = Em.Controller.extend({
  name: 'mainAdminServiceAutoStartController',

  /**
   * @type {?object}
   * @default null
   */
  clusterConfigs: null,

  /**
   * @type {Array}
   */
  componentsConfigsCached: [],

  /**
   * @type {object}
   */
  componentsConfigsCachedMap: function() {
    const map = {};
    this.get('componentsConfigsCached').forEach((component) => {
      map[component.component_name] = component.recovery_enabled === 'true'
    });
    return map;
  }.property('componentsConfigsCached.@each.recovery_enabled'),

  /**
   * @type {Array}
   */
  componentsConfigsGrouped: [],

  /**
   * @type {boolean}
   */
  isLoaded: false,

  /**
   * @type {boolean}
   */
  isGeneralRecoveryEnabled: false,

  /**
   * @type {boolean}
   */
  isGeneralRecoveryEnabledCached: false,

  /**
   * @type {boolean}
   */
  saveInProgress: false,

  /**
   * @type {boolean}
   */
  isModified: function() {
    return this.get('isGeneralModified') || this.get('isComponentModified');
  }.property('isGeneralModified', 'isComponentModified'),

  /**
   * @type {boolean}
   */
  isGeneralModified: function() {
    return this.get('isGeneralRecoveryEnabled') !== this.get('isGeneralRecoveryEnabledCached')
  }.property('isGeneralRecoveryEnabled', 'isGeneralRecoveryEnabledCached'),

  /**
   * @type {boolean}
   */
  isComponentModified: function() {
    const componentsConfigsCachedMap = this.get('componentsConfigsCachedMap');

    return this.get('componentsConfigsGrouped').some((component) => {
      return component.get('recoveryEnabled') !== componentsConfigsCachedMap[component.get('componentName')];
    });
  }.property('componentsConfigsGrouped.@each.recoveryEnabled', 'componentsConfigsCachedMap'),

  parseComponentConfigs: function(componentsConfigsCached) {
    componentsConfigsCached.sortPropertyLight('service_name');
    const componentsConfigsGrouped = [];
    const servicesMap = componentsConfigsCached.mapProperty('service_name').uniq().toWickMap();
  
    componentsConfigsCached.forEach((component) => {
      componentsConfigsGrouped.push(Em.Object.create({
        serviceDisplayName: App.format.role(component.service_name, true),
        isFirst: servicesMap[component.service_name],
        componentName: component.component_name,
        displayName: App.format.role(component.component_name, false),
        recoveryEnabled: component.recovery_enabled === 'true'
      }));
      servicesMap[component.service_name] = false;
    });
    return componentsConfigsGrouped;
  },

  load: function() {
    const dfd = $.Deferred();
    const clusterConfigController = App.router.get('configurationController');
    clusterConfigController.updateConfigTags().always(() => {
      clusterConfigController.getCurrentConfigsBySites(['cluster-env']).done((data) => {
        this.set('clusterConfigs', data[0].properties);
        this.set('isGeneralRecoveryEnabled', data[0].properties.recovery_enabled === 'true');
        this.set('isGeneralRecoveryEnabledCached', this.get('isGeneralRecoveryEnabled'));
        this.loadComponentsConfigs().then(() => {
          this.set('isLoaded', true);
          dfd.resolve();
        }, () => dfd.reject());
      });
    });
    
    return dfd;
  },

  loadComponentsConfigs: function () {
    return App.ajax.send({
      name: 'components.get_category',
      sender: this,
      success: 'loadComponentsConfigsSuccess'
    });
  },

  loadComponentsConfigsSuccess: function (data) {
    const restartableComponents = data.items.mapProperty('ServiceComponentInfo').filter((component) => {
      // Hide clients, as the are not restartable, components which are not installed
      return App.StackServiceComponent.find(component.component_name).get('isRestartable') && component.total_count > 0;
    });
    this.set('componentsConfigsCached', restartableComponents);
    this.set('componentsConfigsGrouped', this.parseComponentConfigs(restartableComponents));
  },

  saveClusterConfigs: function (clusterConfigs, recoveryEnabled) {
    clusterConfigs.recovery_enabled = String(recoveryEnabled);
    return App.ajax.send({
      name: 'admin.save_configs',
      dataType:'text',
      sender: this,
      data: {
        siteName: 'cluster-env',
        properties: clusterConfigs
      }
    });
  },

  saveComponentSettingsCall: function(recoveryEnabled, components) {
    return App.ajax.send({
      name: 'components.update',
      sender: this,
      dataType:'text',
      data: {
        ServiceComponentInfo: {
          recovery_enabled: recoveryEnabled
        },
        query: 'ServiceComponentInfo/component_name.in(' + components.join(',') + ')'
      }
    });
  },

  syncStatus: function () {
    const componentsConfigsGrouped = this.get('componentsConfigsGrouped');
    this.set('isGeneralRecoveryEnabledCached', this.get('isGeneralRecoveryEnabled'));
    this.get('componentsConfigsCached').forEach((component) => {
      const actualComponent = componentsConfigsGrouped.findProperty('componentName', component.component_name);
      Ember.set(component, 'recovery_enabled', String(actualComponent.get('recoveryEnabled')));
    });
    this.propertyDidChange('componentsConfigsCached');
  },

  restoreCachedValues: function () {
    this.set('isGeneralRecoveryEnabled', this.get('isGeneralRecoveryEnabledCached'));
    this.set('componentsConfigsGrouped', this.parseComponentConfigs(this.get('componentsConfigsCached')));
  },

  filterComponentsByChange: function(components, value) {
    const map = this.get('componentsConfigsCachedMap');

    return components.filter((component) => {
      return component.get('recoveryEnabled') !== map[component.get('componentName')]
          && component.get('recoveryEnabled') === value;
    }).mapProperty('componentName');
  },

  /**
   * If some configs are changed and user navigates away or select another config-group, show this popup with propose to save changes
   * @param {object} transitionCallback - callback with action to change configs view
   * @return {App.ModalPopup}
   * @method showSavePopup
   */
  showSavePopup: function (transitionCallback) {
    var self = this;
    var title = '';
    var body = '';
    if (typeof transitionCallback === 'function') {
      title = Em.I18n.t('admin.serviceAutoStart.save.popup.transition.title');
      body = Em.I18n.t('admin.serviceAutoStart.save.popup.transition.body');
    } else {
      title = Em.I18n.t('admin.serviceAutoStart.save.popup.title');
      body = Em.I18n.t('admin.serviceAutoStart.save.popup.body');
    }
    return App.ModalPopup.show({
      header: title,
      bodyClass: Ember.View.extend({
        template: Ember.Handlebars.compile(body)
      }),
      footerClass: Em.View.extend({
        templateName: require('templates/main/service/info/save_popup_footer')
      }),
      primary: Em.I18n.t('common.save'),
      secondary: Em.I18n.t('common.cancel'),
      onSave: function () {
        let clusterConfigsCall, enabledComponentsCall, disabledComponentsCall;

        if (self.get('isGeneralModified')) {
          clusterConfigsCall = self.saveClusterConfigs(self.get('clusterConfigs'), self.get('isGeneralRecoveryEnabled'));
        }

        const enabledComponents = self.filterComponentsByChange(self.get('componentsConfigsGrouped'), true);
        const disabledComponents = self.filterComponentsByChange(self.get('componentsConfigsGrouped'), false);

        if (enabledComponents.length) {
          enabledComponentsCall = self.saveComponentSettingsCall('true', enabledComponents);
        }
        if (disabledComponents.length) {
          disabledComponentsCall = self.saveComponentSettingsCall('false', disabledComponents);
        }
        self.set('saveInProgress', true);
        $.when(clusterConfigsCall, enabledComponentsCall, disabledComponentsCall).done(function () {
          if (typeof transitionCallback === 'function') {
            transitionCallback();
          }
          self.syncStatus();
        }).always(function() {
          self.set('saveInProgress', false);
        });
        this.hide();
      },
      onDiscard: function () {
        self.restoreCachedValues();
        if (typeof transitionCallback === 'function') {
          transitionCallback();
        }
        this.hide();
      },
      onCancel: function () {
        this.hide();
      }
    });
  }
});
