'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _index = require('../index.js');

var _index2 = _interopRequireDefault(_index);

var _array = require('../array.js');

var _array2 = _interopRequireDefault(_array);

var _extent = require('../extent.js');

var _extent2 = _interopRequireDefault(_extent);

var _geometrylayout = require('../geom/geometrylayout.js');

var _geometrylayout2 = _interopRequireDefault(_geometrylayout);

var _geometrytype = require('../geom/geometrytype.js');

var _geometrytype2 = _interopRequireDefault(_geometrytype);

var _simplegeometry = require('../geom/simplegeometry.js');

var _simplegeometry2 = _interopRequireDefault(_simplegeometry);

var _closest = require('../geom/flat/closest.js');

var _closest2 = _interopRequireDefault(_closest);

var _deflate = require('../geom/flat/deflate.js');

var _deflate2 = _interopRequireDefault(_deflate);

var _inflate = require('../geom/flat/inflate.js');

var _inflate2 = _interopRequireDefault(_inflate);

var _interpolate = require('../geom/flat/interpolate.js');

var _interpolate2 = _interopRequireDefault(_interpolate);

var _intersectsextent = require('../geom/flat/intersectsextent.js');

var _intersectsextent2 = _interopRequireDefault(_intersectsextent);

var _length = require('../geom/flat/length.js');

var _length2 = _interopRequireDefault(_length);

var _segments = require('../geom/flat/segments.js');

var _segments2 = _interopRequireDefault(_segments);

var _simplify = require('../geom/flat/simplify.js');

var _simplify2 = _interopRequireDefault(_simplify);

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };
}

/**
 * @classdesc
 * Linestring geometry.
 *
 * @constructor
 * @extends {ol.geom.SimpleGeometry}
 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
 * @api
 */
var _ol_geom_LineString_ = function (coordinates, opt_layout) {

  _simplegeometry2.default.call(this);

  /**
   * @private
   * @type {ol.Coordinate}
   */
  this.flatMidpoint_ = null;

  /**
   * @private
   * @type {number}
   */
  this.flatMidpointRevision_ = -1;

  /**
   * @private
   * @type {number}
   */
  this.maxDelta_ = -1;

  /**
   * @private
   * @type {number}
   */
  this.maxDeltaRevision_ = -1;

  this.setCoordinates(coordinates, opt_layout);
};

_index2.default.inherits(_ol_geom_LineString_, _simplegeometry2.default);

/**
 * Append the passed coordinate to the coordinates of the linestring.
 * @param {ol.Coordinate} coordinate Coordinate.
 * @api
 */
_ol_geom_LineString_.prototype.appendCoordinate = function (coordinate) {
  if (!this.flatCoordinates) {
    this.flatCoordinates = coordinate.slice();
  } else {
    _array2.default.extend(this.flatCoordinates, coordinate);
  }
  this.changed();
};

/**
 * Make a complete copy of the geometry.
 * @return {!ol.geom.LineString} Clone.
 * @override
 * @api
 */
_ol_geom_LineString_.prototype.clone = function () {
  var lineString = new _ol_geom_LineString_(null);
  lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
  return lineString;
};

/**
 * @inheritDoc
 */
