///////////////////////////////////////////////////////////////////////////
// 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/lang',
  'dojo/_base/array',
  'dojo/_base/html',
  'dojo/topic',
  'dojo/dom-construct',
  'dojo/dom-geometry',
  'dojo/promise/all',
  'dojo/when',
  '../WidgetManager',
  '../PanelManager',
  '../utils',
  '../dijit/LoadingShelter',
  './BaseLayoutManager'
],

function(declare, lang, array, html, topic, domConstruct, domGeometry,
  all, when, WidgetManager, PanelManager, utils, LoadingShelter, BaseLayoutManager) {
  /* global jimuConfig:true */
  var instance = null, clazz;

  clazz = declare([BaseLayoutManager], {
    name: 'AbsolutePositionLayoutManager',

    constructor: function() {
      /*jshint unused: false*/
      this.widgetManager = WidgetManager.getInstance();
      this.panelManager = PanelManager.getInstance();

      topic.subscribe("changeMapPosition", lang.hitch(this, this.onChangeMapPosition));

      this.onScreenGroupPanels = [];
    },

    map: null,

    resize: function() {
      //resize widgets. the panel's resize is called by the panel manager.
      //widgets which is in panel is resized by panel
      array.forEach(this.widgetManager.getAllWidgets(), function(w) {
        if (w.inPanel === false) {
          w.resize();
        }
      }, this);
    },

    setMap: function(map){
      this.inherited(arguments);
      this.panelManager.setMap(map);
    },

    getMapDiv: function(){
      if(html.byId(this.mapId)){
        return html.byId(this.mapId);
      }else{
        return html.create('div', {
          id: this.mapId,
          style: lang.mixin({
            position: 'absolute',
            backgroundColor: '#EEEEEE',
            overflow: 'hidden',
            minWidth:'1px',
            minHeight:'1px'
          }, utils.getPositionStyle(this.appConfig.map.position))
        }, this.layoutId);
      }
    },

    loadAndLayout: function(appConfig){
      console.time('Load widgetOnScreen');
      this.setMapPosition(appConfig.map.position);

      var loading = new LoadingShelter(), defs = [];
      loading.placeAt(this.layoutId);
      loading.startup();

      this._setTabindex(appConfig, false);
      // topic.publish('tabIndexChanged', appConfig);//this line will change this.appConfig

      //load widgets
      defs.push(this.loadOnScreenWidgets(appConfig));

      //load groups
      array.forEach(appConfig.widgetOnScreen.groups, function(groupConfig) {
        defs.push(this._loadOnScreenGroup(groupConfig, appConfig));
      }, this);

      all(defs).then(lang.hitch(this, function(){
        if(loading){
          loading.destroy();
          loading = null;
        }
        console.timeEnd('Load widgetOnScreen');
        topic.publish('preloadWidgetsLoaded');
        this._doPostLoad();
      }), lang.hitch(this, function(){
        if(loading){
          loading.destroy();
          loading = null;
        }
        //if error when load widget, let the others continue
        console.timeEnd('Load widgetOnScreen');
        topic.publish('preloadWidgetsLoaded');
        this._doPostLoad();
      }));
    },

    destroyOnScreenWidgetsAndGroups: function(){
      this.panelManager.destroyAllPanels();
      this.destroyOnScreenOffPanelWidgets();
      this.destroyWidgetPlaceholders();
      this.destroyOnScreenWidgetIcons();
      //the panels have been destroyed by panelManager, so just clean array after switch theme.
      this.onScreenGroupPanels = [];
      //reset sideBar class from layoutContainer
      html.removeClass(this.map.container.parentNode, 'sideBarDisplay');
      html.removeClass(this.map.container.parentNode, 'sideBarHidden');
    },

    ///seems this function is not used any more, leave it here for backward compatibility.
    openWidget: function(widgetId){
      //if widget is in group, we just ignore it

      //check on screen widgets, we don't check not-closeable off-panel widget
      array.forEach(this.onScreenWidgetIcons, function(widgetIcon){
        if(widgetIcon.configId === widgetId){
          widgetIcon.switchToOpen();
        }
      }, this);

      //check controllers
      array.forEach(this.widgetManager.getControllerWidgets(), function(controllerWidget){
        if(controllerWidget.widgetIsControlled(widgetId)){
          controllerWidget.setOpenedIds([widgetId]);
        }
      }, this);
    },

    /////////////functions to handle builder events
    onLayoutChange: function(appConfig){
      this._changeMapPosition(appConfig);

      //relayout placehoder
      array.forEach(this.widgetPlaceholders, function(placeholder){
        placeholder.moveTo(appConfig.getConfigElementById(placeholder.configId).position);
      }, this);

      //relayout icons
      array.forEach(this.onScreenWidgetIcons, function(icon){
        icon.moveTo(appConfig.getConfigElementById(icon.configId).position);
      }, this);

      //relayout paneless widget
      array.forEach(this.widgetManager.getOnScreenOffPanelWidgets(), function(widget){
        if(widget.closeable){
          //this widget position is controlled by icon
          return;
        }
        var position = appConfig.getConfigElementById(widget.id).position;
        widget.setPosition(position);
      }, this);

      //relayout groups
      array.forEach(this.onScreenGroupPanels, function(panel){
        var position = appConfig.getConfigElementById(panel.config.id).panel.position;
        panel.setPosition(position);
      }, this);
    },

    onWidgetChange: function(appConfig, widgetConfig){
      widgetConfig = appConfig.getConfigElementById(widgetConfig.id);

      this.onOnScreenWidgetChange(appConfig, widgetConfig);

      array.forEach(this.onScreenGroupPanels, function(panel){
        panel.reloadWidget(widgetConfig);
      }, this);

    },

    onGroupChange: function(appConfig, groupConfig){
      groupConfig = appConfig.getConfigElementById(groupConfig.id);

      if(groupConfig.isOnScreen){
        //for now, onscreen group can change widgets in it only
        this.panelManager.destroyPanel(groupConfig.id + '_panel');
        this.removeDestroyed(this.onScreenGroupPanels);
        this._loadOnScreenGroup(groupConfig, appConfig);
      }else{
        array.forEach(this.widgetManager.getControllerWidgets(), function(controllerWidget){
          if(controllerWidget.isControlled(groupConfig.id)){
            this.reloadControllerWidget(appConfig, controllerWidget.id);
          }
        }, this);

        array.forEach(this.panelManager.panels, function(panel){
          if(panel.config.id === groupConfig.id){
            panel.updateConfig(groupConfig);
          }
        }, this);
      }
    },

    onActionTriggered: function(info){
      if(info.action === 'highLight'){
        array.forEach(this.widgetPlaceholders, function(placehoder){
          if(placehoder.configId === info.elementId){
            this._highLight(placehoder);
          }
        }, this);
        array.forEach(this.onScreenWidgetIcons, function(widgetIcon){
          if (widgetIcon.configId === info.elementId){
            this._highLight(widgetIcon);
          }
        }, this);
        array.forEach(this.widgetManager.getOnScreenOffPanelWidgets(), function(panelessWidget){
          if (panelessWidget.configId === info.elementId){
            this._highLight(panelessWidget);
          }
        }, this);
        array.forEach(this.onScreenGroupPanels, function(panel){
          if (panel.configId === info.elementId){
            this._highLight(panel);
          }
        }, this);
      }
      if(info.action === 'removeHighLight'){
        this._removeHighLight();
      }
      if(info.action === 'showLoading'){
        html.setStyle(jimuConfig.loadingId, 'display', 'block');
        html.setStyle(jimuConfig.mainPageId, 'display', 'none');
      }
      if(info.action === 'showApp'){
        html.setStyle(jimuConfig.loadingId, 'display', 'none');
        html.setStyle(jimuConfig.mainPageId, 'display', 'block');
      }
    },

    onChangeMapPosition: function(position) {
      var pos = lang.clone(this.mapPosition);
      lang.mixin(pos, position);
      this.setMapPosition(pos);
    },

    setMapPosition: function(position){
      this.mapPosition = position;

      var posStyle = utils.getPositionStyle(position);
      html.setStyle(this.mapId, posStyle);
      if (this.map && this.map.resize) {
        this.map.resize();
      }
    },

    getMapPosition: function(){
      return this.mapPosition;
    },

    _highLight: function(dijit){
      if(!dijit.domNode){
        //the dijit may be destroyed
        return;
      }
      if (this.hlDiv){
        this._removeHighLight(dijit);
      }
      var position = domGeometry.getContentBox(dijit.domNode);
      var hlStyle = {
        position: 'absolute',
        left: position.l + 'px',
        top: position.t + 'px',
        width: position.w + 'px',
        height: position.h + 'px'
      };
      this.hlDiv = domConstruct.create('div', {
        "style": hlStyle,
        "class": 'icon-highlight'
      }, dijit.domNode, 'before');
    },

    _removeHighLight: function(){
      if (this.hlDiv){
        domConstruct.destroy(this.hlDiv);
        this.hlDiv = null;
      }
    },

    _changeMapPosition: function(appConfig){
      if(!this.map){
        return;
      }
      if(!utils.isEqual(this.getMapPosition(), appConfig.map.position)){
        this.setMapPosition(appConfig.map.position);
      }
    },

    _loadOnScreenGroup: function(groupJson, appConfig) {
      if(!appConfig.mode && (!groupJson.widgets || groupJson.widgets.length === 0)){
        html.addClass(this.map.container.parentNode, 'sideBarHidden');
        return when(null);
      }
      return this.panelManager.showPanel(groupJson).then(lang.hitch(this, function(panel){
        panel.configId = groupJson.id;
        this.onScreenGroupPanels.push(panel);
        return panel;
      }));
    }
  });

  clazz.getInstance = function() {
    if (instance === null) {
      instance = new clazz();
      window._absolutLayoutManager = instance;
    }
    return instance;
  };
  return clazz;
});
