//MIDI 14bit management
var pan_midi_ch = script.addIntParameter("pan midi channel", "", 0);
var pan_midi={channel:pan_midi_ch.get(), MSB:0, LSB:0, target:root.customVariables.unitValues.variables.pan.pan };

var tilt_midi_ch = script.addIntParameter("tilt midi channel", "", 1);
var tilt_midi={channel:tilt_midi_ch.get(), MSB:0, LSB:0, target:root.customVariables.unitValues.variables.tilt.tilt};

var delCue_Trigger = script.addTrigger("clear cues", "clear all cues in the timeline");
var clearTL_Trigger = script.addTrigger("clear timeline", "clear all cues and keys in the timeline");
var createKeyGroup_Trigger = script.addTrigger("create group","create key group @ current time");
var createKeyGroupInOut_Trigger = script.addTrigger("create InOut group","create key group @ current time and key group ten seconds later, with constant  values inbetween");

var myFile = script.addFileParameter("textFile", "this is a text file");
var myTrigger = script.addTrigger("Print pan keys", "Trigger description");
var myTrigger2 = script.addTrigger("test", "Trigger description");
								//This will add a trigger (button)

var tl_keyframes = {cues : {}, keys : {}} ; //holds timeline keys, is updated at fixed rate
//variable to hold group logic
var tl_groups = {groups: 0
	/*group0 : { inCue : {pan : "key", tilt : "key", zoom : "key", dim : "key", focus : "key"},
							 							outCue : {pan : "key", tilt : "key", zoom : "key", dim : "key", focus : "key"}
													}*/
								} ;

var file_keyframes = {groups : 0} ; //holds file keys, used to save and load
var myFloatParam = script.addFloatParameter("My Float Param","Description of my float param",.1,0,1);


/*
var myBoolParam = script.addBoolParameter("My Bool Param","Description of my bool param",false); 			//This will add a boolean parameter (toggle), defaut unchecked
var myFloatParam = script.addFloatParameter("My Float Param","Description of my float param",.1,0,1); 		//This will add a float number parameter (slider), default value of 0.1, with a range between 0 and 1
var myIntParam = script.addIntParameter("My Int Param","Description of my int param",2,0,10); 				//This will add an integer number parameter (stepper), default value of 2, with a range between 0 and 10
var myStringParam = script.addStringParameter("My String Param","Description of my string param", "cool");	//This will add a string parameter (text field), default value is "cool"
var myColorParam = script.addColorParameter("My Color Param","Description of my color param",0xff0000ff); 	//This will add a color parameter (color picker), default value of opaque blue (ARGB)
var myP2DParam = script.addPoint2DParameter("My P2D Param","Description of my p2d param"); 					//This will add a point 2d parameter
var myP3DParam = script.addPoint3DParameter("My P3D Param","Description of my p3d param"); 					//This will add a point 3d parameter
var myTargetParam = script.addTargetParameter("My Target Param","Description of my target param"); 			//This will add a target parameter (to reference another parameter)
var myEnumParam = script.addEnumParameter("My Enum Param","Description of my enum param",					//This will add a enum parameter (dropdown with options)
											"Option 1", 1,													//Each pair of values after the first 2 arguments define an option and its linked data
											"Option 2", 5,												    //First argument of an option is the label (string)
											"Option 3", "banana"											//Second argument is the value, it can be whatever you want
											);
*/


//you can also declare custom internal variable
//var myValue = 5;

///////////////////////		MIDI FUNCTIONS			///////////////////////

function checkAxe(CC){
	if(CC==pan_midi.channel || CC==pan_midi.channel+32){
		return pan_midi;
	}
	else return 0;
}

function updateAxe(axe, CC, value){
	if(CC==axe.channel){
		axe.MSB = value;
		// root.customVariables.unitValues.variables.pan.pan.set((128*axe.MSB+axe.LSB)/16383.0);
	}
	if(CC==axe.channel+32){
		axe.LSB = value;
		// myFloatParam.set((128*MSB+LSB)/16383.0);
	}
	axe.target=(128*axe.MSB+axe.LSB)/16383.0;
	script.log(axe.target);
}


///////////////////////		TIMELINE FUNCTIONS		///////////////////////

