//implementation following this protocol : https://www.epiphan.com/userguides/LUMiO12x/Content/UserGuides/PTZ/3-operation/VISCAcommands.htm#InquiryCommands


// var parameterPath = local.parameters;
// var valuesPath = local.values;

var ZoomPos = script.addFloatParameter("Zoom Position", "", 0., 0., 1.);
var ZoomPosLastUpdate = script.addFloatParameter("Zoom update", "", 0.);

// var state = 
var inquiry = ['CAM_ZoomPosInq', 'CAM_FocusModeInq', 'CAM_FocusPosInq', 'CAM_ReplyIntervalTimeInq'];
var camID = 1;
var waitTaskComplete = 0 ;
var currentInquiry = '';

var ZoomAuto  = false ;
var ZoomPos_target ;
var ZoomTime_target ;

////////////////////////		HELPERS FUNCTIONS	 ////////////////////////////

function printArray(name, array){
	var printHeader = ' '+name+' : ';
	if (array.length){for(var i=0; i<array.length; i++){printHeader+=array[i] + ' ';}}
	script.log(printHeader);
}



////////////////////////		VISCA FUNCTIONS	 ////////////////////////////////

function setZoomPos(ID, position){
	var header = [1, 4, 71];
	var posCmd =	[];
	var pos = Math.round(Math.floor(16384 * position));
	// script.log(pos);
	posCmd[3]=pos%16;
	pos = Math.round(Math.floor(pos/16));
	posCmd[2]=pos%16;
	pos=Math.round(Math.floor(pos/16));
	posCmd[1]=pos%16;
	posCmd[0]=Math.round(Math.floor(pos/16));
	// local.sendBytes(idHex, 1, 4, 71, posCommand, 255);
	
	sendHeaderCommand(camID, header, posCmd);
}

function setZoomSpeed(ID, speed){
	var header = [1, 4, 7];

	var speedCmd = speed < 0 ?  48 : 32;
	
	speedCmd += Math.abs(speed)-1;
	speedCmd = speed == 0 ? 0 : speedCmd ;
	sendHeaderCommand(camID, header, speedCmd);
}



function sendInquiry(id, inquiryName){
	var command ;
	if (currentInquiry == ''){ //no inquiry running;
		currentInquiry = inquiryName ;
		if(inquiryName == 'CAM_ZoomPosInq'){ command = [9, 4, 71];}
		if(inquiryName == 'CAM_ReplyIntervalTimeInq'){ command = [9, 4, 106];}
		sendCommand(camID, command);
	}
	else{script.log("inquiry running");}

}

function sendCommand(id, command){
	var idHex = (parseInt("0x80") + id);

	// printArray('command', command);
	local.sendBytes(idHex, command, 255);
}

function sendHeaderCommand(id, header, command){
	if (!waitTaskComplete){
		var idHex = (parseInt("0x80") + id);
		// printArray('header', header);
		// printArray('command', command);
		local.sendBytes(idHex, header, command, 255);
		waitTaskComplete = 1;
	}
	else { script.log('task not complete');}
	
}




////////////////////////		ZOOM AUTOMATION	 ////////////////////////////////


function setZoomPositionInTime(ID, position, time){
	
	//update zoom position and time targets
	ZoomPos_target = position ;
	ZoomTime_target = util.getTime()+time;

	//activate callback
	ZoomAuto = true ;

	//deduce appropriate speed
	// var speedCmd = speed < 0 ?  48 : 32;
	// speedCmd = speed == 0 ? 0 : speedCmd ;
	// speedCmd += Math.abs(speed);
	// sendHeaderCommand(camID, header, speedCmd);
}

function setZoomPositionInTime_TL(ID, position, time){
	
	var tl_time = root.sequences.keys.currentTime.get();
	
	//update zoom position and time targets
	ZoomPos_target = root.sequences.keys.zoom.automation.getValueAtPosition(tl_time+time) ;
	ZoomTime_target = util.getTime()+time;

	//activate callback
	ZoomAuto = true ;

	//deduce appropriate speed
	// var speedCmd = speed < 0 ?  48 : 32;
	// speedCmd = speed == 0 ? 0 : speedCmd ;
	// speedCmd += Math.abs(speed);
	// sendHeaderCommand(camID, header, speedCmd);
}

