'use strict';

const Curve = require('./curve');
const Vector2 = require('./vector2');
/**
 * BezierCurve Class
 */
class BezierCurve extends Curve {
	/**
     * Create a bezier curve
	 * @param {Vector2} first The first point of the curve
	 * @param {Vector2} last The last point of the curve
	 * @param {Vector2[]} [controllers] Controllers points of the curve
	 * @param {Number} [segmentsCount] Segment count for polygon conversion and drawing
	 */
	constructor(first, last, controllers = [], segmentsCount = 100) {
		super();
		this._first = first;
		this._last = last;
		this._controllers = controllers;
		this._segmentsCount = parseInt(segmentsCount) || 1;
		this._calc();
	}

	/**
	 * The first point of the curve
	 * @type {Vector2}
	 */
	get first() {
		return this._first;
	}

	/**
	 * The last point of the curve
	 * @type {Vector2}
	 */
	get last() {
		return this._last;
	}

	/**
	 * Controllers of the curve
	 * @type {Vector2[]}
	 */
	get controllers() {
		return this._controllers;
	}

	/**
	 * Segment count for the curve calc (for line display)
	 * @type {Number}
	 */
	get segmentsCount() {
		return this._segmentsCount;
	}

	set first(value) {
		this._first = value;
		this._calc();
	}

	set last(value) {
		this._last = value;
		this._calc();
	}

	set controllers(value) {
		this._controllers = value;
		this._calc();
	}

	set segmentsCount(value) {
		this._segmentsCount = value;
		this._calc();
	}

	_calc() {
		this._points = [];
		let prevPt = null;
		for (let si = 0; si <= this.segmentsCount; si++) {
			const t = si / this.segmentsCount;
			let pts = [this.first, ...this.controllers, this.last];
			do {
				const tmpPts = [];
				let prev = null;
				for (const pt of pts) {
					if (prev) {
						tmpPts.push(Vector2.Lerp(prev, pt, t));
					}
					prev = pt;
				}
				pts = tmpPts;
			} while (pts.length > 1);
			const nextPt = pts.shift();
			if (nextPt) {
				if (prevPt) {
					nextPt.prev = prevPt;
					prevPt.next = nextPt;
				}
				this._points.push(nextPt);
				prevPt = nextPt;
			}
		}
		this._points[this._points.length - 1].next = this._next;
		this._points[0].prev = this._prev;
	}
}

module.exports = BezierCurve;