import { GUI } from 'lil-gui';


const DEFAULTS = {
	nodesize: 0.6,
	nodeopacity: 1,
	linksize: 1.0,
	linkopacity: 0.75,
	shape: '120-cell',
	link2opacity: 0.75,
	option: 'none',
	visibility: 5,
	inscribed: false,
	inscribe_all: false,
	colour: 0x3293a9,
	background: 0xd4d4d4,
	hyperplane: 0.93,
	zoom: 1,
	xRotate: 'YZ',
	yRotate: 'XZ',
	dtheta: 0,
	damping: false,
	captions: true,
	dpsi: 0,
}



class FourDGUI {

	constructor(funcs) {
                this.shapes = funcs.shapes;
		this.gui = new GUI();
		const SHAPE_NAMES = this.shapes.map((s) => s.name);

		this.parseLinkParams();
		const guiObj = this;
		this.params = {
			shape: this.link['shape'],
			option: this.link['option'],
			inscribed: this.link['inscribed'],
			inscribe_all: this.link['inscribe_all'],
			linksize: this.link['linksize'],
			linkopacity: this.link['linkopacity'],
			link2opacity: this.link['link2opacity'],
			nodesize: this.link['nodesize'],
			nodeopacity: this.link['nodeopacity'],
			depth: this.link['depth'],
			colour: this.link['colour'],
			background: this.link['background'],
			hyperplane: this.link['hyperplane'],
			zoom: this.link['zoom'],
			xRotate: this.link['xRotate'],
			yRotate: this.link['yRotate'],
			damping: false,
			captions: true,
			dtheta: this.link['dtheta'],
			dpsi: this.link['dpsi'],
			"copy link": function () { guiObj.copyUrl() },
		};
		if( funcs.extras ) {
    		    for( const label in funcs.extras ) {
    		        this.params[label] = funcs.extras[label];
    		    }
		}
		let options_ctrl;
		this.gui.add(this.params, 'shape', SHAPE_NAMES).onChange((shape) => {
			const options = this.getShapeOptions(shape);
			options_ctrl = options_ctrl.options(options).onChange((option) => {
				funcs.setVisibility(option)
			});
			options_ctrl.setValue(options[0])
			funcs.changeShape(shape)
		});
		const options = this.getShapeOptions(this.params['shape']);
		options_ctrl = this.gui.add(this.params, 'option').options(options).onChange((option) => {
			funcs.setVisibility(option)
		});
		this.gui.add(this.params, 'hyperplane', 0.5, 1 / 0.8);
		this.gui.add(this.params, 'zoom', 0.1, 2.0);
		this.gui.add(this.params, 'nodesize', 0, 1.5);
		this.gui.add(this.params, 'nodeopacity', 0, 1).onChange(funcs.setNodeOpacity);
		this.gui.add(this.params, 'linksize', 0, 2);
		this.gui.add(this.params, 'linkopacity', 0, 1).onChange((v) => funcs.setLinkOpacity(v, true));
		this.gui.add(this.params, 'link2opacity', 0, 1).onChange((v) => funcs.setLinkOpacity(v, false));
		this.gui.addColor(this.params, 'colour').onChange(funcs.setColours);
		this.gui.addColor(this.params, 'background').onChange(funcs.setBackground);
		this.gui.add(this.params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]);
		this.gui.add(this.params, 'yRotate', [ 'XZ', 'XY', 'XW' ]);
		this.gui.add(this.params, 'captions').onChange(this.showDocs);
		this.gui.add(this.params, 'damping');
		this.gui.add(this.params, 'copy link');
		if( funcs.extras ) {
     		    for( const label in funcs.extras ) {
    		        this.gui.add(this.params, label);
     		    }
                }
	}

	getShapeOptions(shape) {
		const spec = this.shapes.filter((s) => s.name === shape);
		if( spec && spec[0].options ) {
			return spec[0].options.map((o) => o.name);
		} else {
			return [];
		}
	}


	numParam(param, parser) {
		const value = this.urlParams.get(param);
		if( value ) {
			const n = parser(value);
			if( n !== NaN ) {
				return n;
			}
		}
		return DEFAULTS[param];
	}

	stringToHex(cstr) {
		return parseInt('0x' + cstr.substr(1));
	}

	hexToString(hex) {
		return '#' + hex.toString(16);
	}



	parseLinkParams() {
		this.linkUrl = new URL(window.location.toLocaleString());
		this.link = {};
		const guiObj = this;

		this.urlParams = this.linkUrl.searchParams;
		for( const param of [ "shape", "xRotate", "yRotate", "option" ]) {
			const value = this.urlParams.get(param);
			if( value ) {
				this.link[param] = value;
			} else {
				this.link[param] = DEFAULTS[param];
			}
		}
		for( const param of [ "inscribed", "inscribe_all"] ) {
			this.link[param] = ( this.urlParams.get(param) === 'y' );
		}
		this.link['hyperplane'] = this.numParam('hyperplane', parseFloat);
		this.link['zoom'] = this.numParam('zoom', parseFloat);
		this.link['linksize'] = this.numParam('linksize', parseFloat);
		this.link['linkopacity'] = this.numParam('linkopacity', parseFloat);
		this.link['link2opacity'] = this.numParam('link2opacity', parseFloat);
		this.link['nodesize'] = this.numParam('nodesize', parseFloat);
		this.link['nodeopacity'] = this.numParam('nodeopacity', parseFloat);
		this.link['colour'] = this.numParam('colour', (s) => guiObj.stringToHex(s));
		this.link['background'] = this.numParam('background', (s) => guiObj.stringToHex(s));
		this.link['dpsi'] = this.numParam('dpsi', parseFloat);
		this.link['dtheta'] = this.numParam('dtheta', parseFloat);
	}


	copyUrl() {
		const url = new URL(this.linkUrl.origin + this.linkUrl.pathname);
		url.searchParams.append("shape", this.params.shape);
		url.searchParams.append("option", this.params.option);
		url.searchParams.append("inscribed", this.params.inscribed ? 'y': 'n');
		url.searchParams.append("inscribe_all", this.params.inscribe_all ? 'y': 'n');
		url.searchParams.append("linksize", this.params.linksize.toString());
		url.searchParams.append("nodesize", this.params.nodesize.toString());
		url.searchParams.append("nodeopacity", this.params.nodesize.toString());
		url.searchParams.append("linkopacity", this.params.nodeopacity.toString());
		url.searchParams.append("colour", this.hexToString(this.params.colour));
		url.searchParams.append("background", this.hexToString(this.params.background));
		url.searchParams.append("hyperplane", this.params.hyperplane.toString());
		url.searchParams.append("zoom", this.params.zoom.toString());
		url.searchParams.append("xRotate", this.params.xRotate);
		url.searchParams.append("yRotate", this.params.yRotate);
		url.searchParams.append("dtheta", this.params.dtheta.toString());
		url.searchParams.append("dpsi", this.params.dpsi.toString());
		this.copyTextToClipboard(url);
	}


	copyTextToClipboard(text) {
 		if (!navigator.clipboard) {
    		this.fallbackCopyTextToClipboard(text);
    		return;
  		}
  		navigator.clipboard.writeText(text).then(function() {
  		}, function(err) {
    	console.error('Async: Could not copy text: ', err);
  		});
	}


	fallbackCopyTextToClipboard(text) {
		var textArea = document.createElement("textarea");
		textArea.value = text;
		  
		// Avoid scrolling to bottom
		textArea.style.top = "0";
		textArea.style.left = "0";
		textArea.style.position = "fixed";

		document.body.appendChild(textArea);
		textArea.focus();
		textArea.select();

		try {
		    var successful = document.execCommand('copy');
		    var msg = successful ? 'successful' : 'unsuccessful';
		    console.log('Fallback: Copying text command was ' + msg);
		} catch (err) {
		    console.error('Fallback: Oops, unable to copy', err);
		}

		document.body.removeChild(textArea);
	}


}


export { FourDGUI, DEFAULTS };
