import {shiftKeyOnly as ol_events_condition_shiftKeyOnly} from 'ol/events/condition.js'
import {click as ol_events_condition_click} from 'ol/events/condition.js'
import ol_interaction_Draw from 'ol/interaction/Draw.js'
import ol_geom_LineString from 'ol/geom/LineString.js'
import ol_geom_Polygon from 'ol/geom/Polygon.js'
import ol_interaction_Select from 'ol/interaction/Select.js'

import ol_control_Bar from './Bar.js'
import ol_control_Button from './Button.js'
import ol_control_Toggle from './Toggle.js'
import ol_control_TextButton from './TextButton.js'
import ol_interaction_Delete from '../interaction/Delete.js'
import ol_ext_element from '../util/element.js'
import ol_interaction_Offset from '../interaction/Offset.js'
import ol_interaction_Split from '../interaction/Split.js'
import ol_interaction_Transform from '../interaction/Transform.js'
import ol_interaction_ModifyFeature from '../interaction/ModifyFeature.js'
import ol_interaction_DrawRegular from '../interaction/DrawRegular.js'
import ol_interaction_DrawHole from '../interaction/DrawHole.js'

/** Control bar for editing in a layer
 * @constructor
 * @extends {ol_control_Bar}
 * @fires info
 * @param {Object=} options Control options.
 *	@param {String} options.className class of the control
 *	@param {String} options.target Specify a target if you want the control to be rendered outside of the map's viewport.
 *	@param {boolean} options.edition false to remove the edition tools, default true
 *	@param {boolean} options.drawOptions false to remove the draw options bar
 *	@param {Object} options.interactions List of interactions to add to the bar 
 *    ie. Select, Delete, Info, DrawPoint, DrawLine, DrawPolygon
 *    Each interaction can be an interaction or true (to get the default one) or false to remove it from bar
 *	@param {ol.source.Vector} options.source Source for the drawn features. 
 */