function refresh_tl_keys_list(){



	// tl_keyframes['cues']
	if(root.sequences.keys.cues.getItems().length){
		for (var i = 0 ; i < root.sequences.keys.cues.getItems().length ; i++){
			tl_keyframes['cues']['cue'+i] = {index : i};
			tl_keyframes['cues']['cue'+i]['name'] = root.sequences.keys.cues.getItems()[i].name;
			tl_keyframes['cues']['cue'+i]['time'] = root.sequences.keys.cues.getItems()[i].time.get();
			// script.log(tl_keyframes['cues']['cue'+i].time);
		}
	}
	if(root.sequences.keys.layers.getItems().length){
		for (var i = 0 ; i < root.sequences.keys.layers.getItems().length ; i++){
			var currentLayer = root.sequences.keys.layers.getItems()[i] ;
			tl_keyframes['keys'][currentLayer.name] = {};
			// script.log(currentLayer.name);

			if(currentLayer.automation.getItems().length){
				// script.log(currentLayer.automation.items.length);
				for (var j = 0 ; j < currentLayer.automation.getItems().length ; j++){

					var currentkey = currentLayer.automation.getItems()[j] ;
					tl_keyframes['keys'][currentLayer.name][currentkey.name] = {
																				position : currentkey.position.get(),
																				value : currentkey.value.get()
																				};
					// script.log(tl_keyframes['keys'][currentLayer.name][currentkey.name].value);
				}
			}
		}
	}

	// myFile.writeFile(JSON.stringify(tl_keyframes), 1);
}

function reorderLayers(){
	root.sequences.keys.layers.pan.automation.reorderItems();
	// if(root.sequences.keys.layers.getItems().length){
	// 	for (var i = 0 ; i < root.sequences.keys.layers.getItems().length ; i++){
	// 		root.sequences.keys.layers.getItems()[i].automation.reorderItems();
	// 	}
	// }
}

function apply_tl_groups() {
	if(tl_groups.groups){
		for(var i=0 ; i<tl_groups.groups ; i++){
			//set all keys in a group to its cue time
			var tempGroup = tl_groups['group'+i];
			var hasOut= typeof tempGroup.cueOut.pan!='undefined' ;
			var layers = root.sequences.keys.layers.getItems() ;
			var inTime = root.sequences.keys.cues[tempGroup.cueIn.cue].time.get();
			var outTime;
			if(hasOut){ outTime = root.sequences.keys.cues[tempGroup.cueOut.cue].time.get();}
			if(layers.length){
				for(var j = 0 ; j<layers.length ; j++){
					var tempLayer=layers[j].name;
					var inKey = tempGroup.cueIn[tempLayer];
					root.sequences.keys.layers[tempLayer].automation[inKey].position.set(inTime);
					if (hasOut) {
						var outKey = tempGroup.cueOut[tempLayer];
						root.sequences.keys.layers[tempLayer].automation[outKey].position.set(outTime);
						//apply inKey value
						root.sequences.keys.layers[tempLayer].automation[outKey].value.set(root.sequences.keys.layers[tempLayer].automation[inKey].value.get());
					}
				}
			}
		}
	}
	// root.sequences.keys.layers.items[0].automation.items[0].position.set(root.sequences.keys.cues.items[0].time.get());
	// script.log(root.sequences.keys.cues.items[0].name + "  " + root.sequences.keys.layers.items[0].automation.items[0].name );


}

function clear_tl_cues(){
	if(root.sequences.keys.cues.getItems().length){
		for (var i = root.sequences.keys.cues.getItems().length-1 ; i>=0 ; i--){
			root.sequences.keys.cues.removeItem(root.sequences.keys.cues.getItems()[i].name);
		}
		script.log("Cleared all cues");
	}
	else {script.log("no cues to clear");}
}

function clear_tl_keys(){
	script.log(root.sequences.keys.layers.getItems().length);
	if(root.sequences.keys.layers.getItems().length){
		for (var i = root.sequences.keys.layers.getItems().length-1 ; i >=0  ; i--){
			if(root.sequences.keys.layers.getItems()[i].automation.getItems().length){
				for (var j = root.sequences.keys.layers.getItems()[i].automation.getItems().length-1 ; j >= 0 ; j--){
					root.sequences.keys.layers.getItems()[i].automation.removeItem(root.sequences.keys.layers.getItems()[i].automation.getItems()[j].name);
				}
			}
			// root.sequences.keys.cues.removeItem(root.sequences.keys.cues.items[i].name);
		}
		script.log("Cleared all keys");
	}
	else{script.log("no keys to clear");}
}
function clear_tl_full(){
	clear_tl_cues();
	clear_tl_keys();
	tl_groups = {groups: 0};
	myFile.writeFile(JSON.stringify(tl_groups), 1);
}

