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

	Usefull function to handle geometric operations
*/
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/

import ol_geom_MultiLineString from 'ol/geom/MultiLineString.js'
import ol_geom_Polygon from 'ol/geom/Polygon.js'
import ol_geom_MultiPolygon from 'ol/geom/MultiPolygon.js'
import '../render/Cspline.js'
import { ol_coordinate_splitH } from "./GeomUtils.js";

/**
 * Calculate a MultiPolyline to fill a Polygon with a scribble effect that appears hand-made
 * @param {} options
 *  @param {Number} options.interval interval beetween lines
 *  @param {Number} options.angle hatch angle in radian, default PI/2
 * @return {ol_geom_MultiLineString|null} the resulting MultiLineString geometry or null if none
 */
ol_geom_MultiPolygon.prototype.scribbleFill = function (options) {
  var scribbles = [];
  var poly = this.getPolygons();
  var i, p, s;
  for (i=0; p=poly[i]; i++) {
    var mls = p.scribbleFill(options);
    if (mls) scribbles.push(mls);
  } 
  if (!scribbles.length) return null;
  // Merge scribbles
  var scribble = scribbles[0];
    var ls;
    for (i = 0; s = scribbles[i]; i++) {
      ls = s.getLineStrings();
      for (var k = 0; k < ls.length; k++) {
        scribble.appendLineString(ls[k]);
      }
    }
  return scribble;
};

/**
 * Calculate a MultiPolyline to fill a Polygon with a scribble effect that appears hand-made
 * @param {} options
 *  @param {Number} options.interval interval beetween lines
 *  @param {Number} options.angle hatch angle in radian, default PI/2
 * @return {ol_geom_MultiLineString|null} the resulting MultiLineString geometry or null if none
 */
ol_geom_Polygon.prototype.scribbleFill = function (options) {
	var step = options.interval;
  var angle = options.angle || Math.PI/2;
  var i, k,l;
  
  // Geometry + rotate
	var geom = this.clone();
	geom.rotate(angle, [0,0]);
  var coords = geom.getCoordinates();
  // Merge holes
  var coord = coords[0];
  for (i=1; i<coords.length; i++) {
    // Add a separator
    coord.push([]);
    // Add the hole
    coord = coord.concat(coords[i]);
  }
  // Extent 
	var ext = geom.getExtent();
  
	// Split polygon with horizontal lines
  var lines = [];
	for (var y = (Math.floor(ext[1]/step)+1)*step; y<ext[3]; y += step) {
    l = ol_coordinate_splitH(coord, y, i);
    lines = lines.concat(l);
  }
  
  if (!lines.length) return null;
  // Order lines on segment index
  var mod = coord.length-1;
	var first = lines[0][0].index;
	for (k=0; l=lines[k]; k++) {
		lines[k][0].index = (lines[k][0].index-first+mod) % mod;
		lines[k][1].index = (lines[k][1].index-first+mod) % mod;
	}

  var scribble = [];

  while (true) {
    for (k=0; l=lines[k]; k++) {
      if (!l[0].done) break;
    }
    if (!l) break;
    var scrib = [];
    while (l) {
      l[0].done = true;
      scrib.push(l[0].pt);
      scrib.push(l[1].pt);
      var nexty = l[0].pt[1] + step;
      var d0 = Infinity;
      var l2 = null;
      while (lines[k]) {
        if (lines[k][0].pt[1] > nexty) break;
        if (lines[k][0].pt[1] === nexty) {
          var d = Math.min(
            (lines[k][0].index - l[0].index + mod) % mod,
            (l[0].index - lines[k][0].index + mod) % mod
          );
          var d2 = Math.min(
            (l[1].index - l[0].index + mod) % mod,
            (l[0].index - l[1].index + mod) % mod
          );
          if (d<d0 && d<d2) {
            d0 = d;
            if (!lines[k][0].done) l2 = lines[k];
            else l2 = null;
          }
        }
        k++;
      }
      l = l2;
    }
    if (scrib.length) {
      scribble.push(scrib);
    }
  }

  // Return the scribble as MultiLineString
  if (!scribble.length) return null;
  var mline = new ol_geom_MultiLineString(scribble);
  mline.rotate(-angle,[0,0]);
	return mline.cspline({ pointsPerSeg:8, tension:.9 });
};

/** Calculate a MultiPolyline to fill a geomatry (Polygon or MultiPolygon) with a scribble effect that appears hand-made
 * @param {ol_geom_Geometry} geom the geometry to scribble
 * @param {Object} options
 *  @param {Number} options.interval interval beetween lines
 *  @param {Number} options.angle hatch angle in radian, default PI/2
 * @return {ol_geom_Geometry} the resulting MultiLineString geometry or initial geometry
 */
var ol_geom_scribbleFill = function(geom, options) {
  switch (geom.getType()) {
    case 'Polygon': {
      return ol_geom_Polygon.prototype.scribbleFill.call(geom, options)
    }
    case 'MultiPolygon': {
      return ol_geom_MultiPolygon.prototype.scribbleFill.call(geom, options)
    }
    default: return geom
  }
}

export default ol_geom_scribbleFill