/*Global variable*/
var load = 1;
var noload = 0;

/* Singleton Object */
var single_obj = false;


/*
 * MOSTool ()
 *	Represent the wrapper class of MOS 
 *	- Create a single instance of MOS class
 *
 *		This class is created because the MOSApplet uses the same instance for updating the result values, test state and test progress.
 */
function MOSTool(TestState_Notification, TestProgress_Notification, TestResult_Notification, TestInfo_Notification)
{
	if(!single_obj)
		mos = new MOS(TestState_Notification, TestProgress_Notification, TestResult_Notification, TestInfo_Notification);
	else
		alert("Only single object can be created");

	//single object is created
	single_obj = true;

	return mos;
}

/*
 * MOS ()
 *	Represent the main class of MOS tool
 *	- Start and Stop MOS tool
 *	- Store all values in Hash
 *	- Set and Clear the results
 *	- Provide Information about Test
 *
 *	The param in which specific result is stored are :
 *		"MOS" - MOS score, 0.0 to 5.0
 *		"OWD" - One Way Dealy in ms
 *		"MeanJitter" - mean jitter in ms
 *		"PeakJitter" - peak jitter in ms
 *		"PacketLoss" - packet loss percentage, 0.0 to 100.0
 *		"PacketLate" - packet late percentage, 0.0 to 100.0
 */
function MOS(TestState_Notification, TestProgress_Notification, TestResult_Notification, TestInfo_Notification)
{
	/*Initialize the callback function*/
	this.TestState_Notification = TestState_Notification;
	this.TestProgress_Notification = TestProgress_Notification;
	this.TestResult_Notification = TestResult_Notification;
	this.TestInfo_Notification = TestInfo_Notification;

	/*	Test States :
		"idle"      - no test in progress (may be done)
		"error"     - no test in progress, error resulted from last test
		"starting"  - starting test
		"noload"    - performing no load ("Internet") test
		"load"      - performing load ("QoS") test
	*/
	this.test_state = "idle";
	
	/*	Test Progress : It is the amount of test finish.*/
	this.test_progress = 0;

	/*
	 * mos_test_resultset
	 *	store value of MOS test parameter with respect to its id
	 */
	this.mos_test_resultset = new Hash();


	/*
	 * StartMOSTest ()
	 *	Initialize all the variable and start the test
	 */
	this.StartMOSTest = function ()
	{ 
		// First clear all the previous results from Hash
		this.ClearAllResults();
		if(document.MOSApplet)
			document.MOSApplet.js_startMOSTest();
		// ToDo : Call "StartMOSTest ()" from Applet
	}

	/*
	 * StopMOSTest ()
	 *	Stop the running MOS test
	 */
	this.StopMOSTest = function ()
	{ 
		if(document.MOSApplet)
			document.MOSApplet.js_stopMOSTest();			
		this.setTestState ("stopped");
		document.getElementById('loader').style.display = 'none';
		
		// ToDo : Call "StopMOSTest ()" from Applet
	}
	document.onbeforeunload = this.StopMOSTest;

	/*
	 *	ClearAllResults ()
	 *		Clear the last or previous test results from Hash
	 */
	this.ClearAllResults = function ()
	{
		this.test_Progress = 0;
		this.test_State = "idle";
		this.mos_test_resultset.setItem("load_mos", 0.0);
		this.mos_test_resultset.setItem("load_owd", 0.0);
		this.mos_test_resultset.setItem("load_meanjitter", 0.0);
		this.mos_test_resultset.setItem("load_peakjitter", 0.0);
		this.mos_test_resultset.setItem("load_packeloss", 0.0);
		this.mos_test_resultset.setItem("load_packetlate", 0.0);
		this.mos_test_resultset.setItem("noload_mos", 0.0);
		this.mos_test_resultset.setItem("noload_owd", 0.0);
		this.mos_test_resultset.setItem("noload_meanjitter", 0.0);
		this.mos_test_resultset.setItem("noload_peakjitter", 0.0);
		this.mos_test_resultset.setItem("noload_packetloss", 0.0);
		this.mos_test_resultset.setItem("noload_packetlate", 0.0);
	}

	/*
	 * GetMOSTest_State ()
	 *	returns the Test state. The states are defined above
	 */
	this.GetMOSTest_State = function ()
	{
		return this.test_state;
	}

	/*
	 * GetMOSTest_State ()
	 *	returns the Test state. The states are defined above
	 */
	this.GetMOSTest_Info = function ()
	{
		return this.test_state;
	}
	
	/*
	 * GetMOSTest_Progress ()
	 *	returns the Test progress. The range of progress is : 0 to 100
	 */
	this.GetMOSTest_Progress = function ()
	{
		return this.test_progress;
	}

	/*
	 *	getValue ()
	 *		Returns the specific result value from Hash
	 *
	 *		testType
	 *			Specify the test type : load or noload
	 *		param
	 *			Specifies the actual parameter, whose result to be return
	 *		If you want the result of mos with load,then
	 *			specify	testType = load
	 *			specify	param = "mos"
	 *		If you want the result of mos with noload,then
	 *			specify	testType = noload
	 *			specify	param = "mos"
	 *		The same is for : owd, meanjitter, peakjitter, packetloss, packetlate etc
	 */
	this.GetMOSTest_Result = function (testType, param)
	{
		if (this.test_state == "error")
			return;

		lstr = (testType == load) ? "load" : "noload";
		id = lstr + "_" +param;
		return this.mos_test_resultset.getItem(id);
	}

	/* setTestResult ()
	 *	Store all MOS Test Results into Hash
	 *
	 *	testType
	 *		testType = 0, for no-load ("internet") test
	 *		testType = 1, for load ("QoS") test
	 *	param
	 *		param represent the specific result from applet
	 *		The params are declare at top of this class, any other value will be ignore
	 *	value
	 *		contains the actual result value return from the test
	 */
	this.setTestResult = function (testType, param, value)
	{
		lstr = (testType == load) ? "load" : "noload";
		id = lstr + "_" +param;
		/*Insert the result into Hash*/
		this.mos_test_resultset.setItem(id, value);
 
		/*
		 *	Call user defined function, to pass the test result to the user
		 *	UI developer can use this callback notification, if he wants to display test result
		 */
		if(this.TestResult_Notification) {
			try {
				TestResult_Notification(testType, param, value);
			} catch(e) {
				return false;
			}
		}

		return value;
	}

	/*
	 * setTestState ()
	 *	Set the Test State. The states are defined above.
	 *	Param1 :
	 *		state : Test state in string format
	 */
	this.setTestState = function (state)
	{
		this.test_state = state;
		
		/*
		 *	Call user defined function, to pass the current test state to the user
		 *	UI developer can use this callback notification, if he wants to any event on test state change
		 *	The "state" value will be anything of defined test sate : idle, error, starting, noload, load
		 */
		if(this.TestState_Notification) {
			try {
				TestState_Notification(state);
			} catch(e) {
				return false;
			}
		}
	}

	/*
	 * setTestProgress ()
	 *	Increament the progress of ProgressBar, by the amount of increment character (incBy).
	 *	Params:
	 *		progress - Percentage increment character
	 */
	this.setTestProgress = function (progress)
	{
		this.test_progress = progress;
		/*
		 *	Call user defined function, to pass the current progress value to the user
		 *	UI developer can use this callback notification, if he wants to write any event on progress bar
		 *	The "progress" value will give progress in multiple of 5 or 10.
		 */
		if(this.TestProgress_Notification) {
			try {
				TestProgress_Notification(progress);
			} catch(e) {
				return false;
			}
		}
	}
	
	/*
	 * setTestInfo ()
	 *	Set Test Information into the String. 
	 *		info - The current action done by MOS Test
	 */
	this.setTestInfo = function (info)
	{
		this.test_info = info;
		/*
		 *	Call user defined function, to pass the test information to the user
		 *	UI developer can use this callback notification, if he wants to trace the MOS test
		 *	The "test_info" value will give the String that describe the current test action
		 */
		if(this.TestInfo_Notification) {
			try {
				TestInfo_Notification(this.test_info);
			} catch(e) {
				return false;
			}
		}
	}

}