function updateZoomPosition() {
	
	if (ZoomAuto){		
		//update position
		sendInquiry(1, 'CAM_ZoomPosInq');
		
		//update speed if needed
		var lastUpdated = util.getTime()-ZoomPosLastUpdate.get();
		// script.log(lastUpdated);
		if(lastUpdated<0.5){
			//compute remaining time
			var remainTime = ZoomTime_target - util.getTime();
			if(remainTime > 0){
				var remainLength = (ZoomPos_target - ZoomPos.get()) * 100;
				var rawSpeed = remainLength / remainTime ;
				
				var absSpeed = Math.abs(rawSpeed);
				var realSpeed = -0.00221 * Math.pow(absSpeed,2) + 0.30898 * absSpeed ;
				var direction = rawSpeed > 0 ? 1 : -1;
				realSpeed *= direction ;
				realSpeed = Math.floor(realSpeed);
				script.log(remainLength + '% in ' + remainTime + ' s : ' + realSpeed + ' / ' +rawSpeed );
				setZoomSpeed(1, realSpeed);
			}
			else { 
				ZoomAuto = false;
				script.log('automation timeout');
				//go to position
				setZoomPos(1, ZoomPos_target);
				sendInquiry(1, 'CAM_ZoomPosInq');
			}
		}
	}	
}

 function computeSpeed(){
	

	// 0,151*PUISSANCE((A18+1);2) +3,0001717*(A18+1)+0,007557
}




///////////////////////		SCRIPT FUNCTIONS	 ///////////////////////////////



function init() {
	//loadFixtures();
	script.log("VISCA module loaded");
	script.setUpdateRate(2);
}

function update(deltaTime){
	updateZoomPosition();
	computeSpeed();
	// script.log('update');
	
}


var buffer=[];
var bufferIndex = 0 ;
function dataReceived(data)
{
	//If mode is "Lines", you can expect data to be a single line String
	// script.log("Data received : " +data);

	//If mode is anything else, you can expect data to be an array of bytes
	// script.log(" Bytes received : "+data.length);
	// for(var i=0; i < data.length; i++)
	// {
	// 	script.log(" > " + parseInt((""+data[i]),16));
	// }

	//fill buffer with bytes until you find a 255
	for (var i = 0 ; i<data.length ; i++){
		if (data[i]!=255){
			buffer[bufferIndex]=data[i];
			bufferIndex += 1;

		}

		else{
			if(buffer[0]==144){	//0x90, you've got a message
				if (buffer[1]==65){script.log("received command");} //0x41
				else if (buffer[1]==81){script.log("complete command");waitTaskComplete=0;} //0x51
				else if (buffer[1]==96){script.log("syntax error");} //0x60
				else if (buffer[1]==97){//0x61
					var msg = "error :";
					if(buffer[2]==1){msg=msg+"message length";}
					else if(buffer[2]==2){msg=msg+"syntax";}
					else if(buffer[2]==3){msg=msg+"command buffer full";}
					else if(buffer[2]==4){msg=msg+"command cancelled";}
					else if(buffer[2]==5){msg=msg+"no socket";}
					else if(buffer[2]==65){msg=msg+"command not executable";}
					else{
							msg=msg+"unknow error";
							for(var j=2; j < buffer.length; j++)
							{
								script.log(" > " +data[i]);
							}
						}
					script.log(msg);
				}

				//inquiry answers
				else if (buffer[1]==80){//0x50
					if(currentInquiry == 'CAM_ZoomPosInq'){
						var position = buffer[2]*4096 + buffer[3]*256 + buffer[4]*16 + buffer[5];
						// printArray("zoom position :", buffer);
						// script.log(position);
						ZoomPos.set(position/16384.);
						ZoomPosLastUpdate.set(util.getTime());
					}
					if(currentInquiry == 'CAM_ReplyIntervalTimeInq'){
						var position = buffer[4]*16 + buffer[5];
						// printArray("zoom position :", buffer);
						// script.log(position);
						ZoomPos.set(position/16384.);
						ZoomPosLastUpdate.set(util.getTime());
					}
					//free inquiry slot
					currentInquiry = '';
				}
				else if(buffer[1] == 7 && buffer[2] == 4 && buffer[3]==105){
					var position = buffer[6]*4096 + buffer[7]*256 + buffer[8]*16 + buffer[9];
						// printArray("zoom position :", buffer);
						// script.log(position);
						ZoomPos.set(position/16384.);
						ZoomPosLastUpdate.set(util.getTime());
				}
				else{printArray("unknown answer :", buffer);}
			}
			bufferIndex = 0;
			buffer=[];
		}

	}
	//then process buffer

}