'use strict';

const Vector2 = require('./vector2');

/**
 * Line Class
 * @property {Vector2} start The start position of the line
 * @property {Vector2} end The end position of the line
 */
class Line {
	/**
	 * @param {Vector2|Object} [p1] Vector2 like object of the start position
	 * @param {Vector2|Object} [p2] Vector2 like object of the end position
	 */
	constructor(...args) {
		this.start = new Vector2.Zero();
		this.end = new Vector2.Zero();
		this._checkParams(args);
	}

	/**
	 * @readonly
	 * @type {Number}
	 */
	get length() {
		return Vector2.Distance(this.end, this.start);
	}

	/**
	 * Get the intersection of this line with an other one
	 * Return false if lines does not intersect
	 * @param {Line} line Second line
	 * @returns boolean|Vector2
	 */
	intersect(line) {
		return Line.Intersect(this, line);
	}

	/**
	 * Get a point on the line from start to end at lerpValue
	 * @param {Number} lerpValue The lerp value, should be between 0 and 1, and it will be clamped
	 * @returns Vector2
	 */
	alongPoint(lerpValue) {
		return Vector2.Lerp(this.start, this.end, lerpValue);
	}

	/**
	 * Get a point on the line from start to end at lerpValue (Unclamped version)
	 * @param {Number} lerpValue The lerp value, should be between 0 and 1, but can be out of bound
	 * @returns Vector2
	 */
	alongPointUnclamped(lerpValue) {
		return Vector2.LerpUnclamped(this.start, this.end, lerpValue);
	}

	/**
	 * Get the intersection of two lines
	 * Return false if lines does not intersect
	 * @param {Line} l1 First line
	 * @param {Line} l2 Second line
	 * @returns boolean|Vector2
	 */
	static Intersect(l1, l2) {
		const p0x = l1.start.x;
		const p0y = l1.start.y;
		const p1x = l1.end.x;
		const p1y = l1.end.y;
		const p2x = l2.start.x;
		const p2y = l2.start.y;
		const p3x = l2.end.x;
		const p3y = l2.end.y;
		const s1x = p1x - p0x;
		const s1y = p1y - p0y;
		const s2x = p3x - p2x;
		const s2y = p3y - p2y;

		const s = ((-s1y * (p0x - p2x)) + (s1x * (p0y - p2y))) / ((-s2x * s1y) + (s1x * s2y));
		const t = ((s2x * (p0y - p2y)) - (s2y * (p0x - p2x))) / ((-s2x * s1y) + (s1x * s2y));

		const p = new Vector2.Zero();
		if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
			p.x = p0x + (t * s1x);
			p.y = p0y + (t * s1y);
			return p;
		}
		return false;
	}

	_checkParams(args) {
		const p1 = Vector2.IsVector2Like(args[0]);
		const p2 = Vector2.IsVector2Like(args[1]);
		if (p1 && p2) {
			this.start = p1;
			this.end = p2;
		} else if (p1) {
			this.end = p1;
		}
	}
}

module.exports = Line;