/* 
  Using WMS Layer with EPSG:4326 projection.
  The tiles will be reprojected to map pojection (EPSG:3857).
  NB: reduce tileSize to minimize deformations on small scales.
*/
import ol_View from 'ol/View.js'
import ol_source_TileWMS from 'ol/source/TileWMS.js'
import ol_layer_Tile from 'ol/layer/Tile.js'
import {transformExtent as ol_proj_transformExtent} from 'ol/proj.js'
import ol_format_WMSCapabilities from 'ol/format/WMSCapabilities.js'
import ol_ext_element from '../util/element.js'
import ol_ext_Ajax from '../util/Ajax.js'
import ol_control_Button from './Button.js'
import ol_control_Dialog from './Dialog.js'
import '../layer/GetPreview.js';

/** WMSCapabilities
 * @constructor
 * @fires load
 * @fires capabilities
 * @extends {ol_control_Button}
 * @param {*} options
 *  @param {string|Element} [options.target] the target to set the dialog, use document.body to have fullwindow dialog
 *  @param {string} [options.proxy] proxy to use when requesting Getcapabilites, default none (suppose the service use CORS)
 *  @param {string} [options.placeholder='service url...'] input placeholder, default 'service url...'
 *  @param {string} [options.title=WMS] dialog title, default 'WMS'
 *  @param {string} [options.searchLabel='search'] Label for search button, default 'search'
 *  @param {string} [options.loadLabel='load'] Label for load button, default 'load'
 *  @param {Array<string>} [options.srs] an array of supported srs, default map projection code or 'EPSG:3857'
 *  @param {number} [options.timeout=1000] Timeout for getCapabilities request, default 1000
 *  @param {boolean} [options.cors=false] Use CORS, default false
 *  @param {string} [options.optional] a list of optional url properties (when set in the request url), separated with ','
 *  @param {boolean} [options.trace=false] Log layer info, default false
 *  @param {*} [options.services] a key/url object of services for quick access in a menu
 */