function create_keyGroup(mode){ //mode=0 single cue, mode=1 dual cues

	 //get current variables values
	var tempValues = {
		position: root.sequences.keys.currentTime.get() ,
		pan : root.customVariables.unitValues.variables.pan.pan.get(),
		tilt : root.customVariables.unitValues.variables.tilt.tilt.get(),
		zoom : root.customVariables.unitValues.variables.zoom.zoom.get(),
		dim : root.customVariables.unitValues.variables.dimmer.dimmer.get(),
		focus: root.customVariables.unitValues.variables.focus.focus.get(),
		speed : root.customVariables.unitValues.variables.speed.speed.get(),

	};
	// script.log(tempValues.pan);

	//create new entry in group list
	var groupIndex = tl_groups.groups;
	script.log("creating group # : " + groupIndex);

	tl_groups['group'+groupIndex] ={cueIn: {}};
	var inCue = root.sequences.keys.cues.addItem();
	inCue.time.set(tempValues.position);
	tl_groups['group'+groupIndex].cueIn.cue = inCue.name;
	//create cues and tl_group entries
	if(mode){
		tl_groups['group'+groupIndex].cueOut = {} ;
		var outCue = root.sequences.keys.cues.addItem();
		outCue.time.set(tempValues.position+10.);
		tl_groups['group'+groupIndex].cueOut.cue = outCue.name;
	}
	//create keys
	var layers = root.sequences.keys.layers.getItems() ;
	if(layers.length){
		for(var i = 0 ; i<layers.length ; i++){
				tempKeyIn = root.sequences.keys.layers.getItems()[i].automation.addItem();
				tempKeyIn.value.set(tempValues[root.sequences.keys.layers.getItems()[i].name]);
				tempKeyIn.position.set(inCue.time.get());
				tl_groups['group'+groupIndex].cueIn[root.sequences.keys.layers.getItems()[i].name]=tempKeyIn.name;

				if(mode) {
					tempKeyOut = root.sequences.keys.layers.getItems()[i].automation.addItem();
					tempKeyOut.value.set(tempValues[root.sequences.keys.layers.getItems()[i].name]);
					tempKeyOut.position.set(outCue.time.get());
					tl_groups['group'+groupIndex].cueOut[root.sequences.keys.layers.getItems()[i].name]=tempKeyOut.name;
				}

				root.sequences.keys.layers.getItems()[i].automation.reorderItems();
			}
		}
		tl_groups.groups += 1;
		myFile.writeFile(JSON.stringify(tl_groups), 1);
}



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

/*
 The init() function will allow you to init everything you want after the script has been checked and loaded
 WARNING it also means that if you change values of your parameters by hand and set their values inside the init() function, they will be reset to this value each time the script is reloaded !
*/
function init()
{
	script.log("Reading key group file");
	tl_groups = JSON.parse(myFile.readFile());
	//script.log (tl_groups.groups);
	script.log(root.sequences.keys.layers.pan.automation.getItems()[0]);
//root.sequences.keys.layers.pan.value
	// script.log(root.reference);
	// script.log(root.sequences.keys.addCueAt(1.11));
	// root.sequences.keys.layers[0].getObjectProperties();
	//myFloatParam.set(5); //The .set() function set the parameter to this value.
	//myColorParam.set([1,.5,1,1]);	//for a color parameter, you need to pass an array with 3 (RGB) or 4 (RGBA) values.
	//myP2DParam.set([1.5,-5]); // for a Point2D parameter, you need to pass 2 values (XY)
	//myP3DParam.set([1.5,2,-3]); // for a Point3D parameter, you need to pass 3 values (XYZ)
	// tl.cues.cue.time
	// script.log(tl.cues.items[0].name);
	// for (var i = tl.cues.items.length-1 ; i>=0 ; i--){
	// 	// tl.cues.items[i].name='truc'+i;
	// 	script.log(tl.cues.items[i].time.get());
	// }

	root.sequences.keys.cues.getItems()[0].setName("moncue");
	// root.sequences.keys.cues.cue.time

}

