export default class PatternedLine {
	constructor(pattern = null, phase = 0) {
		this.pattern = pattern;
		this.dw = pattern && pattern.partWidth;
		this.points = [];
		this.phase = phase;
		this.x = null;
		this.y = null;
		this.disconnect = 0;
	}

	_nextDelta() {
		return this.pattern.getDelta(this.phase ++);
	}

	_link() {
		if(this.disconnect === 2) {
			this.points.push(this.x + ' ' + this.y);
			this.disconnect = 0;
		}
	}

	cap() {
		if(this.disconnect > 0) {
			this.points.push(this.x + ' ' + this.y);
			this.disconnect = 0;
		}
		return this;
	}

	move(x, y) {
		this.cap();
		this.x = x;
		this.y = y;
		this.disconnect = 2;
		return this;
	}

	line(x, y, {patterned = true} = {}) {
		if(this.pattern && patterned) {
			const len = Math.sqrt(
				(x - this.x) * (x - this.x) +
				(y - this.y) * (y - this.y),
			);
			const dx1 = (x - this.x) / len;
			const dy1 = (y - this.y) / len;
			const dx2 = -dy1;
			const dy2 = dx1;

			for(let pos = 0; pos + this.dw <= len; pos += this.dw) {
				const delta = this._nextDelta();
				this.points.push(
					(this.x + pos * dx1 + delta * dx2) + ' ' +
					(this.y + pos * dy1 + delta * dy2),
				);
			}
			this.disconnect = 1;
		} else {
			this._link();
			this.disconnect = 2;
		}

		this.x = x;
		this.y = y;
		return this;
	}

	arc(cx, cy, theta) {
		const radius = Math.sqrt(
			(cx - this.x) * (cx - this.x) +
			(cy - this.y) * (cy - this.y),
		);
		const theta1 = Math.atan2(this.x - cx, cy - this.y);
		const nextX = cx + Math.sin(theta1 + theta) * radius;
		const nextY = cy - Math.cos(theta1 + theta) * radius;

		if(this.pattern) {
			const dir = (theta < 0 ? 1 : -1);
			const dt = this.dw / radius;

			for(let t = theta1; t + dt <= theta1 + theta; t += dt) {
				const delta = this._nextDelta() * dir;
				this.points.push(
					(cx + Math.sin(t) * (radius + delta)) + ' ' +
					(cy - Math.cos(t) * (radius + delta)),
				);
			}
			this.disconnect = 1;
		} else {
			this.points.push(
				this.x + ' ' + this.y +
				'A' + radius + ' ' + radius + ' 0 ' +
				((Math.abs(theta) >= Math.PI) ? '1 ' : '0 ') +
				((theta < 0) ? '0 ' : '1 ') +
				nextX + ' ' + nextY,
			);
			this.disconnect = 0;
		}

		this.x = nextX;
		this.y = nextY;

		return this;
	}

	asPath() {
		this._link();
		return 'M' + this.points.join('L');
	}
}
