/*	Copyright (c) 2019 Jean-Marc VIGLINO, 
  released under the CeCILL-B license (French BSD license)
  (http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/

import ol_style_Style from 'ol/style/Style.js'
import ol_style_Stroke from 'ol/style/Stroke.js'
import ol_style_Fill from 'ol/style/Fill.js'
import {asString as ol_color_asString} from 'ol/color.js'
import {ol_coordinate_dist2d} from '../geom/GeomUtils.js'
import { VERSION as ol_util_VERSION } from 'ol/util.js'

/** Profile style
 * Draw a profile on the map
 * @extends {ol_style_Style}
 * @constructor
 * @param {Object} options
 *  @param {ol.style.Stroke} options.stroke 
 *  @param {ol.style.Fill} options.fill 
 *  @param {number} options.scale z scale 
 *  @param {number} options.zIndex 
 *  @param {ol.geom.Geometry} options.geometry 
 *  @param {number} options.vertexSize size of the vertex to draw. Default is 0 (no vertex).
 */
var ol_style_Profile = class olstyleProfile extends ol_style_Style {
  constructor(options) {
    options = options || {}

    super({
      zIndex: options.zIndex,
      geometry: options.geometry
    })
    this.setRenderer(this._render.bind(this))
    
    this.setStroke(options.stroke)
    this.setFill(options.fill)
    this.setScale(options.scale)
    this.setVertexSize(options.vertexSize)

  }
  /** Set style stroke
   * @param {ol.style.Stroke}
   */
  setStroke(stroke) {
    this._stroke = stroke || new ol_style_Stroke({ color: '#fff', width: 1 })
  }
  /** Get style stroke
   * @return {ol.style.Stroke}
   */
  getStroke() {
    return this._stroke
  }
  /** Set style stroke
   * @param {ol.style.Fill}
   */
  setFill(fill) {
    this._fill = fill || new ol_style_Fill({ color: 'rgba(255,255,255,.3' })
  }
  /** Get style stroke
   * @return {ol.style.Fill}
   */
  getFill() {
    return this._fill
  }
  /** Set z scale
   * @param {number}
   */
  setScale(sc) {
    this._scale = sc || .2
  }
  /** Get z scale
   * @return {number}
   */
  getScale() {
    return this._scale
  }
  /** Set the vertex size
   * Use 0 to disable vertex rendering
   * @param {number}
   */
  setVertexSize(ver) {
    this._vertexSize = ver || 0
  }
  /** Get the vertex size
   * @return {number}
   */
  getVertexSize() {
    return this._vertexSize
  }
  /** Renderer function
   * @param {Array<ol.coordinate>} geom The pixel coordinates of the geometry in GeoJSON notation
   * @param {ol.render.State} e The olx.render.State of the layer renderer
   */
  _render(geom, e) {
    if (!/Z/.test(e.feature.getGeometry().getLayout()))
      return
    var g = e.geometry.getCoordinates()
    switch (e.geometry.getType()) {
      case 'LineString': {
        this._renderLine(geom, g, e.feature.getGeometry(), e)
        break
      }
      case 'MultiLineString': {
        e.feature.getGeometry().getLineStrings().forEach(function (l, i) {
          this._renderLine(geom[i], g[i], l, e)
        }.bind(this))
        break
      }
      case 'Point': {
        break
      }
    }
  }
  /** @private */
  _renderLine(geom, g, l, e) {
    var i, p, ctx = e.context

    var cos = parseFloat(ol_util_VERSION) > 9.1 ? 1 : Math.cos(e.rotation)
    var sin = parseFloat(ol_util_VERSION) > 9.1 ? 0 : Math.sin(e.rotation)
    // var a = e.pixelRatio / e.resolution;
    var a = ol_coordinate_dist2d(geom[0], geom[1]) / ol_coordinate_dist2d(g[0], g[1])
    var dx = geom[0][0] - g[0][0] * a * cos - g[0][1] * a * sin
    var dy = geom[0][1] - g[0][0] * a * sin + g[0][1] * a * cos
    geom = l.getCoordinates()
    var dz = Infinity
    for (i = 0; p = geom[i]; i++) {
      var x = dx + p[0] * a * cos + p[1] * a * sin
      var y = dy + p[0] * a * sin - p[1] * a * cos
      var z = p[2]
      if (typeof z === 'number') {
        dz = Math.min(dz, z)
      }
      geom[i] = [x, y, z]
    }

    ctx.save()

    ctx.fillStyle = ol_color_asString(this.getFill().getColor())
    ctx.strokeStyle = ol_color_asString(this.getStroke().getColor())
    ctx.lineWidth = this.getStroke().getWidth()

    var p0 = geom[0]
    var ez = this.getScale() * e.pixelRatio

    for (i = 1; p = geom[i]; i++) {
      ctx.beginPath()
      ctx.moveTo(p0[0], p0[1])
      ctx.lineTo(p[0], p[1])
      if (typeof p[2] === 'number') {
        ctx.lineTo(p[0], p[1] - (p[2] - dz) * ez)
        ctx.lineTo(p0[0], p0[1] - (p0[2] - dz) * ez)
      }
      ctx.lineTo(p0[0], p0[1])
      ctx.fill()
      p0 = p
    }

    var vertexSize = this.getVertexSize();
    if (vertexSize) {
      // draw vertex on top of the lines
      ctx.beginPath();
      // draw first vertex before loop
      var p0 = geom[0];
      var y0 = p0[1] - (p0[2] - dz) * ez;
      ctx.arc(p0[0], y0, vertexSize, 0, 2 * Math.PI);
      ctx.moveTo(p0[0] + vertexSize, y0);

      for (i = 1; p = geom[i]; i++) {
        if (typeof p[2] === 'number' ) {
          var yElev = p[1] - (p[2] - dz) * ez;
          ctx.arc(p[0], yElev, vertexSize, 0, 2 * Math.PI);
          ctx.moveTo(p[0] + vertexSize, yElev);
        }
      }
      ctx.fill();
    }

    p0 = geom[0]
    ctx.beginPath()
    ctx.moveTo(p0[0], p0[1] - (p0[2] - dz) * ez)
    for (i = 1; p = geom[i]; i++) {
      ctx.lineTo(p[0], p[1] - (p[2] - dz) * ez)
    }
    ctx.stroke()

    ctx.restore()
  }
}

export default ol_style_Profile