/*
 This function will be called each time a parameter of your script has changed
*/
function scriptParameterChanged(param)
{
	if(param.is(myTrigger)){
		script.log(root.sequences.keys.layers.getItems()[0].automation.getItems().length);
		for (var j = 0 ; j<root.sequences.keys.layers.getItems()[0].automation.getItems().length ; j++){
			script.log(root.sequences.keys.layers.getItems()[0].automation.getItems()[j].name);
		}
		//  for (var i = tl.cues.items.length-1 ; i>=0 ; i--){
	 	// 	script.log(tl.cues.items[i].name);
	 	// }
		 // myFile.writeFile(JSON.stringify(testJSON), 1);
	}
	else if(param.is(myTrigger2)){
		// var props = util.getObjectMethods(root.sequences.keys.layers.getItems()[0].automation, true, true);
		// for (var j = 0 ; j<props.length ; j++){
		// 	script.log(props[i].name);
		// }
		reorderLayers();
		script.log("reorder");
	}

	else if (param.is(delCue_Trigger)){clear_tl_cues();}
	else if (param.is(clearTL_Trigger)){clear_tl_full();}
	else if (param.is(createKeyGroup_Trigger)){create_keyGroup(0);}
	else if (param.is(createKeyGroupInOut_Trigger)){create_keyGroup(1);}
	else if (param.is(myFloatParam)){
		//var time = myFloatParam.get() * root.sequences.keys.totalTime.get();
		// root.sequences.keys.layers.items[0].automation.items[0].position.set(time);
	}
	else if(param.is(myEnumParam)) script.log("Label = "+param.get()+", data = "+param.getData()); //The enum parameter has a special function getData() to get the data associated to the option
	// else script.log("Value is "+param.get()); //All parameters have a get() method that will return their value
	// script.log(myFile.readFile());
}

/*
 This function, if you declare it, will launch a timer at 50hz, calling this method on each tick
*/
var tl_refresh_delta = 0.;
var tl_refresh_rate = 0.1;

function update(deltaTime)
{
	tl_refresh_delta += deltaTime ;
	if (tl_refresh_delta > tl_refresh_rate){
			tl_refresh_delta = 0. ;
			refresh_tl_keys_list();
			apply_tl_groups();
			//reorderLayers();
			// script.log("Update : "+util.getTime()+", delta = "+deltaTime); //deltaTime is the time between now and last update() call, util.getTime() will give you a timestamp relative to either the launch time of the software, or the start of the computer.
	}

}




/* ********** MODULE SPECIFIC SCRIPTING **********************

	The "local" variable refers to the object containing the scripts. In this case, the local variable refers to the module.
	It means that you can access any control inside  this module by accessing it through its address.
	For instance, if the module has a float value named "Density", you can access it via local.values.density
	Then you can retrieve its value using local.values.density.get() and change its value using local.values.density.set()
*/

/*
 This function will be called each time a parameter of this module has changed, meaning a parameter or trigger inside the "Parameters" panel of this module
 This function only exists because the script is in a module
*/
function moduleParameterChanged(param)
{
	// if(param.isParameter())
	// {
	// 	script.log("Module parameter changed : "+param.name+" > "+param.get());
	// }else
	// {
	// 	script.log("Module parameter triggered : "+value.name);
	// }
}

/*
 This function will be called each time a value of this module has changed, meaning a parameter or trigger inside the "Values" panel of this module
 This function only exists because the script is in a module
*/
function moduleValueChanged(value)
{
	// if(value.isParameter())
	// {
	// 	script.log("Module value changed : "+value.name+" > "+value.get());
	// }else
	// {
	// 	script.log("Module value triggered : "+value.name);
	// }
}


/* ********** MIDI MODULE SPECIFIC SCRIPTING ********************* */

function ccEvent(channel, number, value)
{
	// script.log("ControlChange received "+channel+", "+number+", "+value);
	//feedback to BCF
	local.sendCC(channel, number, value);
	var currentAxe=checkAxe(number);
	if (currentAxe){updateAxe(currentAxe, number, value);}
	// if(number==pan_midi.channel){
	// 	MSB = value;
	// 	myFloatParam.set((128*MSB+LSB)/16383.0);
	// }
	// if(number==32){
	// 	LSB = value;
	// 	myFloatParam.set((128*MSB+LSB)/16383.0);
	// }
}
