/** @internal */
declare let _debug_: Debug; 

import { drawFs } from 'flo-draw';
import { equal, getObjClosestTo } from 'flo-vector2d';
import { Debug } from '../debug.js';
import { ThreeProngForDebugging } from '../three-prong-for-debugging.js';


/** @internal */
export interface IThreeProngDebugFunctions {
	drawSpokes       : (g: SVGGElement, n: number) => void,
	traceConvergence : (g: SVGGElement, n: number, indx: number) => void,
	showBoundary     : (g: SVGGElement, n: number, indx: number) => void,
	logδs            : (n: number) => void,
	logNearest       : (
			showSpokes?     : boolean,
			showTrace?      : boolean,
			showBoundaries? : boolean
	) => (g: SVGGElement, p: number[], showDelay?: number) => void
}


/**
 * @internal
 * Draws 3 lines from the given 3-prong center to its 3 contact points.
 * @param n - The 3-prong's zero-based index. 
 */
function drawSpokes(g: SVGGElement, n: number): void {
	const threeProng = _debug_.generated.elems.threeProng[n]; 
	const cc = threeProng.circle.center;
	const poss = threeProng.poss;

	for (let i=0; i<poss.length; i++) {
		const pos = poss[i];
		drawFs.line(g, [pos.p, cc], 'thin5 red');
	}
}


/**
 * @internal
 * Shows the circle for each boundary iteration.
 * @param n_ - The 3-prong's zero-based index. If ommitted, all will be shown.
 * @param idx - The specific boundary iteration index to view. If ommitted, all
 * will be shown.
 */
function traceConvergence(g: SVGGElement, n_: number, idx: number): void {
	let sIndx;
	let eIndx;
	if (n_ === undefined) {
		sIndx = 0;
		eIndx = _debug_.generated.elems.threeProng.length;
	} else {
		sIndx = n_;
		eIndx = n_ + 1;
	}
	
	for (let n=sIndx; n<eIndx; n++) {

		const forDebugging = _debug_.generated.elems.threeProng[n];
		//const g = forDebugging.generated.g;
		
		console.log(forDebugging);
		
		const candidateThreeProngs = forDebugging.candidateThreeProngs;
		
		//-----------------------------
		//---- Get start and end index
		//-----------------------------
		let startIndx;
		let endIndx;
		if (n_ === undefined || idx === -1) {
			startIndx = forDebugging.bestIndx;
			endIndx   = forDebugging.bestIndx + 1;
		} else {
			if (idx === undefined) {
				startIndx = 0;
				endIndx   = candidateThreeProngs.length;
			} else {
				startIndx = idx;
				endIndx   = idx + 1;
			}	
		}

		//---------------------------------
		//---- Draw candidate three-prongs
		//---------------------------------
		for (let i=startIndx; i<endIndx; i++) {
			const circle = candidateThreeProngs[i].circle;
			if (forDebugging.bestIndx === i) {
				drawFs.dot(g, circle.center, 0.2, 'green');
				drawFs.circle(g, circle, 'black thin10 nofill');	
			} else {
				drawFs.dot(g, circle.center, 0.2, 'cyan');
				drawFs.circle(g, circle, 'cyan thin5 nofill');
			}
		}
	}
}


/**
 * @internal
 * Shows the actual boundary for each iteration.
 * @param n The 3-prong's zero-based index.
 * @param idx The specific boundary iteration index to view. If ommitted will 
 * show all.
 */
function showBoundary(g: SVGGElement, n: number, idx: number): void {
	const debugInfo = _debug_.generated.elems.threeProng[n];
	//const g = debugInfo.generated.g;
	
	const candidateThreeProngs = debugInfo.candidateThreeProngs;
	
	const startIndx = idx === undefined ? 0 : idx;
	const endIndx   = idx === undefined ? candidateThreeProngs.length : idx;
	
	// Draw relevant δs
	const cpss = debugInfo.cpss;
	let j = 0;
	// For each iteration of δ3s (indexed by j)
	for (let idx=1; idx<cpss.length-1; idx++) {
		
		if (!(j >= startIndx && j <= endIndx)) {
			j++;
			continue; 
		}
		
		const δ3s = [
			cpss[0], 
			cpss[idx], 
			cpss[cpss.length-1]
		];
		
		
		// For each of the 3 δs
		for (let i=0; i<3; i++) {
			const δ = δ3s[i];
			const δS = δ[0]; // Delta Start
			const δE = δ[1]; // Delta End
			
			const posS = δS.cp.pointOnShape;
			const posE = δE.cp.pointOnShape;
			
			const pS = posS.p;
			const pE = posE.p;
			
			const r = 1 + (i*0.5);
			
			if (equal(pS, pE)) {
				drawFs.crossHair(g, pS, 'red thin10 nofill', r); 
			} else {
				drawFs.crossHair(g, pS, 'green thin10 nofill', r);
				drawFs.crossHair(g, pE, 'blue thin10 nofill', r);
			}
		}
		
		j++;
	}
}


/**
 * @internal
 * @param n The 3-prong's zero-based index. 
 */
function logδs(n: number): void {
	const threeProng = _debug_.generated.elems.threeProng[n];
	
	console.log(threeProng.cpss);		
}


/**
 * @internal
 * @param p
 */
function logNearest(
		showSpokes = true,
		showTrace = true,
		showBoundaries = true) {

	return function(g: SVGGElement, p: number[], showDelay = 1000) {
		const generated = _debug_.generated;

		const threeProng = getObjClosestTo<ThreeProngForDebugging>(
			p, 
			generated.elems.threeProng, 
			threeProng => threeProng.circle ? threeProng.circle.center : [0,0]
		)!;


		const circle = threeProng.circle;
		//const g = threeProng.generated.g;
		
		console.log(threeProng);

		const circle2 = {
			center: circle.center,
			radius: circle.radius || 1
		};

		//const draw = _debug_.fs.draw;

		drawFs.circle(g, circle2, 'blue thin10 nofill', showDelay);
		drawFs.crossHair(g, circle.center, 'red thin2 nofill', 2, showDelay);

		if (showSpokes) {
			drawFs.line(g, [threeProng.poss[0].p, circle.center], 'blue thin5 nofill', showDelay);
			drawFs.line(g, [threeProng.poss[1].p, circle.center], 'blue thin5 nofill', showDelay);
			drawFs.line(g, [threeProng.poss[2].p, circle.center], 'blue thin5 nofill', showDelay);
		}


		if (showBoundaries) {
			const boundaries = threeProng.boundaries;
			const boundaryS = boundaries[0];
			const boundaryE = boundaries[boundaries.length-1];

			drawFs.beziers(g, boundaryS, 'red thin20 nofill', showDelay);
			for (let i=1; i<boundaries.length-1; i++) {
				const boundary = boundaries[i];
				drawFs.beziers(g, boundary, 'green thin20 nofill', showDelay);
			}
			drawFs.beziers(g, boundaryE, 'blue thin20 nofill', showDelay);
		}

		if (showTrace) {
			const traces = threeProng.traces;
			for (const trace of traces) {
				drawFs.polyline(g, trace, 'red thin5 nofill', showDelay)
			}
		}
	}
}


/** @internal */
const threeProngDebugFunctions: IThreeProngDebugFunctions = {
	drawSpokes,
	traceConvergence,
	showBoundary,
	logδs,
	logNearest
}	
	

export { threeProngDebugFunctions }