_ol_geom_LineString_.prototype.closestPointXY = function (x, y, closestPoint, minSquaredDistance) {
  if (minSquaredDistance < _extent2.default.closestSquaredDistanceXY(this.getExtent(), x, y)) {
    return minSquaredDistance;
  }
  if (this.maxDeltaRevision_ != this.getRevision()) {
    this.maxDelta_ = Math.sqrt(_closest2.default.getMaxSquaredDelta(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
    this.maxDeltaRevision_ = this.getRevision();
  }
  return _closest2.default.getClosestPoint(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
};

/**
 * Iterate over each segment, calling the provided callback.
 * If the callback returns a truthy value the function returns that
 * value immediately. Otherwise the function returns `false`.
 *
 * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function
 *     called for each segment.
 * @param {S=} opt_this The object to be used as the value of 'this'
 *     within callback.
 * @return {T|boolean} Value.
 * @template T,S
 * @api
 */
_ol_geom_LineString_.prototype.forEachSegment = function (callback, opt_this) {
  return _segments2.default.forEach(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, callback, opt_this);
};

/**
 * Returns the coordinate at `m` using linear interpolation, or `null` if no
 * such coordinate exists.
 *
 * `opt_extrapolate` controls extrapolation beyond the range of Ms in the
 * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
 * M will return the first coordinate and Ms greater than the last M will
 * return the last coordinate.
 *
 * @param {number} m M.
 * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
 * @return {ol.Coordinate} Coordinate.
 * @api
 */
_ol_geom_LineString_.prototype.getCoordinateAtM = function (m, opt_extrapolate) {
  if (this.layout != _geometrylayout2.default.XYM && this.layout != _geometrylayout2.default.XYZM) {
    return null;
  }
  var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;
  return _interpolate2.default.lineStringCoordinateAtM(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, m, extrapolate);
};

/**
 * Return the coordinates of the linestring.
 * @return {Array.<ol.Coordinate>} Coordinates.
 * @override
 * @api
 */
_ol_geom_LineString_.prototype.getCoordinates = function () {
  return _inflate2.default.coordinates(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};

/**
 * Return the coordinate at the provided fraction along the linestring.
 * The `fraction` is a number between 0 and 1, where 0 is the start of the
 * linestring and 1 is the end.
 * @param {number} fraction Fraction.
 * @param {ol.Coordinate=} opt_dest Optional coordinate whose values will
 *     be modified. If not provided, a new coordinate will be returned.
 * @return {ol.Coordinate} Coordinate of the interpolated point.
 * @api
 */
_ol_geom_LineString_.prototype.getCoordinateAt = function (fraction, opt_dest) {
  return _interpolate2.default.lineString(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, fraction, opt_dest);
};

/**
 * Return the length of the linestring on projected plane.
 * @return {number} Length (on projected plane).
 * @api
 */
_ol_geom_LineString_.prototype.getLength = function () {
  return _length2.default.lineString(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};

/**
 * @return {Array.<number>} Flat midpoint.
 */
_ol_geom_LineString_.prototype.getFlatMidpoint = function () {
  if (this.flatMidpointRevision_ != this.getRevision()) {
    this.flatMidpoint_ = this.getCoordinateAt(0.5, this.flatMidpoint_);
    this.flatMidpointRevision_ = this.getRevision();
  }
  return this.flatMidpoint_;
};

/**
 * @inheritDoc
 */
_ol_geom_LineString_.prototype.getSimplifiedGeometryInternal = function (squaredTolerance) {
  var simplifiedFlatCoordinates = [];
  simplifiedFlatCoordinates.length = _simplify2.default.douglasPeucker(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, squaredTolerance, simplifiedFlatCoordinates, 0);
  var simplifiedLineString = new _ol_geom_LineString_(null);
  simplifiedLineString.setFlatCoordinates(_geometrylayout2.default.XY, simplifiedFlatCoordinates);
  return simplifiedLineString;
};

/**
 * @inheritDoc
 * @api
 */
_ol_geom_LineString_.prototype.getType = function () {
  return _geometrytype2.default.LINE_STRING;
};

/**
 * @inheritDoc
 * @api
 */
_ol_geom_LineString_.prototype.intersectsExtent = function (extent) {
  return _intersectsextent2.default.lineString(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, extent);
};

/**
 * Set the coordinates of the linestring.
 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
 * @override
 * @api
 */
_ol_geom_LineString_.prototype.setCoordinates = function (coordinates, opt_layout) {
  if (!coordinates) {
    this.setFlatCoordinates(_geometrylayout2.default.XY, null);
  } else {
    this.setLayout(opt_layout, coordinates, 1);
    if (!this.flatCoordinates) {
      this.flatCoordinates = [];
    }
    this.flatCoordinates.length = _deflate2.default.coordinates(this.flatCoordinates, 0, coordinates, this.stride);
    this.changed();
  }
};

/**
 * @param {ol.geom.GeometryLayout} layout Layout.
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 */
_ol_geom_LineString_.prototype.setFlatCoordinates = function (layout, flatCoordinates) {
  this.setFlatCoordinatesInternal(layout, flatCoordinates);
  this.changed();
};
exports.default = _ol_geom_LineString_;
module.exports = exports['default'];