var ol_control_EditBar = class olcontrolEditBar extends ol_control_Bar {
  constructor(options) {
    options = options || {}
    options.interactions = options.interactions || {}

    // New bar
    super({
      className: (options.className ? options.className + ' ' : '') + 'ol-editbar',
      toggleOne: true,
      target: options.target
    })

    this._source = options.source
    // Add buttons / interaction
    this._interactions = {}
    this._setSelectInteraction(options)
    if (options.edition !== false)
      this._setEditInteraction(options)
    this._setModifyInteraction(options)
  }
  /**
   * Set the map instance the control is associated with
   * and add its controls associated to this map.
   * @param {_ol_Map_} map The map instance.
   */
  setMap(map) {
    if (this.getMap()) {
      if (this._interactions.Delete)
        this.getMap().removeInteraction(this._interactions.Delete)
      if (this._interactions.ModifySelect)
        this.getMap().removeInteraction(this._interactions.ModifySelect)
    }
    super.setMap(map)

    if (this.getMap()) {
      if (this._interactions.Delete)
        this.getMap().addInteraction(this._interactions.Delete)
      if (this._interactions.ModifySelect)
        this.getMap().addInteraction(this._interactions.ModifySelect)
    }
  }
  /** Get an interaction associated with the bar
   * @param {string} name
   */
  getInteraction(name) {
    return this._interactions[name]
  }
  /** Get the option title */
  _getTitle(option) {
    if (option) {
      if (option.get)
        return option.get('title')
      else if (typeof (option) === 'string')
        return option
      else
        return option.title
    }
  }
  /** Add selection tool:
   * 1. a toggle control with a select interaction
   * 2. an option bar to delete / get information on the selected feature
   * @private
   */
  _setSelectInteraction(options) {
    var self = this

    // Sub bar
    var sbar = new ol_control_Bar()
    var selectCtrl

    // Delete button
    if (options.interactions.Delete !== false) {
      if (options.interactions.Delete instanceof ol_interaction_Delete) {
        this._interactions.Delete = options.interactions.Delete
      } else {
        this._interactions.Delete = new ol_interaction_Delete()
      }
      var del = this._interactions.Delete
      del.setActive(false)
      if (this.getMap())
        this.getMap().addInteraction(del)
      sbar.addControl(new ol_control_Button({
        className: 'ol-delete',
        title: this._getTitle(options.interactions.Delete) || "Delete",
        name: 'Delete',
        handleClick: function (e) {
          // Delete selection
          del.delete(selectCtrl.getInteraction().getFeatures())
          var evt = {
            type: 'select',
            selected: [],
            deselected: selectCtrl.getInteraction().getFeatures().getArray().slice(),
            mapBrowserEvent: e.mapBrowserEvent
          }
          selectCtrl.getInteraction().getFeatures().clear()
          selectCtrl.getInteraction().dispatchEvent(evt)
        }
      }))
    }

    // Info button
    if (options.interactions.Info !== false) {
      sbar.addControl(new ol_control_Button({
        className: 'ol-info',
        name: 'Info',
        title: this._getTitle(options.interactions.Info) || "Show informations",
        handleClick: function () {
          self.dispatchEvent({
            type: 'info',
            features: selectCtrl.getInteraction().getFeatures()
          })
        }
      }))
    }

    // Select button
    if (options.interactions.Select !== false) {
      if (options.interactions.Select instanceof ol_interaction_Select) {
        this._interactions.Select = options.interactions.Select
      } else {
        this._interactions.Select = new ol_interaction_Select({
          condition: ol_events_condition_click
        })
      }
      var sel = this._interactions.Select
      selectCtrl = new ol_control_Toggle({
        className: 'ol-selection',
        name: 'Select',
        title: this._getTitle(options.interactions.Select) || "Select",
        interaction: sel,
        bar: sbar.getControls().length ? sbar : undefined,
        autoActivate: true,
        active: true
      })

      this.addControl(selectCtrl)
      sel.on('change:active', function () {
        if (!sel.getActive()) {
          sel.getFeatures().clear()
        }
      }.bind(this))
    }
  }
  /** Add editing tools
   * @private
   */
  _setEditInteraction(options) {
    if (options.interactions.DrawPoint !== false) {
      if (options.interactions.DrawPoint instanceof ol_interaction_Draw) {
        this._interactions.DrawPoint = options.interactions.DrawPoint
      } else {
        this._interactions.DrawPoint = new ol_interaction_Draw({
          type: 'Point',
          source: this._source
        })
      }
      var pedit = new ol_control_Toggle({
        className: 'ol-drawpoint',
        name: 'DrawPoint',
        title: this._getTitle(options.interactions.DrawPoint) || 'Point',
        interaction: this._interactions.DrawPoint
      })
      this.addControl(pedit)
    }

    if (options.interactions.DrawLine !== false) {
      if (options.interactions.DrawLine instanceof ol_interaction_Draw) {
        this._interactions.DrawLine = options.interactions.DrawLine
      } else {
        this._interactions.DrawLine = new ol_interaction_Draw({
          type: 'LineString',
          source: this._source,
          // Count inserted points
          geometryFunction: function (coordinates, geometry) {
            if (geometry)
              geometry.setCoordinates(coordinates)
            else
              geometry = new ol_geom_LineString(coordinates)
            this.nbpts = geometry.getCoordinates().length
            return geometry
          }
        })
      }
      var ledit
      if (options.drawOptions !== false) {
        ledit = new ol_control_Toggle({
          className: 'ol-drawline',
          title: this._getTitle(options.interactions.DrawLine) || 'LineString',
          name: 'DrawLine',
          interaction: this._interactions.DrawLine,
          // Options bar associated with the control
          bar: new ol_control_Bar({
            controls: [
              new ol_control_TextButton({
                html: this._getTitle(options.interactions.UndoDraw) || 'undo',
                title: this._getTitle(options.interactions.UndoDraw) || "delete last point",
                handleClick: function () {
                  if (ledit.getInteraction().nbpts > 1)
                    ledit.getInteraction().removeLastPoint()
                }
              }),
              new ol_control_TextButton({
                html: this._getTitle(options.interactions.FinishDraw) || 'finish',
                title: this._getTitle(options.interactions.FinishDraw) || "finish",
                handleClick: function () {
                  // Prevent null objects on finishDrawing
                  if (ledit.getInteraction().nbpts > 2)
                    ledit.getInteraction().finishDrawing()
                }
              })
            ]
          })
        })
      } else {
        ledit = new ol_control_Toggle({
          className: 'ol-drawline',
          title: this._getTitle(options.interactions.DrawLine) || 'LineString',
          name: 'DrawLine',
          interaction: this._interactions.DrawLine,
        })
      }

      this.addControl(ledit)
    }

    if (options.interactions.DrawPolygon !== false) {
      if (options.interactions.DrawPolygon instanceof ol_interaction_Draw) {
        this._interactions.DrawPolygon = options.interactions.DrawPolygon
      } else {
        this._interactions.DrawPolygon = new ol_interaction_Draw({
          type: 'Polygon',
          source: this._source,
          // Count inserted points
          geometryFunction: function (coordinates, geometry) {
            this.nbpts = coordinates[0].length
            if (geometry)
              geometry.setCoordinates([coordinates[0].concat([coordinates[0][0]])])
            else
              geometry = new ol_geom_Polygon(coordinates)
            return geometry
          }
        })
      }
      this._setDrawPolygon(
        'ol-drawpolygon',
        this._interactions.DrawPolygon,
        this._getTitle(options.interactions.DrawPolygon) || 'Polygon',
        'DrawPolygon',
        options
      )
    }

    // Draw hole
    if (options.interactions.DrawHole !== false) {
      if (options.interactions.DrawHole instanceof ol_interaction_DrawHole) {
        this._interactions.DrawHole = options.interactions.DrawHole
      } else {
        this._interactions.DrawHole = new ol_interaction_DrawHole()
      }
      this._setDrawPolygon(
        'ol-drawhole',
        this._interactions.DrawHole,
        this._getTitle(options.interactions.DrawHole) || 'Hole',
        'DrawHole',
        options
      )
    }

    // Draw regular
    if (options.interactions.DrawRegular !== false) {
      var label = { pts: 'pts', circle: 'circle' }
      if (options.interactions.DrawRegular instanceof ol_interaction_DrawRegular) {
        this._interactions.DrawRegular = options.interactions.DrawRegular
        label.pts = this._interactions.DrawRegular.get('ptsLabel') || label.pts
        label.circle = this._interactions.DrawRegular.get('circleLabel') || label.circle
      } else {
        this._interactions.DrawRegular = new ol_interaction_DrawRegular({
          source: this._source,
          sides: 4
        })
        if (options.interactions.DrawRegular) {
          label.pts = options.interactions.DrawRegular.ptsLabel || label.pts
          label.circle = options.interactions.DrawRegular.circleLabel || label.circle
        }
      }
      var regular = this._interactions.DrawRegular

      var div = document.createElement('div')

      var down = ol_ext_element.create('DIV', { parent: div })
      ol_ext_element.addListener(down, ['click', 'touchstart'], function () {
        var sides = regular.getSides() - 1
        if (sides < 2)
          sides = 2
        regular.setSides(sides)
        text.textContent = sides > 2 ? sides + ' ' + label.pts : label.circle
      }.bind(this))

      var text = ol_ext_element.create('TEXT', { html: '4 ' + label.pts, parent: div })

      var up = ol_ext_element.create('DIV', { parent: div })
      ol_ext_element.addListener(up, ['click', 'touchstart'], function () {
        var sides = regular.getSides() + 1
        if (sides < 3)
          sides = 3
        regular.setSides(sides)
        text.textContent = sides + ' ' + label.pts
      }.bind(this))

      var ctrl = new ol_control_Toggle({
        className: 'ol-drawregular',
        title: this._getTitle(options.interactions.DrawRegular) || 'Regular',
        name: 'DrawRegular',
        interaction: this._interactions.DrawRegular,
        // Options bar associated with the control
        bar: new ol_control_Bar({
          controls: [
            new ol_control_TextButton({
              html: div
            })
          ]
        })
      })
      this.addControl(ctrl)
    }

  }
  /**
   * @private
   */
  _setDrawPolygon(className, interaction, title, name, options) {
    var fedit
    if (options.drawOptions !== false) {
      fedit = new ol_control_Toggle({
        className: className,
        name: name,
        title: title,
        interaction: interaction,
        // Options bar associated with the control
        bar: new ol_control_Bar({
          controls: [
            new ol_control_TextButton({
              html: this._getTitle(options.interactions.UndoDraw) || 'undo',
              title: this._getTitle(options.interactions.UndoDraw) || 'undo last point',
              handleClick: function () {
                if (fedit.getInteraction().nbpts > 1)
                  fedit.getInteraction().removeLastPoint()
              }
            }),
            new ol_control_TextButton({
              html: this._getTitle(options.interactions.FinishDraw) || 'finish',
              title: this._getTitle(options.interactions.FinishDraw) || 'finish',
              handleClick: function () {
                // Prevent null objects on finishDrawing
                if (fedit.getInteraction().nbpts > 3)
                  fedit.getInteraction().finishDrawing()
              }
            })
          ]
        })
      })
    } else {
      fedit = new ol_control_Toggle({
        className: className,
        name: name,
        title: title,
        interaction: interaction,
      })
    }
    this.addControl(fedit)
    return fedit
  }
  /** Add modify tools
   * @private
   */
  _setModifyInteraction(options) {
    // Modify on selected features
    if (options.interactions.ModifySelect !== false && options.interactions.Select !== false) {
      if (options.interactions.ModifySelect instanceof ol_interaction_ModifyFeature) {
        this._interactions.ModifySelect = options.interactions.ModifySelect
      } else {
        this._interactions.ModifySelect = new ol_interaction_ModifyFeature({
          features: this.getInteraction('Select').getFeatures()
        })
      }
      if (this.getMap())
        this.getMap().addInteraction(this._interactions.ModifySelect)
      // Activate with select
      this._interactions.ModifySelect.setActive(this._interactions.Select.getActive())
      this._interactions.Select.on('change:active', function () {
        this._interactions.ModifySelect.setActive(this._interactions.Select.getActive())
      }.bind(this))
    }

    if (options.interactions.Transform !== false) {
      if (options.interactions.Transform instanceof ol_interaction_Transform) {
        this._interactions.Transform = options.interactions.Transform
      } else {
        this._interactions.Transform = new ol_interaction_Transform({
          select: this._interactions.Select,
          addCondition: ol_events_condition_shiftKeyOnly
        })
        // Remove selection if not active
        if (this._interactions.Select) {
          this._interactions.Transform.on('change:active', function() {
            if (!this._interactions.Select.getActive()) {
              this._interactions.Select.getFeatures().clear();
            }
          }.bind(this))
        }
      }
      var transform = new ol_control_Toggle({
        html: '<i></i>',
        className: 'ol-transform',
        title: this._getTitle(options.interactions.Transform) || 'Transform',
        name: 'Transform',
        interaction: this._interactions.Transform
      })
      this.addControl(transform)
    }

    if (options.interactions.Split !== false) {
      if (options.interactions.Split instanceof ol_interaction_Split) {
        this._interactions.Split = options.interactions.Split
      } else {
        this._interactions.Split = new ol_interaction_Split({
          sources: this._source
        })
      }
      var split = new ol_control_Toggle({
        className: 'ol-split',
        title: this._getTitle(options.interactions.Split) || 'Split',
        name: 'Split',
        interaction: this._interactions.Split
      })
      this.addControl(split)
    }

    if (options.interactions.Offset !== false) {
      if (options.interactions.Offset instanceof ol_interaction_Offset) {
        this._interactions.Offset = options.interactions.Offset
      } else {
        this._interactions.Offset = new ol_interaction_Offset({
          source: this._source
        })
      }
      var offset = new ol_control_Toggle({
        html: '<i></i>',
        className: 'ol-offset',
        title: this._getTitle(options.interactions.Offset) || 'Offset',
        name: 'Offset',
        interaction: this._interactions.Offset
      })
      this.addControl(offset)
    }

  }
}

export default ol_control_EditBar