var ol_control_WMSCapabilities = class olcontrolWMSCapabilities extends ol_control_Button {
  constructor(options) {
    options = options || {}
    var buttonOptions = Object.assign({}, options || {})

    if (buttonOptions.target === document.body) delete buttonOptions.target
    if (buttonOptions.target) {
      buttonOptions.className = ((buttonOptions.className || '') + ' ol-wmscapabilities ol-hidden').trim()
      delete buttonOptions.target
    } else {
      buttonOptions.className = ((buttonOptions.className || '') + ' ol-wmscapabilities').trim()
      buttonOptions.handleClick = function () {
        self.showDialog()
      }
    }
    super(buttonOptions);

    var self = this;
    this._proxy = options.proxy

    // WMS options
    this.set('srs', options.srs || [])
    this.set('cors', options.cors)
    this.set('trace', options.trace)
    this.set('title', options.title)
    this.set('loadLabel', options.loadLabel)
    this.set('optional', options.optional)

    // Dialog
    this.createDialog(options)
    // Default version
    this._elements.formVersion.value = '1.0.0'

    // Ajax request
    var parser = this._getParser()
    this._ajax = new ol_ext_Ajax({ dataType: 'text', auth: options.authentication })
    this._ajax.on('success', function (evt) {
      var caps
      try {
        caps = parser.read(evt.response)
      } catch (e) {
        this.showError({ type: 'load', error: e })
      }
      if (caps) {
        if (!caps.Capability.Layer.Layer) {
          this.showError({ type: 'noLayer' })
        } else {
          caps.url = evt.options.url
          this.showCapabilities(caps)
        }
      }
      this.dispatchEvent({ type: 'capabilities', capabilities: caps })
      if (typeof (evt.options.callback) === 'function')
        evt.options.callback(caps)
    }.bind(this))
    this._ajax.on('error', function (evt) {
      this.showError({ type: 'load', error: evt })
      this.dispatchEvent({ type: 'capabilities' })
      if (typeof (evt.options.callback) === 'function')
        false
    }.bind(this))

    // Handle waiting
    this._ajax.on('loadstart', function () {
      this._elements.element.classList.add('ol-searching')
    }.bind(this))
    this._ajax.on('loadend', function () {
      this._elements.element.classList.remove('ol-searching')
    }.bind(this))

    // Load a layer
    if (options.onselect) {
      this.on('load', function (e) {
        options.onselect(e.layer, e.options)
      })
    }
  }
  /** Get service parser
   */
  _getParser() {
    return new ol_format_WMSCapabilities()
  }
  /** Create dialog
   * @private
   */
  createDialog(options) {
    var target = options.target
    if (!target || target === document.body) {
      this._dialog = new ol_control_Dialog({
        className: 'ol-wmscapabilities',
        closeBox: true,
        closeOnSubmit: false,
        target: options.target
      })
      this._dialog.on('button', function (e) {
        if (e.button === 'submit') {
          this.getCapabilities(e.inputs.url.value)
        }
      }.bind(this))
      target = null
    }
    var element = ol_ext_element.create('DIV', {
      className: ('ol-wmscapabilities ' + (options.className || '')).trim(),
      parent: target
    })
    this._elements = {
      element: target || element
    }
    var inputdiv = ol_ext_element.create('DIV', {
      className: 'ol-url',
      parent: element
    })
    var input = this._elements.input = ol_ext_element.create('INPUT', {
      className: 'url',
      type: 'text',
      tabIndex: 1,
      placeholder: options.placeholder || 'service url...',
      autocorrect: 'off',
      autocapitalize: 'off',
      parent: inputdiv
    })
    input.addEventListener('keyup', function (e) {
      if (e.keyCode === 13) {
        this.getCapabilities(input.value, options)
      }
    }.bind(this))
    if (options.services) {
      var qaccess = ol_ext_element.create('SELECT', {
        className: 'url',
        on: {
          change: function (e) {
            var url = e.target.options[e.target.selectedIndex].value
            this.getCapabilities(url, options)
            e.target.selectedIndex = 0
          }.bind(this)
        },
        parent: inputdiv
      })
      ol_ext_element.create('OPTION', {
        html: ' ',
        parent: qaccess
      })
      for (var k in options.services) {
        ol_ext_element.create('OPTION', {
          html: k,
          value: options.services[k],
          parent: qaccess
        })
      }
    }
    ol_ext_element.create('BUTTON', {
      click: function () {
        this.getCapabilities(input.value, options)
      }.bind(this),
      html: options.searchLabel || 'search',
      parent: inputdiv
    })
    // Errors
    this._elements.error = ol_ext_element.create('DIV', {
      className: 'ol-error',
      parent: inputdiv
    })
    // Result div
    var rdiv = this._elements.result = ol_ext_element.create('DIV', {
      className: 'ol-result',
      parent: element
    })
    // Preview
    var preview = ol_ext_element.create('DIV', {
      className: 'ol-preview',
      html: options.previewLabel || 'preview',
      parent: rdiv
    })
    this._elements.preview = ol_ext_element.create('IMG', {
      parent: preview
    })
    // Check tainted canvas
    this._img = new Image
    this._img.crossOrigin = 'Anonymous'
    this._img.addEventListener('error', function () {
      preview.className = 'ol-preview tainted'
      this._elements.formCrossOrigin.checked = false
    }.bind(this))
    this._img.addEventListener('load', function () {
      preview.className = 'ol-preview ok'
      this._elements.formCrossOrigin.checked = true
    }.bind(this))
    // Select list
    this._elements.select = ol_ext_element.create('SELECT', {
      className: 'ol-select-list',
      on: {
        keydown: function(e) {
          if (e.key === 'Enter' || e.key === ' ') {
            var index = this._elements.select.selectedIndex;
            if (index >= 0) {
              this._elements.select.querySelectorAll('OPTION')[index].click();
            }
          }
        }.bind(this)
      },
      size: 100,
      parent: rdiv
    })
    // Info data
    this._elements.data = ol_ext_element.create('DIV', {
      className: 'ol-data',
      parent: rdiv
    })
    this._elements.buttons = ol_ext_element.create('DIV', {
      className: 'ol-buttons',
      parent: rdiv
    })
    this._elements.legend = ol_ext_element.create('IMG', {
      className: 'ol-legend',
      parent: rdiv
    })
    // WMS form
    var form = this._elements.form = ol_ext_element.create('UL', {
      className: 'ol-wmsform',
      parent: element
    })
    var addLine = function (label, val, pholder) {
      var li = ol_ext_element.create('LI', {
        parent: form
      })
      ol_ext_element.create('LABEL', {
        html: this.labels[label],
        parent: li
      })
      if (typeof (val) === 'boolean') {
        this._elements[label] = ol_ext_element.create('INPUT', {
          type: 'checkbox',
          checked: val,
          parent: li
        })
      } else if (val instanceof Array) {
        var sel = this._elements[label] = ol_ext_element.create('SELECT', {
          parent: li
        })
        val.forEach(function (v) {
          ol_ext_element.create('OPTION', {
            html: v,
            value: v,
            parent: sel
          })
        }.bind(this))
      } else {
        this._elements[label] = ol_ext_element.create('INPUT', {
          value: (val === undefined ? '' : val),
          placeholder: pholder || '',
          type: typeof (val) === 'number' ? 'number' : 'text',
          parent: li
        })
      }
      return li
    }.bind(this)
    addLine('formTitle')
    addLine('formLayer', '', 'layer1,layer2,...')
    var li = addLine('formMap')
    li.setAttribute('data-param', 'map')
    li = addLine('formStyle')
    li.setAttribute('data-param', 'style')
    addLine('formFormat', ['image/png', 'image/jpeg'])
    addLine('formMinZoom', 0)
    addLine('formMaxZoom', 20)
    li = addLine('formExtent', '', 'xmin,ymin,xmax,ymax')
    li.setAttribute('data-param', 'extent')
    var extent = li.querySelector('input')
    ol_ext_element.create('BUTTON', {
      title: this.labels.mapExtent,
      click: function () {
        extent.value = this.getMap().getView().calculateExtent(this.getMap().getSize()).join(',')
      }.bind(this),
      parent: li
    })
    li = addLine('formProjection', '')
    li.setAttribute('data-param', 'proj')
    addLine('formCrossOrigin', false)
    li = addLine('formVersion', '1.3.0')
    li.setAttribute('data-param', 'version')
    addLine('formAttribution', '')

    ol_ext_element.create('BUTTON', {
      html: this.get('loadLabel') || 'Load',
      click: function () {
        var opt = this._getFormOptions()
        var layer = this.getLayerFromOptions(opt)
        this.dispatchEvent({ type: 'load', layer: layer, options: opt })
        this._dialog.hide()
      }.bind(this),
      parent: form
    })

    return element
  }
  /** Create a new layer using options received by getOptionsFromCap method
   * @param {*} options
   */
  getLayerFromOptions(options) {
    options.layer.source = new ol_source_TileWMS(options.source)
    var layer = new ol_layer_Tile(options.layer)
    delete options.layer.source
    return layer
  }
  /**
   * 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) {
    super.setMap(map)
    if (this._dialog) this._dialog.setMap(map)
  }
  /** Get the dialog
   * @returns {ol_control_Dialog}
   */
  getDialog() {
    return this._dialog
  }
  /** Show dialog for url
   * @param {string} [url] service url, default ask for an url
   * @param {*} options capabilities options
   *  @param {string} options.map WMS map or get map in url?map=xxx
   *  @param {string} options.version WMS version (yet only 1.3.0 is implemented), default 1.3.0
   *  @param {number} options.timeout timout to get the capabilities, default 10000
   */
  showDialog(url, options) {
    this.showError()
    if (!this._elements.formProjection.value) {
      this._elements.formProjection.value = this.getMap().getView().getProjection().getCode()
    }
    if (this._dialog) {
      this._dialog.show({
        title: this.get('title') === undefined ? 'WMS' : this.get('title'),
        content: this._elements.element
      })
    }
    this.getCapabilities(url, options)
    // Center on selection
    var sel = this._elements.select.querySelector('.selected')
    if (sel) {
      this._elements.select.scrollTop = sel.offsetTop - 20
    }
  }
  /** Test url and return true if it is a valid url string
   * @param {string} url
   * @return {bolean}
   * @api
   */
  testUrl(url) {
    // var pattern = /(https?:\/\/)([\da-z.-]+)\.([a-z]{2,6})([/\w.-]*)*\/?/
    var pattern = new RegExp(
      // protocol
      '^(https?:\\/\\/)' +
      // domain name
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' +
      // OR ip (v4) address
      '((\\d{1,3}\\.){3}\\d{1,3}))' +
      // port and path
      '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' +
      // query string
      '(\\?[;&a-z\\d%_.~+=\\/-]*)?' +
      // fragment locator
      '(\\#[-a-z\\d_]*)?$', 'i')
    return !!pattern.test(url)
  }
  /** Get Capabilities request parameters
   * @param {*} options
   */
  getRequestParam(options) {
    return {
      SERVICE: 'WMS',
      REQUEST: 'GetCapabilities',
      VERSION: options.version || '1.3.0'
    }
  }
  /** Get WMS capabilities for a server
   * @fire load
   * @param {string} url service url
   * @param {*} options
   *  @param {string} options.map WMS map or get map in url?map=xxx
   *  @param {string} [options.version=1.3.0] WMS version (yet only 1.3.0 is implemented), default 1.3.0
   *  @param {number} [options.timeout=10000] timout to get the capabilities, default 10000
   *  @param {function} [options.onload] callback function
   */
  getCapabilities(url, options) {
    if (!url)
      return
    if (!this.testUrl(url)) {
      this.showError({
        type: 'badUrl'
      })
      return
    }

    options = options || {}

    // Extract map attributes
    url = url.split('?')
    var search = url[1]
    url = url[0]

    // reset
    this._elements.formMap.value = ''
    this._elements.formLayer.value = ''
    this._elements.formStyle.value = ''
    this._elements.formTitle.value = ''
    this._elements.formProjection.value = this.getMap().getView().getProjection().getCode()
    this._elements.formFormat.selectedIndex = 0
    var map = options.map || ''
    var optional = {}
    if (search) {
      search = search.replace(/^\?/, '').split('&')
      search.forEach(function (s) {
        s = s.split('=')
        s[1] = decodeURIComponent(s[1] || '')
        if (/^map$/i.test(s[0])) {
          map = s[1]
          this._elements.formMap.value = map
        }
        if (/^layers$/i.test(s[0])) {
          this._elements.formLayer.value = s[1]
          this._elements.formTitle.value = s[1].split(',')[0]
        }
        if (/^style$/i.test(s[0])) {
          this._elements.formStyle.value = s[1]
        }
        if (/^crs$/i.test(s[0])) {
          this._elements.formProjection.value = s[1]
        }
        if (/^format$/i.test(s[0])) {
          for (var o, i = 0; o = this._elements.formFormat.options[i]; i++) {
            if (o.value === s[1]) {
              this._elements.formFormat.selectedIndex = i
              break
            }
          }
        }
        // Check optionals
        if (this.get('optional')) {
          this.get('optional').split(',').forEach(function (o) {
            if (o === s[0]) {
              optional[o] = s[1]
            }
          }.bind(this))
        }
      }.bind(this))
    }
    this._optional = optional;

    // Get request params
    var request = this.getRequestParam(options)
    var opt = []
    if (map) {
      request.MAP = map
      opt.push('map=' + map)
    }
    for (var o in optional) {
      request[o] = optional[o]
      opt.push(o + '=' + optional[o])
    }

    // Fill form
    var uri = this._elements.input.value = (url || '') + (opt ? '?' + opt.join('&') : '')
    this.clearForm()

    // Sen drequest
    if (this._proxy) {
      var q = ''
      for (var r in request)
        q += (q ? '&' : '') + r + '=' + request[r]
      this._ajax.send(this._proxy, {
        url: q
      }, {
        url: uri,
        timeout: options.timeout || 10000,
        callback: options.onload,
        abort: false
      })
    } else {
      this._ajax.send(url, request, {
        url: uri,
        timeout: options.timeout || 10000,
        callback: options.onload,
        abort: false
      })
    }
  }
  /** Display error
   * @param {*} error event
   */
  showError(e) {
    if (!e)
      this._elements.error.innerHTML = ''
    else
      this._elements.error.innerHTML = this.error[e.type] || ('ERROR (' + e.type + ')')
    if (e && e.type === 'load') {
      this._elements.form.classList.add('visible')
    } else {
      this._elements.form.classList.remove('visible')
    }
  }
  /** Clear form
   */
  clearForm() {
    this._elements.result.classList.remove('ol-visible')
    this.showError()
    this._elements.select.innerHTML = ''
    this._elements.data.innerHTML = ''
    this._elements.preview.src = ''
    this._elements.legend.src = ''
    this._elements.legend.classList.remove('visible')
  }
  /** Display capabilities in the dialog
   * @param {*} caps JSON capabilities
   */
  showCapabilities(caps) {
    this._elements.result.classList.add('ol-visible')
    //  console.log(caps)
    var list = []
    var addLayers = function (parent, level) {
      level = level || 0
      parent.Layer.forEach(function (l) {
        if (!l.Attribution) l.Attribution = parent.Attribution
        if (!l.EX_GeographicBoundingBox) l.EX_GeographicBoundingBox = parent.EX_GeographicBoundingBox
        var li = ol_ext_element.create('OPTION', {
          className: (l.Layer ? 'ol-title ' : '') + 'level-' + level,
          html: l.Name || l.Title,
          title: l.Name || l.Title,
          click: function () {
            // Reset
            this._elements.buttons.innerHTML = ''
            this._elements.data.innerHTML = ''
            this._elements.legend.src = this._elements.preview.src = ''
            this._elements.element.classList.remove('ol-form')
            this.showError()
            // Load layer
            var options = this.getOptionsFromCap(l, caps)
            var layer = this.getLayerFromOptions(options)
            this._currentOptions = options
            //
            list.forEach(function (i) {
              i.classList.remove('selected')
            })
            li.classList.add('selected')
            // Fill form
            if (layer) {
              ol_ext_element.create('BUTTON', {
                html: this.get('loadLabel') || 'Load',
                className: 'ol-load',
                click: function () {
                  this.dispatchEvent({ type: 'load', layer: layer, options: options })
                  if (this._dialog)
                    this._dialog.hide()
                }.bind(this),
                parent: this._elements.buttons
              })
              ol_ext_element.create('BUTTON', {
                className: 'ol-wmsform',
                click: function () {
                  this._elements.element.classList.toggle('ol-form')
                }.bind(this),
                parent: this._elements.buttons
              })
              // Show preview
              var reso = this.getMap().getView().getResolution()
              var center = this.getMap().getView().getCenter()
              this._elements.preview.src = layer.getPreview(center, reso, this.getMap().getView().getProjection())
              this._img.src = this._elements.preview.src

              // ShowInfo
              ol_ext_element.create('p', {
                className: 'ol-title',
                html: options.data.title,
                parent: this._elements.data
              })
              ol_ext_element.create('p', {
                html: options.data.abstract,
                parent: this._elements.data
              })
              if (options.data.legend && options.data.legend.length) {
                this._elements.legend.src = options.data.legend[0]
                this._elements.legend.classList.add('visible')
              } else {
                this._elements.legend.src = ''
                this._elements.legend.classList.remove('visible')
              }
            }
          }.bind(this),
          parent: this._elements.select
        })
        list.push(li)
        if (l.Layer) {
          addLayers(l, level + 1)
        }
      }.bind(this))
    }.bind(this)
    // Show layers
    this._elements.select.innerHTML = ''
    addLayers(caps.Capability.Layer)
  }
  /** Get resolution for a layer
   * @param {string} 'min' or 'max'
   * @param {*} layer
   * @param {number} val
   * @return {number}
   * @private
   */
  getLayerResolution(m, layer, val) {
    var att = m === 'min' ? 'MinScaleDenominator' : 'MaxScaleDenominator'

    if (layer[att] !== undefined)
      return layer[att] / (72 / 2.54 * 100)

    if (!layer.Layer)
      return (m === 'min' ? 0 : 156543.03392804097)

    // Get min / max of contained layers
    val = (m === 'min' ? 156543.03392804097 : 0)
    for (var i = 0; i < layer.Layer.length; i++) {
      var res = this.getLayerResolution(m, layer.Layer[i], val)
      if (res !== undefined)
        val = Math[m](val, res)
    }
    return val
  }
  /** Return a WMS ol.layer.Tile for the given capabilities
   * @param {*} caps layer capabilities (read from the capabilities)
   * @param {*} parent capabilities
   * @return {*} options
   */
  getOptionsFromCap(caps, parent) {
    var formats = parent.Capability.Request.GetMap.Format
    var format, i
    // Look for prefered format first
    var pref = [/png/, /jpeg/, /gif/]
    for (i = 0; i < 3; i++) {
      for (var f = 0; f < formats.length; f++) {
        if (pref[i].test(formats[f])) {
          format = formats[f]
          break
        }
      }
      if (format)
        break
    }
    if (!format)
      format = formats[0]

    // Check srs
    var srs = this.getMap().getView().getProjection().getCode()
    this.showError()
    var crs = false
    if (!caps.CRS) {
      crs = false
    } else if (caps.CRS.indexOf(srs) >= 0) {
      crs = true
    } else if (caps.CRS.indexOf('EPSG:4326') >= 0) {
      // try to set EPSG:4326 instead
      srs = 'EPSG:4326'
      crs = true
    } else {
      this.get('srs').forEach(function (s) {
        if (caps.CRS.indexOf(s) >= 0) {
          srs = s
          crs = true
        }
      })
    }
    if (!crs) {
      this.showError({ type: 'srs' })
      if (this.get('trace'))
        console.log('BAD srs: ', caps.CRS)
    }

    var bbox = caps.EX_GeographicBoundingBox
    //bbox = ol_proj_transformExtent(bbox, 'EPSG:4326', srs);
    if (bbox)
      bbox = ol_proj_transformExtent(bbox, 'EPSG:4326', this.getMap().getView().getProjection())

    var attributions = []
    if (caps.Attribution && caps.Attribution.Title) {
      attributions.push('<a href="' + encodeURI(caps.Attribution.OnlineResource) + '">&copy; ' + caps.Attribution.Title.replace(/</g, '&lt;') + '</a>')
    }

    var layer_opt = {
      title: caps.Title,
      extent: bbox,
      queryable: caps.queryable,
      abstract: caps.Abstract,
      minResolution: this.getLayerResolution('min', caps),
      maxResolution: this.getLayerResolution('max', caps) || 156543.03392804097
    }

    var source_opt = {
      url: (parent.Capability.Request.GetMap.DCPType[0].HTTP.Get.OnlineResource || '').replace(/service=wms&?/i,''),
      projection: srs,
      attributions: attributions,
      crossOrigin: this.get('cors') ? 'anonymous' : null,
      params: {
        'LAYERS': caps.Name,
        'FORMAT': format,
        'VERSION': parent.version || '1.3.0'
      }
    }

    Object.keys(this._optional).forEach(o => source_opt.params[o] = this._optional[o])

    // Resolution to zoom
    var view = new ol_View({
      projection: this.getMap().getView().getProjection()
    })
    view.setResolution(layer_opt.minResolution)
    var maxZoom = Math.round(view.getZoom())
    view.setResolution(layer_opt.maxResolution)
    var minZoom = Math.round(view.getZoom())

    // Fill form
    this._fillForm({
      title: layer_opt.title,
      layers: source_opt.params.LAYERS,
      format: source_opt.params.FORMAT,
      minZoom: minZoom,
      maxZoom: maxZoom,
      extent: bbox ? bbox.join(',') : '',
      projection: source_opt.projection,
      attribution: source_opt.attributions[0] || '',
      version: source_opt.params.VERSION
    })

    // Trace
    if (this.get('trace')) {
      var tso = JSON.stringify([source_opt], null, "\t").replace(/\\"/g, '"')
      layer_opt.source = "SOURCE"
      var t = "new ol.layer.Tile (" + JSON.stringify(layer_opt, null, "\t") + ")"
      t = t.replace(/\\"/g, '"')
        .replace('"SOURCE"', "new ol.source.TileWMS(" + tso + ")")
        .replace(/\\t/g, "\t").replace(/\\n/g, "\n")
        .replace("([\n\t", "(")
        .replace("}\n])", "})")
      console.log(t)
      delete layer_opt.source
    }

    // Legend ?
    var legend = []
    if (caps.Style) {
      caps.Style.forEach(function (s) {
        if (s.LegendURL) {
          legend.push(s.LegendURL[0].OnlineResource)
        }
      })
    }

    return ({
      layer: layer_opt,
      source: source_opt,
      data: {
        title: caps.Title,
        abstract: caps.Abstract,
        logo: caps.Attribution && caps.Attribution.LogoURL ? caps.Attribution.LogoURL.OnlineResource : undefined,
        keyword: caps.KeywordList,
        legend: legend,
        opaque: caps.opaque,
        queryable: caps.queryable
      }
    })
  }
  /** Get WMS options from control form
   * @return {*} options
   * @private
   */
  _getFormOptions() {
    var minZoom = parseInt(this._elements.formMinZoom.value)
    var maxZoom = parseInt(this._elements.formMaxZoom.value)
    var view = new ol_View({
      projection: this.getMap().getView().getProjection()
    })
    view.setZoom(minZoom)
    var maxResolution = view.getResolution()
    view.setZoom(maxZoom)
    var minResolution = view.getResolution()
    var ext = []
    if (this._elements.formExtent.value) {
      this._elements.formExtent.value.split(',').forEach(function (b) {
        ext.push(parseFloat(b))
      })
    }
    if (ext.length !== 4)
      ext = undefined
    var attributions = []
    if (this._elements.formAttribution.value)
      attributions.push(this._elements.formAttribution.value)
    var options = {
      layer: {
        title: this._elements.formTitle.value,
        extent: ext,
        maxResolution: maxResolution,
        minResolution: minResolution
      },
      source: {
        url: this._elements.input.value,
        crossOrigin: this._elements.formCrossOrigin.checked ? 'anonymous' : null,
        projection: this._elements.formProjection.value,
        attributions: attributions,
        params: {
          FORMAT: this._elements.formFormat.options[this._elements.formFormat.selectedIndex].value,
          LAYERS: this._elements.formLayer.value,
          VERSION: this._elements.formVersion.value
        }
      },
      data: {
        title: this._elements.formTitle.value
      }
    }

    Object.keys(this._optional).forEach(o => options.source.params[o] = this._optional[o])
    if (this._elements.formMap.value) {
      options.source.params.MAP = this._elements.formMap.value
    }
    return options
  }
  /** Fill dialog form
   * @private
   */
  _fillForm(opt) {
    this._elements.formTitle.value = opt.title
    this._elements.formLayer.value = opt.layers
    this._elements.formStyle.value = opt.style
    var o, i
    for (i = 0; o = this._elements.formFormat.options[i]; i++) {
      if (o.value === opt.format) {
        this._elements.formFormat.selectedIndex = i
        break
      }
    }
    this._elements.formExtent.value = opt.extent || ''
    this._elements.formMaxZoom.value = opt.maxZoom
    this._elements.formMinZoom.value = opt.minZoom
    this._elements.formProjection.value = opt.projection
    this._elements.formAttribution.value = opt.attribution
    this._elements.formVersion.value = opt.version
  }
  /** Load a layer using service
   * @param {string} url service url
   * @param {string} layername
   * @param {function} [onload] callback function (or listen to 'load' event)
   */
  loadLayer(url, layerName, onload) {
    this.getCapabilities(url, {
      onload: function (cap) {
        if (cap) {
          cap.Capability.Layer.Layer.forEach(function (l) {
            if (l.Name === layerName || l.Identifier === layerName) {
              var options = this.getOptionsFromCap(l, cap)
              var layer = this.getLayerFromOptions(options)
              this.dispatchEvent({ type: 'load', layer: layer, options: options })
              if (typeof (onload) === 'function')
                onload({ layer: layer, options: options })
            }
          }.bind(this))
        } else {
          this.dispatchEvent({ type: 'load', error: true })
        }
      }.bind(this)
    })
  }
}

/** Error list: a key/value list of error to display in the dialog 
 * Overwrite it to handle internationalization
 */
ol_control_WMSCapabilities.prototype.error = {
  load: 'Can\'t retrieve service capabilities, try to add it manually...',
  badUrl: 'The input value is not a valid url...',
  TileMatrix: 'No TileMatrixSet supported...',
  noLayer: 'No layer available for this service...',
  srs: 'The service projection looks different from that of your map, it may not display correctly...'
};

/** Form labels: a key/value list of form labels to display in the dialog
 * Overwrite it to handle internationalization
 */
ol_control_WMSCapabilities.prototype.labels = {
  formTitle: 'Title:',
  formLayer: 'Layers:',
  formMap: 'Map:',
  formStyle: 'Style:',
  formFormat: 'Format:',
  formMinZoom: 'Min zoom level:',
  formMaxZoom: 'Max zoom level:',
  formExtent: 'Extent:',
  mapExtent: 'use map extent...',
  formProjection: 'Projection:',
  formCrossOrigin: 'CrossOrigin:',
  formVersion: 'Version:',
  formAttribution: 'Attribution:',
};

export default ol_control_WMSCapabilities