/*
 * Hash ()
 * 	Represent the class to store the MOS calculation results
 * 	Store each value as key-value pair.
 * 	Where, 
 * 	key - name of parameter
 * 	value - value of parameter
 */
function Hash()
{
	this.length = 0; 
	this.items = new Array();

	for (var i = 0; i < arguments.length; i += 2) {
		if (typeof(arguments[i + 1]) != 'undefined') {
			this.items[arguments[i]] = arguments[i + 1];
			this.length++;
		}
	}
   
	/* 
	 * removeItem ()
	 * 	Remove item from hash
	 *
	 * 	Param1 : key of item to be remove
	 * 	Return : value of removed item
	 */
	this.removeItem = function(in_key)
	{
		var tmp_value;
		if (typeof(this.items[in_key]) != 'undefined') {
			this.length--;
			var tmp_value = this.items[in_key];
			delete this.items[in_key];
		}
		return tmp_value;
	}

	/*
	 * getItem ()
	 * 	Get the value of item having key as in_key
	 *  
	 * 	Param 1: Key of item
	 * 	Return : value of item
	 */
	this.getItem = function(in_key) 
	{
		return this.items[in_key];
	}

	/*
	 * setItem ()
	 * 	Set the value of item having key as in_key to in_value
	 *
	 * 	Param 1: key of item, whose value need to be changed
	 * 	Param 2: value of item
	 * 	Return : none
	 */
	this.setItem = function(in_key, in_value)
	{
		if (typeof(in_value) != 'undefined') {
			if (typeof(this.items[in_key]) == 'undefined') {
				this.length++;
			}
			this.items[in_key] = in_value;
		}
	}

	/*
	 * hasItem ()
	 * 	Check if the specified item is defined or not, having key as in_key
	 *
	 *	Param1: key of item
	 *	Return : true - if item is defined
				false -  if item is undefined
	 */
	this.hasItem = function(in_key)
	{
		return typeof(this.items[in_key]) != 'undefined';
	}
}

	/*Create MOSTool instance*/
	var mos = new MOSTool(TestState_Callback, TestProgress_Callback, TestResult_Callback, TestInfo_Callback);

	/*
	 * TestState_Callback ()
	 *  This function will be called by MOS_Tool javascript API, as soon as test state changes
	 *	The test States are : idle, running, noload, load, error
	 *	If user does not want this callback, then pass "null" for TestState_Callback while creating MOSTool instance.
	 */
	function TestState_Callback(test_state)
	{
		document.getElementById("test_status").innerHTML = test_state;
		if(test_state == "idle") {
			document.getElementById("start_button").value = "Start Network Voice Quality Test";
			document.getElementById("start_button").onclick = startMOSTest;
			// ShowGraph();
			document.getElementById('loader').style.display = 'none';
		}
		else {
		  document.getElementById('loader').style.display = '';
		}
		  
		
	}

	/*
	* TestProgress_Callback ()
	 *  This function will be called by MOS_Tool javascript API, after every 5% of test progress
	 *	If user does not want this callback, then pass "null" for TestProgress_Callback while creating instance
	 */
	function TestProgress_Callback(test_progress)
	{
		var progress = test_progress / 10;
		var block = document.getElementById("block" + progress);

		block.innerHTML = "&nbsp;&nbsp;&nbsp;";
		block.style.backgroundColor = "forestgreen";
	}

	/*
	 * TestResult_Callback ()
	 *	This function will be called by MOS_Tool javascript API, as soon as test is finish and results are ready
	 *	If user does not want this callback, then pass "null" for TestResult_Callback while creating instance
	 *
	 *	test_type -	gives the test mode :  	0 for noload 
	 *		            				1 for load
	 *	param -	    gives the parameter name 
	 *			    The parameter names are - mos, owd, meanjitter, peakjitter, packetloss and packetlate ect
	 *	value -	    gives the actual result of the parameter
	 */	
	function TestResult_Callback(test_type, param, value)
	{
		test = (test_type == load) ? "load" : "noload";
		var param_id = test + "_" + param;

		document.getElementById(param_id).innerHTML = value;
	}

	/*
	* TestInfo_Callback ()
	 *  This function will be called by MOS_Tool javascript API and will give the current action done by MOS test
	 *	If user does not want this callback, then pass "null" for TestInfo_Callback while creating instance
	 */
	function TestInfo_Callback(test_info)
	{
		if(document.getElementById("test_info"))
			document.getElementById("test_info").value += test_info + "\n";
	}
	
	/*
	 * StartMOSTest()
	 *  Start MOS test by calling startMOSTest from MOS Tool class
	 */
	function startMOSTest()
	{
		document.getElementById("test_info").value = "";

		for(i=1; i <= 10; i++)
		{
			document.getElementById("block" + i).innerHTML = "";
			document.getElementById("block" + i).style.background = "white";
		}
		if(mos != null) {		
			mos.StartMOSTest();
			document.getElementById("start_button").value = "Stop Network Voice Quality Test";
			document.getElementById("start_button").onclick = stopMOSTest;
			return;
		} else {
			alert("Can't create MOS_Tool instance successfully");
		}
		
	}

	/*
	 * StopMOSTest()
	 *  Stop MOS test by calling stopMOSTest from MOS Tool class
	 */
	function stopMOSTest()
	{
		if(mos != null) {
			mos.StopMOSTest();
			document.getElementById("start_button").value = "Start Network Voice Quality Test";
			document.getElementById("start_button").onclick = startMOSTest;
			return;
		}
	}
	
	/*
	  * ShowGraph ()
	  *	Show the graph after test is finish. It the quality of VoIP with respect to MOS
	  */
	  function ShowGraph()
	  { 
	    return;
		noload_mos = mos.GetMOSTest_Result(noload, "MOS");		
		load_mos = mos.GetMOSTest_Result(load, "MOS");
		var graph = new Graph("MOS_Graph",noload_mos,load_mos);
		
		graph.draw_graph();
	  }

	  function page_load()
	  {
		document.getElementById("test_status").innerHTML = "Loading...";
	  	document.getElementById('loader').style.display = '';

		return;
	  }
