///////////////////////////////////////////////////////////////////////////
// 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',
  'dijit/_WidgetBase',
  'dijit/_TemplatedMixin',
  'dijit/_WidgetsInTemplateMixin',
  'dojo/text!./templates/DrawBox.html',
  'dojo/_base/lang',
  'dojo/_base/html',
  'dojo/_base/array',
  'dojo/on',
  "dijit/a11yclick",
  'dojo/query',
  'dojo/Evented',
  'esri/graphic',
  'esri/layers/GraphicsLayer',
  // 'esri/toolbars/draw',
  'jimu/dijit/Draw',
  'esri/symbols/jsonUtils',
  'esri/geometry/Polygon'
],
function(declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, template, lang, html,
  array, on, a11yclick, query, Evented, Graphic, GraphicsLayer, Draw, jsonUtils, Polygon) {
  var instancesObj = {};

  return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, Evented], {
    templateString:template,
    baseClass: 'jimu-draw-box',
    declaredClass: 'jimu.dijit.DrawBox',
    nls:null,
    drawLayer:null,
    drawLayerId:null,
    drawToolBar:null,
    _isDisabled: false,
    _shiftKey: false,
    _ctrlKey: false,
    _metaKey: false, //used for Mac

    //options:
    //note: 'types' is mutually exclusive with 'geoTypes' and the latter has high priority
    //available types: ['point','polyline','polygon','text']
    types:null,
    /*available geoTypes:
      ["POINT",
       "ARROW",
       "LINE", "POLYLINE", "FREEHAND_POLYLINE",
       "TRIANGLE", "EXTENT", "CIRCLE", "ELLIPSE", "POLYGON", "FREEHAND_POLYGON",
       "TEXT"]
    */
    geoTypes:null,//if 'geoTypes' is set, 'types' is ignored
    map:null,
    pointSymbol:null,
    polylineSymbol:null,
    polygonSymbol:null,
    textSymbol:null,
    showClear:false,//show Clear button or not
    keepOneGraphic:false,//only keep one graphic or not
    deactivateAfterDrawing: true,//deactivate drawToolbar or not after every drawing

    //public methods:
    //setMap
    //setPointSymbol
    //setLineSymbol
    //setPolygonSymbol
    //setTextSymbol
    //addGraphic
    //removeGraphic
    //reset
    //clear
    //activate
    //deactivate
    //enable
    //disable
    //isEnabled

    //events:
    //icon-selected
    //draw-end
    //clear
    //user-clear
    //draw-activate
    //draw-deactivate

    //css classes:
    //draw-item
    //point-icon
    //arrow-icon
    //line-icon
    //polyline-icon
    //freehand-polyline-icon
    //triangle-icon
    //extent-icon
    //circle-icon
    //ellipse-icon
    //polygon-icon
    //freehand-polygon-icon
    //text-icon
    //drawings-clear

    postMixInProperties:function(){
      this.nls = window.jimuNls.drawBox;
    },

    postCreate:function(){
      this.inherited(arguments);
      var layerArgs = {};
      if(this.drawLayerId){
        layerArgs.id = this.drawLayerId;
      }
      this.drawLayer = new GraphicsLayer(layerArgs);
      this._initDefaultSymbols();
      this._initTypes();
      var items = query('.draw-item', this.domNode);
      items.forEach(function(item){
        html.setAttr(item, 'role', 'button');
        html.setAttr(item, 'tabindex', '0');
      });
      this.own(items.on(a11yclick, lang.hitch(this, this._onItemClick)));

      html.setAttr(this.btnClear, 'role', 'button');
      html.setAttr(this.btnClear, 'tabindex', '0');
      this.own(on(this.btnClear, a11yclick, lang.hitch(this, this._onClickClear)));
      //bind key events before draw-end
      this.own(on(document.body, 'keydown', lang.hitch(this, function(event){
        this._shiftKey = !!event.shiftKey;
        this._ctrlKey = !!event.ctrlKey;
        this._metaKey = !!event.metaKey;
      })));
      this.own(on(document.body, 'keyup', lang.hitch(this, function(event){
        this._shiftKey = !!event.shiftKey;
        this._ctrlKey = !!event.ctrlKey;
        this._metaKey = !!event.metaKey;
      })));

      if(this.map){
        this.setMap(this.map);
      }
      var display = this.showClear === true ? 'block' : 'none';
      html.setStyle(this.btnClear, 'display', display);
      this.enable();

      instancesObj[this.id] = this;
    },

    enable: function(){
      this._isDisabled = false;
      html.addClass(this.domNode, 'enabled');
      html.removeClass(this.domNode, 'disabled');
    },

    disable: function(){
      this._isDisabled = true;
      html.addClass(this.domNode, 'disabled');
      html.removeClass(this.domNode, 'enabled');
      this.deactivate();
    },

    hideLayer: function(){
      if(this.drawLayer){
        this.drawLayer.hide();
      }
    },

    showLayer: function(){
      if(this.drawLayer){
        this.drawLayer.show();
      }
    },

    isEnabled: function(){
      return !this._isDisabled;
    },

    isActive: function(){
      var items = query('.draw-item.jimu-state-active', this.domNode);
      return items && items.length > 0;
    },

    disableWebMapPopup:function(){
      if(this.map){
        this.map.setInfoWindowOnClick(false);
      }
    },

    enableWebMapPopup:function(){
      if(this.map){
        this.map.setInfoWindowOnClick(true);
      }
    },

    destroy:function(){
      this.deactivate();

      if(this.drawLayer){
        if(this.map){
          this.map.removeLayer(this.drawLayer);
        }
      }

      this.drawToolBar = null;
      this.map = null;
      this.drawLayer = null;
      delete instancesObj[this.id];
      this.inherited(arguments);
    },

    setMap:function(map){
      if(map){
        this.map = map;
        this.map.addLayer(this.drawLayer);
        this.drawToolBar = new Draw(this.map);
        this.drawToolBar.setMarkerSymbol(this.pointSymbol);
        this.drawToolBar.setLineSymbol(this.polylineSymbol);
        this.drawToolBar.setFillSymbol(this.polygonSymbol);
        this.own(on(this.drawToolBar, 'draw-end', lang.hitch(this, this._onDrawEnd)));
      }
    },

    setPointSymbol:function(symbol){
      this.pointSymbol = symbol;
      this.drawToolBar.setMarkerSymbol(this.pointSymbol);
    },

    setLineSymbol:function(symbol){
      this.polylineSymbol = symbol;
      this.drawToolBar.setLineSymbol(symbol);
    },

    setPolygonSymbol:function(symbol){
      this.polygonSymbol = symbol;
      this.drawToolBar.setFillSymbol(symbol);
    },

    setTextSymbol:function(symbol){
      this.textSymbol = symbol;
    },

    reset: function(){
      this.deactivate();
      this.clear();
    },

    clear:function(){
      this.drawLayer.clear();
      this.onClear();
    },

    deactivate:function(){
      this.enableWebMapPopup();
      query('.draw-item', this.domNode).removeClass('jimu-state-active');
      if(this.drawToolBar){
        this.drawToolBar.deactivate();
        this.emit('draw-deactivate');
      }
    },

    activate: function(tool){
      //tool available values:
      //POINT
      //LINE,POLYLINE,FREEHAND_POLYLINE
      //TRIANGLE,EXTENT,CIRCLE,ELLIPSE,POLYGON,FREEHAND_POLYGON
      //TEXT
      var itemIcon = null;
      var items = query('.draw-item', this.domNode);
      if(tool === 'TEXT'){
        tool = 'POINT';
        itemIcon = this.textIcon;
      }else{
        var filterItems = items.filter(function(itemNode){
          return itemNode.getAttribute('data-geotype') === tool;
        });
        if(filterItems.length > 0){
          itemIcon = filterItems[0];
        }
      }
      if(itemIcon){
        this._activate(itemIcon);
      }
    },

    onIconSelected:function(target, geotype, commontype){
      this.emit("icon-selected", target, geotype, commontype);
    },

    onDrawEnd:function(graphic, geotype, commontype, shiftKey, ctrlKey, metaKey){
      this.emit('draw-end', graphic, geotype, commontype, shiftKey, ctrlKey, metaKey);
    },

    onClear:function(){
      this.emit("clear");
    },

    addGraphic:function(g){
      if(this.keepOneGraphic){
        this.drawLayer.clear();
      }
      this.drawLayer.add(g);
    },

    removeGraphic:function(g){
      this.drawLayer.remove(g);
    },

    getFirstGraphic: function(){
      var firstGraphic = null;
      if(this.drawLayer && this.drawLayer.graphics.length > 0){
        firstGraphic = this.drawLayer.graphics[0];
      }
      return firstGraphic;
    },

    show: function(){
      html.removeClass(this.domNode, 'hidden');
    },

    hide: function(){
      html.addClass(this.domNode, 'hidden');
    },

    getDrawItemIcons: function(){
      return query('.draw-item', this.domNode);
    },

    _onClickClear: function(){
      if(this._isDisabled){
        return;
      }
      this.clear();
      this.emit("user-clear");
    },

    _initDefaultSymbols:function(){
      var pointSys = {
        "style": "esriSMSCircle",
        "color": [0, 0, 128, 128],
        "name": "Circle",
        "outline": {
          "color": [0, 0, 128, 255],
          "width": 1
        },
        "type": "esriSMS",
        "size": 18
      };
      var lineSys = {
        "style": "esriSLSSolid",
        "color": [79, 129, 189, 255],
        "width": 3,
        "name": "Blue 1",
        "type": "esriSLS"
      };
      var polygonSys = {
        "style": "esriSFSSolid",
        "color": [79, 129, 189, 128],
        "type": "esriSFS",
        "outline": {
          "style": "esriSLSSolid",
          "color": [54, 93, 141, 255],
          "width": 1.5,
          "type": "esriSLS"
        }
      };
      if(!this.pointSymbol){
        this.pointSymbol = jsonUtils.fromJson(pointSys);
      }
      if(!this.polylineSymbol){
        this.polylineSymbol = jsonUtils.fromJson(lineSys);
      }
      if(!this.polygonSymbol){
        this.polygonSymbol = jsonUtils.fromJson(polygonSys);
      }
    },

    _initTypes:function(){
      if(this.geoTypes && this.geoTypes.length > 0){
        //if 'geoTypes' is set, we ignore 'types'
        this.types = null;
      }else{
        this.geoTypes = [];
        if(!(this.types && this.types.length > 0)){
          this.types = ['point', 'arrow', 'polyline', 'polygon'];
        }
        if(this.types.indexOf('point') >= 0){
          this.geoTypes = this.geoTypes.concat(["POINT"]);
        }
        if(this.types.indexOf('arrow') >= 0){
          this.geoTypes = this.geoTypes.concat(["ARROW"]);
        }
        if(this.types.indexOf('polyline') >= 0){
          this.geoTypes = this.geoTypes.concat(["LINE", "POLYLINE", "FREEHAND_POLYLINE"]);
        }
        if(this.types.indexOf('polygon') >= 0){
          var a = ["TRIANGLE", "EXTENT", "CIRCLE", "ELLIPSE", "POLYGON", "FREEHAND_POLYGON"];
          this.geoTypes = this.geoTypes.concat(a);
        }
        if(this.types.indexOf('text') >= 0){
          this.geoTypes = this.geoTypes.concat(["TEXT"]);
        }
      }
      var items = query('.draw-item', this.domNode);
      items.style('display', 'none');
      array.forEach(items, lang.hitch(this, function(item){
        var geoType = item.getAttribute('data-geotype');
        var display = array.indexOf(this.geoTypes, geoType) >= 0;
        html.setStyle(item, 'display', display ? 'block' : 'none');
      }));
    },

    _onItemClick:function(event){
      if(this._isDisabled){
        return;
      }
      var target = event.target || event.srcElement;
      if(!html.hasClass(target, 'draw-item')){
        return;
      }
      var isSelected = html.hasClass(target, 'jimu-state-active');

      //toggle tools on and off
      if(isSelected){
        this.deactivate();
      }else{
        this._activate(target);
      }
    },

    _activate: function(itemIcon){
      this._deactiveAllDrawBoxes();

      var items = query('.draw-item', this.domNode);
      items.removeClass('jimu-state-active');
      html.addClass(itemIcon, 'jimu-state-active');
      var geotype = itemIcon.getAttribute('data-geotype');
      var commontype = itemIcon.getAttribute('data-commontype');
      var tool = Draw[geotype];
      if(geotype === 'TEXT'){
        tool = Draw.POINT;
      }
      this.disableWebMapPopup();
      this.drawToolBar.activate(tool);
      this.emit('draw-activate', tool);
      this.onIconSelected(itemIcon, geotype, commontype);
    },

    _onDrawEnd:function(event){
      var selectedItem = query('.draw-item.jimu-state-active', this.domNode)[0];
      var geotype = selectedItem.getAttribute('data-geotype');
      var commontype = selectedItem.getAttribute('data-commontype');
      var geometry = null;

      if(event.geometry.type === 'extent'){
        //convert extent to polygon because Analysis dijit doesn't support extent
        geometry = Polygon.fromExtent(event.geometry);
      }else{
        geometry = event.geometry;
      }

      geometry.geoType = geotype;
      geometry.commonType = commontype;

      var type = geometry.type;
      var symbol = null;

      if (type === "point" || type === "multipoint") {
        if(html.hasClass(this.textIcon, 'jimu-state-active')){
          symbol = this.textSymbol;
        }
        else{
          symbol = this.pointSymbol;
        }
      } else if (type === "line" || type === "polyline") {
        symbol = this.polylineSymbol;
      } else {
        symbol = this.polygonSymbol;
      }

      var g = new Graphic(geometry, symbol, null, null);

      if(this.keepOneGraphic){
        this.drawLayer.clear();
      }

      this.drawLayer.add(g);

      if(this.deactivateAfterDrawing){
        this.deactivate();
      }

      this.onDrawEnd(g, geotype, commontype, this._shiftKey, this._ctrlKey, this._metaKey);
    },

    _deactiveAllDrawBoxes: function() {
      var widget;
      array.forEach(Object.keys(instancesObj), lang.hitch(this, function(key) {
        widget = instancesObj[key];
        if (widget && widget.drawToolBar && key !== this.id) {
          widget.deactivate();
        }
      }));
    }
  });
});