///////////////////////////////////////////////////////////////////////////
// Copyright © Esri. All Rights Reserved.
//
// Licensed 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.
///////////////////////////////////////////////////////////////////////////

define([
  'dojo/_base/declare',
  'dojo/_base/array',
  'dojo/_base/lang',
  'dojo/Deferred',
  'dojo/promise/all',
  'jimu/WidgetManager',
  'jimu/portalUrlUtils',
  'esri/lang',
  './NlsStrings'
], function(declare, array, lang, Deferred, all, WidgetManager, portalUrlUtils, esriLang,
  NlsStrings) {
  var clazz = declare([], {

    _candidateMenuItems: null,
    //_deniedItems: null,
    _displayItems: null,
    _layerInfo: null,
    _layerType: null,
    _appConfig: null,

    constructor: function(layerInfo, displayItemInfos, layerType, layerListWidget) {
      this.nls = NlsStrings.value;
      this._layerInfo = layerInfo;
      this._layerType = layerType;
      this.layerListWidget = layerListWidget;
      this._initCandidateMenuItems();
      this._initDisplayItems(displayItemInfos);
    },

    _getATagLabel: function() {
      var url;
      var label;
      var layerUrl = this._layerInfo.getUrl();
      var basicItemInfo = this._layerInfo.isItemLayer();
      if (basicItemInfo) {
        url = this._getItemDetailsPageUrl(basicItemInfo) || layerUrl;
        label = this.nls.itemShowItemDetails;
      } else if (layerUrl &&
        (this._layerType === "CSVLayer" || this._layerType === "KMLLayer")) {
        url = layerUrl;
        label = this.nls.itemDownload;
      } else if (layerUrl && this._layerType === "WMSLayer") {
        url = layerUrl + (layerUrl.indexOf("?") > -1 ? "&" : "?") + "SERVICE=WMS&REQUEST=GetCapabilities";
        label = this.nls.itemDesc;
      } else if (layerUrl && this._layerType === "WFSLayer") {
        url = layerUrl + (layerUrl.indexOf("?") > -1 ? "&" : "?") + "SERVICE=WFS&REQUEST=GetCapabilities";
        label = this.nls.itemDesc;
      } else if (layerUrl) {
        url = layerUrl;
        label = this.nls.itemDesc;
      } else {
        url = '';
        label = this.nls.itemDesc;
      }
      this._ATagLabelUrl = url;
      return '<a class="menu-item-description" target="_blank" href="' +
        url + '">' + label + '</a>';
    },

    _getItemDetailsPageUrl: function(basicItemInfo) {
      var itemUrl = "";
      itemUrl = portalUrlUtils.getItemDetailsPageUrl(basicItemInfo.portalUrl, basicItemInfo.itemId);
      return itemUrl;
    },

    _initCandidateMenuItems: function() {
      //descriptionTitle: NlsStrings.value.itemDesc,
      // var layerObjectUrl = (this._layerInfo.layerObject && this._layerInfo.layerObject.url) ?
      //                       this._layerInfo.layerObject.url :
      //                       '';
      this._candidateMenuItems = [{
        key: 'separator',
        label: ''
      }, {
        key: 'empty',
        label: this.nls.empty
      }, {
        key: 'zoomto',
        label: this.nls.itemZoomTo
      }, {
        key: 'transparency',
        label: this.nls.itemTransparency
      },  {
        key: 'setVisibilityRange',
        label: this.nls.itemSetVisibilityRange
      }, {
        key: 'moveup',
        label: this.nls.itemMoveUp
      }, {
        key: 'movedown',
        label: this.nls.itemMoveDown
      }, {
        key: 'table',
        label: this.nls.itemToAttributeTable
      }, {
        key: 'controlPopup',
        label: this.nls.removePopup
      }, {
        key: 'controlLabels',
        label: this.nls.showLabels
      }, {
        key: 'url',
        label: this._getATagLabel()
      }];
    },

    _initDisplayItems: function(displayItemInfos) {
      this._displayItems = [];
      // according to candidate itmes to init displayItems
      array.forEach(displayItemInfos, function(itemInfo) {
        array.forEach(this._candidateMenuItems, function(item) {
          if (itemInfo.key === item.key) {
            this._displayItems.push(lang.clone(item));
            if (itemInfo.onClick) {
              this._displayItem.onClick = itemInfo.onClick;
            }
          }
        }, this);
      }, this);
    },

    _getSupportTableInfoForAllSublayers: function(layerInfo) {
      var defs = [];
      layerInfo.traversal(function(subLayerInfo) {
        var def = new Deferred();
        subLayerInfo.getSupportTableInfo().then(function(supportedInfo) {
          supportedInfo.layerInfo = subLayerInfo;
          def.resolve(supportedInfo);
        });
        defs.push(def);
      });
      return all(defs);
    },

    _isSupportedByAT: function(attributeTableWidget, allSupportedInfo) {
      /*jshint unused: false*/
      var isSupported = array.some(allSupportedInfo, function(supportTableInfo) {
        if (!supportTableInfo.isSupportedLayer ||
            !supportTableInfo.isSupportQuery ||
            supportTableInfo.otherReasonCanNotSupport) {
          return false;
        } else {
          return true;
        }
      });
      return isSupported;
    },

    /*
    _isPopupSupported: function() {
      var def = new Deferred();
      var defs = [];
      this._layerInfo.traversal(function(layerInfo) {
        if(layerInfo.isLeaf()) {
          defs.push(layerInfo.loadInfoTemplate());
        }
      });

      all(defs).then(function(infoTemplates) {
        array.some(infoTemplates, function(infoTemplates) {
          if(infoTemplates) {
            def.resolve(true);
            return true;
          } else {
            def.resolve(false);
            return false;
          }
        });
      });
      return def;
    },
    */

    getDeniedItems: function() {
      // summary:
      //    the items that will be denied.
      // description:
      //    return Object = [{
      //   key: String, popupMenuInfo key,
      //   denyType: String, "disable" or "hidden"
      // }]
      var defRet = new Deferred();
      var dynamicDeniedItems = [];

      if (this.layerListWidget.layerListView.isFirstDisplayedLayerInfo(this._layerInfo)) {
        dynamicDeniedItems.push({
          'key': 'moveup',
          'denyType': 'disable'
        });
      }
      if (this.layerListWidget.layerListView.isLastDisplayedLayerInfo(this._layerInfo)) {
        dynamicDeniedItems.push({
          'key': 'movedown',
          'denyType': 'disable'
        });
      }

      if (!this._ATagLabelUrl) {
        dynamicDeniedItems.push({
          'key': 'url',
          'denyType': 'disable'
        });
      }

      // deny controlLabels
      if (!this._layerInfo.canShowLabel()) {
        dynamicDeniedItems.push({
          'key': 'controlLabels',
          'denyType': 'hidden'
        });
      }

      // deny setVisibilityRange
      if(this._layerInfo.originOperLayer.featureCollection) {
        dynamicDeniedItems.push({
          'key': 'setVisibilityRange',
          'denyType': 'hidden'
        });
      } else if(!this._layerInfo.isRootLayer() &&
          this._layerInfo.getRootLayerInfo().layerObject.declaredClass === "esri.layers.ArcGISTiledMapServiceLayer") {
        dynamicDeniedItems.push({
          'key': 'setVisibilityRange',
          'denyType': 'hidden'
        });
      } else if(!this._layerInfo.isRootLayer() &&
          this._layerInfo.getRootLayerInfo().layerObject.declaredClass === "esri.layers.ArcGISDynamicMapServiceLayer" &&
          !this._layerInfo.getRootLayerInfo().layerObject.supportsDynamicLayers) {
        dynamicDeniedItems.push({
          'key': 'setVisibilityRange',
          'denyType': 'disable'
        });
      }

      //var loadInfoTemplateDef = this._layerInfo.loadInfoTemplate();
      var isPopupSupportedDef = this._layerInfo.isSupportPopupNested();
      var getSupportTableInfoDef = this._getSupportTableInfoForAllSublayers(this._layerInfo);

      all({
        //infoTemplate: loadInfoTemplateDef,
        isPopupSupported: isPopupSupportedDef,
        supportTableInfo: getSupportTableInfoDef
      }).then(lang.hitch(this, function(result) {

        // deny controlPopup
        if (!result.isPopupSupported) {
          dynamicDeniedItems.push({
            'key': 'controlPopup',
            'denyType': 'hidden'
          });
        }

        // deny table.
        var supportTableInfo = result.supportTableInfo;
        var attributeTableWidget =
              this.layerListWidget.appConfig.getConfigElementsByName("AttributeTable")[0];

        if (!attributeTableWidget || !attributeTableWidget.visible) {
          dynamicDeniedItems.push({
            'key': 'table',
            'denyType': 'hidden'
          });
        } else if (!this._isSupportedByAT(attributeTableWidget, supportTableInfo)) {
          dynamicDeniedItems.push({
            'key': 'table',
            'denyType': 'disable'
          });
          if(this._layerInfo.isMapNotesLayerInfo() || (this._layerInfo.parentLayerInfo &&
             this._layerInfo.parentLayerInfo.isMapNotesLayerInfo())) {
            dynamicDeniedItems.push({
              'key': 'table',
              'denyType': 'hidden'
            });
          } else {
            dynamicDeniedItems.push({
              'key': 'table',
              'denyType': 'disable'
            });
          }
        }
        defRet.resolve(dynamicDeniedItems);
      }), function() {
        defRet.resolve(dynamicDeniedItems);
      });

      return defRet;

    },

    getDisplayItems: function() {
      return this._displayItems;
    },

    onPopupMenuClick: function(evt) {
      var result = {
        closeMenu: true
      };
      switch (evt.itemKey) {
        case 'zoomto' /*this.nls.itemZoomTo'Zoom to'*/ :
          this._onItemZoomToClick(evt);
          break;
        case 'moveup' /*this.nls.itemMoveUp'Move up'*/ :
          this._onMoveUpItemClick(evt);
          break;
        case 'movedown' /*this.nls.itemMoveDown'Move down'*/ :
          this._onMoveDownItemClick(evt);
          break;
        case 'table' /*this.nls.itemToAttributeTable'Open attribute table'*/ :
          this._onTableItemClick(evt);
          break;
        case 'transparencyChanged':
          this._onTransparencyChanged(evt);
          result.closeMenu = false;
          break;
        case 'controlPopup':
          this._onControlPopup();
          break;
        case 'controlLabels':
          this._onControlLabels();
          break;

      }
      return result;
    },

    /**********************************
     * Respond events respectively.
     *
     * event format:
      // evt = {
      //   itemKey: item key
      //   extraData: estra data,
      //   layerListWidget: layerListWidget,
      //   layerListView: layerListView
      // }, result;
     **********************************/
    _onItemZoomToClick: function(evt) {
      /*jshint unused: false*/
      this._layerInfo.zoomTo();
    },

    _isValidExtent: function(extent){
      var isValid = false;
      if(esriLang.isDefined(extent)){
        if(esriLang.isDefined(extent.xmin) && isFinite(extent.xmin) &&
           esriLang.isDefined(extent.ymin) && isFinite(extent.ymin) &&
           esriLang.isDefined(extent.xmax) && isFinite(extent.xmax) &&
           esriLang.isDefined(extent.ymax) && isFinite(extent.ymax)){
          isValid = true;
        }
      }
      return isValid;
    },

    _onMoveUpItemClick: function(evt) {
      if (!this._layerInfo.isFirst) {
        evt.layerListView.moveUpLayer(this._layerInfo);
      }
    },

    _onMoveDownItemClick: function(evt) {
      if (!this._layerInfo.isLast) {
        evt.layerListView.moveDownLayer(this._layerInfo);
      }
    },

    _onTableItemClick: function(evt) {
      this._getSupportTableInfoForAllSublayers(this._layerInfo).then(lang.hitch(this, function(allSupportTableInfo) {
        var widgetManager;
        var attributeTableWidgetEle =
                    this.layerListWidget.appConfig.getConfigElementsByName("AttributeTable")[0];
        if(this._isSupportedByAT(attributeTableWidgetEle, allSupportTableInfo)) {
          widgetManager = WidgetManager.getInstance();

          array.forEach(allSupportTableInfo, function(supportTableInfo) {
            if(supportTableInfo.isSupportedLayer) {
              widgetManager.triggerWidgetOpen(attributeTableWidgetEle.id)
              .then(lang.hitch(this, function(atWidget) {
                if (atWidget) {
                  widgetManager.activateWidget(atWidget);
                }
                evt.layerListWidget.publishData({
                  'target': 'AttributeTable',
                  'layer': supportTableInfo.layerInfo
                });
              }));
            }
          }, this);

        }
      }));
    },

    _onTransparencyChanged: function(evt) {
      this.layerListWidget._denyLayerInfosOpacityResponseOneTime = true;
      this._layerInfo.setOpacity(1 - evt.extraData.newTransValue);
    },

    _onControlPopup: function(evt) {
      /*jshint unused: false*/
      //if (this._layerInfo.controlPopupInfo.enablePopup) {
      if(this._layerInfo.isPopupNestedEnabled()) {
        this._layerInfo.disablePopupNested();
      } else {
        this._layerInfo.enablePopupNested();
      }
      this._layerInfo.map.infoWindow.hide();
    },

    _onControlLabels: function(evt) {
      /*jshint unused: false*/
      if(this._layerInfo.canShowLabel()) {
        if(this._layerInfo.isShowLabels()) {
          this._layerInfo.hideLabels();
        } else {
          this._layerInfo.showLabels();
        }
      }
    }
  });

  clazz.create = function(layerInfo, layerListWidget) {
    var retDef = new Deferred();
    var isRootLayer = layerInfo.isRootLayer();
    var defaultItemInfos = [{
        key: 'controlPopup'
      }, {
        key: 'separator'
      }, {
        key: 'url',
        onClick: null
      }];

    var itemInfoCategoreList = {
      'RootLayer': [{
        key: 'zoomto'
      }, {
        key: 'transparency'
      }, {
        key: 'setVisibilityRange'
      }, {
        key: 'separator'
      }, {
        key: 'controlPopup'
      }, {
        key: 'separator'
      }, {
        key: 'moveup'
      }, {
        key: 'movedown'
      }, {
        key: 'separator'
      }, {
        key: 'table'
      }, {
        key: 'separator'
      }, {
        key: 'url'
      }],
      'RootLayerAndFeatureLayer': [{
        key: 'zoomto'
      }, {
        key: 'transparency'
      }, {
        key: 'setVisibilityRange'
      }, {
        key: 'separator'
      }, {
        key: 'controlPopup'
      }, {
        key: 'separator'
      }, {
        key: 'controlLabels'
      }, {
        key: 'separator'
      }, {
        key: 'moveup'
      }, {
        key: 'movedown'
      }, {
        key: 'separator'
      }, {
        key: 'table'
      }, {
        key: 'separator'
      }, {
        key: 'url'
      }],
      'FeatureLayer': [{
        key: 'setVisibilityRange'
      }, {
        key: 'separator'
      },{
        key: 'controlPopup'
      }, {
        key: 'separator'
      }, {
        key: 'table'
      }, {
        key: 'separator'
      }, {
        key: 'url'
      }],
      'SublayerOfDynamicMapserviceLayer': [{
        key: 'setVisibilityRange'
      }, {
        key: 'separator'
      }, {
        key: 'url'
      }],
      'GroupLayer': [{
        key: 'setVisibilityRange'
      }, {
        key: 'separator'
      }, {
        key: 'controlPopup'
      }, {
        key: 'separator'
      }, {
        key: 'table'
      }, {
        key: 'separator'
      }, {
        key: 'url'
      }],
      'Table': [{
        key: 'table'
      }, {
        key: 'separator'
      }, {
        key: 'url'
      }],
      'BasemapLayer': [{
        key: 'zoomto'
      }, {
        key: 'transparency'
      }, {
        key: 'separator'
      }, {
        key: 'url'
      }],
      'default': defaultItemInfos
    };

    layerInfo.getLayerType().then(lang.hitch(this, function(layerType) {
      var itemInfoCategory = "";
      if (layerInfo.isBasemap() && layerInfo.isRootLayer()) {
        itemInfoCategory = "BasemapLayer";
      } else if(layerInfo.isBasemap()) {
        itemInfoCategory = "default";
      } else if (isRootLayer &&
          (layerType === "FeatureLayer" ||
            layerType === "CSVLayer" ||
            layerType === "ArcGISImageServiceLayer" ||
            layerType === "StreamLayer" ||
            layerType === "ArcGISImageServiceVectorLayer")) {
        itemInfoCategory = "RootLayerAndFeatureLayer";
      } else if (isRootLayer) {
        itemInfoCategory = "RootLayer";
      } else if (layerType === "FeatureLayer" || layerType === "CSVLayer") {
        itemInfoCategory = "FeatureLayer";
      } else if (layerInfo.isLeaf() &&
                layerInfo.getRootLayerInfo() &&
                layerInfo.getRootLayerInfo().layerObject &&
                layerInfo.getRootLayerInfo().layerObject.declaredClass === "esri.layers.ArcGISDynamicMapServiceLayer") {
        itemInfoCategory = "SublayerOfDynamicMapserviceLayer";
      } else if (layerType === "GroupLayer") {
        itemInfoCategory = "GroupLayer";
      } else if (layerType === "Table") {
        itemInfoCategory = "Table";
      } else {
        //default condition
        itemInfoCategory = "default";
      }
      retDef.resolve(new clazz(layerInfo,
        itemInfoCategoreList[itemInfoCategory],
        layerType,
        layerListWidget));
    }), lang.hitch(this, function() {
      //return default popupmenu info.
      retDef.resolve(new clazz(layerInfo, [{
        key: 'empty'
      }]));
    }));
    return retDef;
  };


  return clazz;
});
