/**
 * 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.MainServiceInfoSummaryController = Em.Controller.extend(App.WidgetSectionMixin, {
  name: 'mainServiceInfoSummaryController',

  selectedFlumeAgent: null,

  /**
   * Indicates whether Ranger plugins status update polling is active
   * @type {boolean}
   */
  isRangerUpdateWorking: false,

  /**
   * Indicates whether array with initial Ranger plugins data is set
   * @type {boolean}
   */
  isRangerPluginsArraySet: false,

  /**
   * Indicates whether previous AJAX request for Ranger plugins config properties has failed
   * @type {boolean}
   */
  isPreviousRangerConfigsCallFailed: false,

  layoutNameSuffix: "_dashboard",

  sectionNameSuffix: "_SUMMARY",

  /**
   * Ranger plugins data
   * @type {array}
   */
  rangerPlugins: [
    {
      serviceName: 'HDFS',
      type: 'ranger-hdfs-plugin-properties',
      propertyName: 'ranger-hdfs-plugin-enabled',
      valueForEnable: 'Yes'
    },
    {
      serviceName: 'HBASE',
      type: 'ranger-hbase-plugin-properties',
      propertyName: 'ranger-hbase-plugin-enabled',
      valueForEnable: 'Yes'
    },
    {
      serviceName: 'HIVE',
      type: 'hive-env',
      propertyName: 'hive_security_authorization',
      valueForEnable: 'Ranger'
    },
    {
      serviceName: 'KNOX',
      type: 'ranger-knox-plugin-properties',
      propertyName: 'ranger-knox-plugin-enabled',
      valueForEnable: 'Yes'
    },
    {
      serviceName: 'STORM',
      type: 'ranger-storm-plugin-properties',
      propertyName: 'ranger-storm-plugin-enabled',
      valueForEnable: 'Yes'
    },
    {
      serviceName: 'YARN',
      type: 'ranger-yarn-plugin-properties',
      propertyName: 'ranger-yarn-plugin-enabled',
      valueForEnable: 'Yes'
    },
    {
      serviceName: 'KAFKA',
      type: 'ranger-kafka-plugin-properties',
      propertyName: 'ranger-kafka-plugin-enabled',
      valueForEnable: 'Yes'
    }
  ],

  /**
   * @type {boolean}
   */
  showTimeRangeControl: function () {
    return !this.get('isServiceWithEnhancedWidgets') || this.get('widgets').filterProperty('widgetType', 'GRAPH').length > 0;
  }.property('isServiceWithEnhancedWidgets', 'widgets.length'),

  /**
   * Set initial Ranger plugins data
   * @method setRangerPlugins
   */
  setRangerPlugins: function () {
    if (App.get('router.clusterController.isLoaded') && !this.get('isRangerPluginsArraySet')) {
      this.setProperties({
        rangerPlugins: this.get('rangerPlugins').map(function (item) {
          var stackService = App.StackService.find().findProperty('serviceName', item.serviceName);
          var displayName = (stackService) ? stackService.get('displayName') : item.serviceName;
          return $.extend(item, {
            pluginTitle: Em.I18n.t('services.service.summary.ranger.plugin.title').format(displayName),
            isDisplayed: App.Service.find().someProperty('serviceName', item.serviceName) &&
              stackService.get('configTypes').hasOwnProperty(item.type),
            status: Em.I18n.t('services.service.summary.ranger.plugin.loadingStatus')
          });
        }),
        isRangerPluginsArraySet: true
      });
    }
  }.observes('App.router.clusterController.isLoaded'),

  /**
   * Get latest config tags
   * @method updateRangerPluginsStatus
   * @param callback
   */
  updateRangerPluginsStatus: function (callback) {
    App.ajax.send({
      name: 'config.tags',
      sender: this,
      success: 'getRangerPluginsStatus',
      callback: callback
    });
  },

  /**
   * Get latest Ranger plugins config properties
   * @method getRangerPluginsStatus
   * @param data
   */
  getRangerPluginsStatus: function (data) {
    var urlParams = [];
    this.get('rangerPlugins').forEach(function (item) {
      if (App.Service.find().someProperty('serviceName', item.serviceName) && data.Clusters.desired_configs.hasOwnProperty(item.type)) {
        var currentTag = data.Clusters.desired_configs[item.type].tag;
        var isTagChanged = item.tag != currentTag;
        Em.set(item, 'isDisplayed', true);
        //Request for properties should be sent either if configs have changed or if previous Ranger plugins config properties has failed
        if (isTagChanged || this.get('isPreviousRangerConfigsCallFailed')) {
          Em.set(item, 'tag', currentTag);
          urlParams.push('(type=' + item.type + '&tag=' + currentTag + ')');
        }
      } else {
        Em.set(item, 'isDisplayed', false);
      }
    }, this);
    if (urlParams.length) {
      App.ajax.send({
        name: 'reassign.load_configs',
        sender: this,
        data: {
          urlParams: urlParams.join('|')
        },
        success: 'getRangerPluginsStatusSuccess',
        error: 'getRangerPluginsStatusError'
      });
    }
  },

  /**
   * Set Ranger plugins statuses
   * @method getRangerPluginsStatusSuccess
   * @param data
   */
  getRangerPluginsStatusSuccess: function (data) {
    this.set('isPreviousRangerConfigsCallFailed', false);
    data.items.forEach(function (item) {
      var serviceName = this.get('rangerPlugins').findProperty('type', item.type).serviceName;
      var propertyName = this.get('rangerPlugins').findProperty('type', item.type).propertyName;
      var propertyValue = this.get('rangerPlugins').findProperty('type', item.type).valueForEnable;
      var statusString;

      if (item.properties[propertyName]) {
        statusString = item.properties[propertyName] == propertyValue ? 'alerts.table.state.enabled' : 'alerts.table.state.disabled';
      }
      else {
        statusString = 'common.unknown';
      }
      Em.set(this.get('rangerPlugins').findProperty('serviceName', serviceName), 'status', Em.I18n.t(statusString));
    }, this);
  },

  /**
   * Method executed if Ranger plugins config properties request has failed
   * @method getRangerPluginsStatusError
   */
  getRangerPluginsStatusError: function () {
    this.set('isPreviousRangerConfigsCallFailed', true);
  },

  /**
   * Send start command for selected Flume Agent
   * @method startFlumeAgent
   */
  startFlumeAgent: function () {
    var selectedFlumeAgent = arguments[0].context;
    if (selectedFlumeAgent && selectedFlumeAgent.get('status') === 'NOT_RUNNING') {
      var self = this;
      App.showConfirmationPopup(function () {
        var state = 'STARTED';
        var context = Em.I18n.t('services.service.summary.flume.start.context').format(selectedFlumeAgent.get('name'));
        self.sendFlumeAgentCommandToServer(state, context, selectedFlumeAgent);
      });
    }
  },

  /**
   * Send stop command for selected Flume Agent
   * @method stopFlumeAgent
   */
  stopFlumeAgent: function () {
    var selectedFlumeAgent = arguments[0].context;
    if (selectedFlumeAgent && selectedFlumeAgent.get('status') === 'RUNNING') {
      var self = this;
      App.showConfirmationPopup(function () {
        var state = 'INSTALLED';
        var context = Em.I18n.t('services.service.summary.flume.stop.context').format(selectedFlumeAgent.get('name'));
        self.sendFlumeAgentCommandToServer(state, context, selectedFlumeAgent);
      });
    }
  },

  /**
   * Send command for Flume Agent to server
   * @param {string} state
   * @param {string} context
   * @param {Object} agent
   * @method sendFlumeAgentCommandToServer
   */
  sendFlumeAgentCommandToServer: function (state, context, agent) {
    App.ajax.send({
      name: 'service.flume.agent.command',
      sender: this,
      data: {
        state: state,
        context: context,
        agentName: agent.get('name'),
        host: agent.get('hostName')
      },
      success: 'commandSuccessCallback'
    });
  },

  /**
   * Callback, that shows Background operations popup if request was successful
   */
  commandSuccessCallback: function () {
    console.log('Send request for refresh configs successfully');
    // load data (if we need to show this background operations popup) from persist
    App.router.get('applicationController').dataLoading().done(function (showPopup) {
      if (showPopup) {
        App.router.get('backgroundOperationsController').showPopup();
      }
    });
  },

  gotoConfigs: function () {
    App.router.get('mainServiceItemController').set('routeToConfigs', true);
    App.router.transitionTo('main.services.service.configs', this.get('content'));
    App.router.get('mainServiceItemController').set('routeToConfigs', false);
  },

  showServiceAlertsPopup: function (event) {
    var service = event.context;
    return App.ModalPopup.show({
      header: Em.I18n.t('services.service.summary.alerts.popup.header').format(service.get('displayName')),
      autoHeight: false,
      classNames: ['forty-percent-width-modal'],
      bodyClass: Em.View.extend({
        templateName: require('templates/main/service/info/service_alert_popup'),
        classNames: ['service-alerts'],
        controllerBinding: 'App.router.mainAlertDefinitionsController',
        didInsertElement: function () {
          Em.run.next(this, function () {
            App.tooltip($(".timeago"));
          });
        },
        alerts: function () {
          var serviceDefinitions = this.get('controller.content').filterProperty('service', service);
          // definitions should be sorted in order: critical, warning, ok, unknown, other
          var criticalDefinitions = [], warningDefinitions = [], okDefinitions = [], unknownDefinitions = [];
          serviceDefinitions.forEach(function (definition) {
            if (definition.get('isCritical')) {
              criticalDefinitions.push(definition);
              serviceDefinitions = serviceDefinitions.without(definition);
            } else if (definition.get('isWarning')) {
              warningDefinitions.push(definition);
              serviceDefinitions = serviceDefinitions.without(definition);
            } else if (definition.get('isOK')) {
              okDefinitions.push(definition);
              serviceDefinitions = serviceDefinitions.without(definition);
            } else if (definition.get('isUnknown')) {
              unknownDefinitions.push(definition);
              serviceDefinitions = serviceDefinitions.without(definition);
            }
          });
          serviceDefinitions = criticalDefinitions.concat(warningDefinitions, okDefinitions, unknownDefinitions, serviceDefinitions);
          return serviceDefinitions;
        }.property('controller.content'),
        gotoAlertDetails: function (event) {
          if (event && event.context) {
            this.get('parentView').hide();
            App.router.transitionTo('main.alerts.alertDetails', event.context);
          }
        },
        closePopup: function () {
          this.get('parentView').hide();
        }
      }),
      isHideBodyScroll: false,
      primary: Em.I18n.t('common.close'),
      secondary: null
    });
  },


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

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

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


  /**
   * load widget layouts across all users in CLUSTER scope
   * @returns {$.ajax}
   */
  loadWidgetLayouts: function () {
    this.set('isWidgetLayoutsLoaded', false);
    return App.ajax.send({
      name: 'widgets.layouts.get',
      sender: this,
      data: {
        sectionName: this.get('sectionName')
      },
      success: 'loadWidgetLayoutsSuccessCallback'
    });
  },

  loadWidgetLayoutsSuccessCallback: function (data) {
    App.widgetLayoutMapper.map(data);
    this.set('isWidgetLayoutsLoaded', true);
  },


  /**
   * load all shared widgets to show on widget browser
   * @returns {$.ajax}
   */
  loadAllSharedWidgets: function () {
    this.set('isAllSharedWidgetsLoaded', false);
    return App.ajax.send({
      name: 'widgets.all.shared.get',
      sender: this,
      success: 'loadAllSharedWidgetsSuccessCallback'
    });
  },

  /**
   * success callback of <code>loadAllSharedWidgets</code>
   * @param {object|null} data
   */
  loadAllSharedWidgetsSuccessCallback: function (data) {
    var widgetIds = this.get('widgets').mapProperty('id');
    if (data.items[0] && data.items.length) {
      this.set("allSharedWidgets",
        data.items.filter(function (widget) {
          return widget.WidgetInfo.widget_type != "HEATMAP";
        }).map(function (widget) {
          var widgetType = widget.WidgetInfo.widget_type;
          var widgetName = widget.WidgetInfo.widget_name;
          var widgetId =  widget.WidgetInfo.id;
          return Em.Object.create({
            id: widgetId,
            widgetName: widgetName,
            description: widget.WidgetInfo.description,
            widgetType: widgetType,
            iconPath: "/img/widget-" + widgetType.toLowerCase() + ".png",
            serviceName: JSON.parse(widget.WidgetInfo.metrics).mapProperty('service_name').uniq().join('-'),
            added: widgetIds.contains(widgetId),
            isShared: widget.WidgetInfo.scope == "CLUSTER"
          });
        })
      );
    }
    this.set('isAllSharedWidgetsLoaded', true);
  },

  allSharedWidgets: [],
  mineWidgets: [],

  /**
   * load all mine widgets of current user to show on widget browser
   * @returns {$.ajax}
   */
  loadMineWidgets: function () {
    this.set('isMineWidgetsLoaded', false);
    return App.ajax.send({
      name: 'widgets.all.mine.get',
      sender: this,
      data: {
        loginName: App.router.get('loginName')
      },
      success: 'loadMineWidgetsSuccessCallback'
    });
  },

  /**
   * success callback of <code>loadMineWidgets</code>
   * @param {object|null} data
   */
  loadMineWidgetsSuccessCallback: function (data) {
    var widgetIds = this.get('widgets').mapProperty('id');
    if (data.items[0] && data.items.length) {
      this.set("mineWidgets",
        data.items.filter(function (widget) {
          return widget.WidgetInfo.widget_type != "HEATMAP";
        }).map(function (widget) {
          var widgetType = widget.WidgetInfo.widget_type;
          var widgetName = widget.WidgetInfo.widget_name;
          var widgetId =  widget.WidgetInfo.id;
          return Em.Object.create({
            id: widget.WidgetInfo.id,
            widgetName: widgetName,
            description: widget.WidgetInfo.description,
            widgetType: widgetType,
            iconPath: "/img/widget-" + widgetType.toLowerCase() + ".png",
            serviceName: JSON.parse(widget.WidgetInfo.metrics).mapProperty('service_name').uniq().join('-'),
            added: widgetIds.contains(widgetId),
            isShared: widget.WidgetInfo.scope == "CLUSTER"
          });
        })
      );
    } else {
      this.set("mineWidgets", []);
    }
    this.set('isMineWidgetsLoaded', true);
  },

  /**
   * add widgets, on click handler for "Add"
   */
  addWidget: function (event) {
    var widgetToAdd = event.context;
    var activeLayout = this.get('activeWidgetLayout');
    var widgetIds = activeLayout.get('widgets').map(function(widget) {
      return {
        "id": widget.get("id")
      }
    });
    widgetIds.pushObject({
      "id": widgetToAdd.id
    });
    var data = {
      "WidgetLayoutInfo": {
        "display_name": activeLayout.get("displayName"),
        "id": activeLayout.get("id"),
        "layout_name": activeLayout.get("layoutName"),
        "scope": activeLayout.get("scope"),
        "section_name": activeLayout.get("sectionName"),
        "widgets": widgetIds
      }
    };

    widgetToAdd.set('added', !widgetToAdd.added);
    return App.ajax.send({
      name: 'widget.layout.edit',
      sender: this,
      data: {
        layoutId: activeLayout.get("id"),
        data: data
      },
      success: 'updateActiveLayout'
    });
  },

  /**
   * hide widgets, on click handler for "Added"
   */
  hideWidget: function (event) {
    var widgetToHide = event.context;
    var activeLayout = this.get('activeWidgetLayout');
    var widgetIds = activeLayout.get('widgets').map(function (widget) {
      return {
        "id": widget.get("id")
      }
    });
    var data = {
      "WidgetLayoutInfo": {
        "display_name": activeLayout.get("displayName"),
        "id": activeLayout.get("id"),
        "layout_name": activeLayout.get("layoutName"),
        "scope": activeLayout.get("scope"),
        "section_name": activeLayout.get("sectionName"),
        "widgets": widgetIds.filter(function (widget) {
          return widget.id !== widgetToHide.id;
        })
      }
    };

    widgetToHide.set('added', !widgetToHide.added);
    return App.ajax.send({
      name: 'widget.layout.edit',
      sender: this,
      data: {
        layoutId: activeLayout.get("id"),
        data: data
      },
      success: 'hideWidgetSuccessCallback'
    });

  },

  /**
   * @param {object|null} data
   * @param {object} opt
   * @param {object} params
   */
  hideWidgetSuccessCallback: function (data, opt, params) {
    params.data.WidgetLayoutInfo.widgets = params.data.WidgetLayoutInfo.widgets.map(function (widget) {
      return {
        WidgetInfo: {
          id: widget.id
        }
      }
    });
    App.widgetLayoutMapper.map({items: [params.data]});
    this.propertyDidChange('widgets');
  },

  /**
   * update current active widget layout
   */
  updateActiveLayout: function () {
    this.getActiveWidgetLayout();
  },

  /**
   * delete widgets, on click handler for "Delete"
   */
  deleteWidget: function (event) {
    var widget = event.context;
    var self = this;
    var confirmMsg =  widget.get('isShared') ? Em.I18n.t('dashboard.widgets.browser.action.delete.shared.bodyMsg').format(widget.widgetName) :  Em.I18n.t('dashboard.widgets.browser.action.delete.mine.bodyMsg').format(widget.widgetName);
    var bodyMessage = Em.Object.create({
      confirmMsg: confirmMsg,
      confirmButton: Em.I18n.t('dashboard.widgets.browser.action.delete.btnMsg')
    });
    return App.showConfirmationFeedBackPopup(function (query) {
      return App.ajax.send({
        name: 'widget.action.delete',
        sender: self,
        data: {
          id: widget.id
        },
        success: 'updateWidgetBrowser'
      });

    }, bodyMessage);
  },

  /**
   * update widget browser content after deleted some widget
   */
  updateWidgetBrowser: function () {
    this.loadAllSharedWidgets();
    this.loadMineWidgets();
  },

  /**
   * Share widgets, on click handler for "Share"
   */
  shareWidget: function (event) {
    var widget = event.context;
    var self = this;
    var bodyMessage = Em.Object.create({
      confirmMsg: Em.I18n.t('dashboard.widgets.browser.action.share.confirmation'),
      confirmButton: Em.I18n.t('dashboard.widgets.browser.action.share')
    });
    return App.showConfirmationFeedBackPopup(function (query) {
      return App.ajax.send({
        name: 'widgets.wizard.edit',
        sender: self,
        data: {
          data: {
            "WidgetInfo": {
              "widget_name": widget.get("widgetName"),
              "scope": "CLUSTER"
            }
          },
          widgetId: widget.get("id")
        },
        success: 'updateWidgetBrowser'
      });
    }, bodyMessage);
  },

  /**
   * create widget
   */
  createWidget: function () {
    App.router.send('createServiceWidget', Em.Object.create({
      layout: this.get('activeWidgetLayout'),
      serviceName: this.get('content.serviceName')
    }));
  },

  /**
   * edit widget
   * @param {App.Widget} content
   */
  editWidget: function (content) {
    content.set('serviceName', this.get('content.serviceName'));
    App.router.send('editServiceWidget', content);
  },

  /**
   * launch Widgets Browser popup
   * @method showPopup
   * @return {App.ModalPopup}
   */
  goToWidgetsBrowser: function () {
    var self = this;

    return App.ModalPopup.show({
      header: function () {
        return Em.I18n.t('dashboard.widgets.browser.header');
      }.property(''),

      classNames: ['sixty-percent-width-modal', 'widgets-browser-popup'],
      onPrimary: function () {
        this.hide();
        self.set('isAllSharedWidgetsLoaded', false);
        self.set('allSharedWidgets', []);
        self.set('isMineWidgetsLoaded', false);
        self.set('mineWidgets', []);
      },
      autoHeight: false,
      isHideBodyScroll: false,
      footerClass: Ember.View.extend({
        templateName: require('templates/common/modal_popups/widget_browser_footer'),
        isShowMineOnly: false,
        onPrimary: function() {
          this.get('parentView').onPrimary();
        }
      }),
      isShowMineOnly: false,
      bodyClass: Ember.View.extend({
        templateName: require('templates/common/modal_popups/widget_browser_popup'),
        controller: self,
        willInsertElement: function () {
          this.get('controller').loadAllSharedWidgets();
          this.get('controller').loadMineWidgets();
        },

        isLoaded: function () {
          return !!(this.get('controller.isAllSharedWidgetsLoaded') && this.get('controller.isMineWidgetsLoaded'));
        }.property('controller.isAllSharedWidgetsLoaded', 'controller.isMineWidgetsLoaded'),

        isWidgetEmptyList: function () {
          return !this.get('filteredContent.length');
        }.property('filteredContent.length'),

        activeService: '',
        activeStatus: '',

        content: function () {
          if (this.get('parentView.isShowMineOnly')) {
            return this.get('controller.mineWidgets');
          } else {
            // merge my widgets and all shared widgets, no duplicated is allowed
            var content = [];
            var widgetMap = {};
            var allWidgets = this.get('controller.allSharedWidgets').concat(this.get('controller.mineWidgets'));
            allWidgets.forEach(function(widget) {
              if (!widgetMap[widget.get("id")]) {
                content.pushObject(widget);
                widgetMap[widget.get("id")] = true;
              }
            });
            return content;
          }
        }.property('controller.allSharedWidgets.length', 'controller.isAllSharedWidgetsLoaded',
          'controller.mineWidgets.length', 'controller.isMineWidgetsLoaded', 'parentView.isShowMineOnly'),

        /**
         * displaying content filtered by service name and status.
         */
        filteredContent: function () {
          var activeService = this.get('activeService') ? this.get('activeService') : this.get('controller.content.serviceName');
          var result = [];
          this.get('content').forEach(function (widget) {
            if (widget.get('serviceName').indexOf(activeService) >= 0) {
              result.pushObject(widget);
            }
          });
          return result;
        }.property('content', 'activeService', 'activeStatus'),

        /**
         * service name filter
         */
        services: function () {
          var view = this;
          var services = App.Service.find().filter(function(item){
            var stackService =  App.StackService.find().findProperty('serviceName', item.get('serviceName'));
            return stackService.get('isServiceWithWidgets');
          });
          return services.map(function (service) {
            return Em.Object.create({
              value: service.get('serviceName'),
              label: service.get('displayName'),
              isActive: function () {
                var activeService = view.get('activeService') ? view.get('activeService') : view.get('controller.content.serviceName');
                return this.get('value') == activeService;
              }.property('value', 'view.activeService')
            })
          });
        }.property('activeService'),

        filterByService: function (event) {
          this.set('activeService', event.context);
        },

        createWidget: function () {
          this.get('parentView').onPrimary();
          this.get('controller').createWidget();
        },

        ensureTooltip: function () {
          Em.run.later(this, function () {
            App.tooltip($("[rel='shared-icon-tooltip']"));
          }, 1000);
        }.observes('activeService', 'parentView.isShowMineOnly'),

        didInsertElement: function () {
          this.ensureTooltip();
        }
      })
    });
  }

});