// JavaScript Document
// The current time when this window was initialized.
var initTime = null;
// The current tab's index.
var nCurrent = 0;
// The minimum and maximum values allowed for the number of timepoints.
var MIN_TIMEPT_NR = 2;
var MAX_TIMEPT_NR = 20;
// The current validated value of number of timepoints. If the user enters 
// an invalid number, curTimeptNr is not updated until the user enters a 
// correct value.
var curTimeptNr = 5;
// The current validated value of number of lags. If the user enters 
// an invalid number, curLags is not updated until the user enters a 
// correct value.
var curLags = 1;
// Array containing the different default values that the first correlation term
// textbox can have, depending on which correlation structure of errors radio button
// is selected. MJ 2/14/2007
var arrDefFirstCorr = new Array(0, 0.3, 0.5);
// Indicates whether the user changed the value of the first correlation term  from 
// the default one, regardless of which correlation structure of error was selected
// at the time. MJ 2/14/2007
var dirtyFirstCorr = false;
// Indicates whether one of the values in a covariance matrix has the focus.
var covFocus = 0;

function init(){
	var initDate = new Date();
	initTime = initDate.getTime();
	
	// Set all the controls back to their default values and state. This is 
	// useful when the user refreshes the page, as most of the controls don't 
	// get reset properly.
	setToDefault();
	
	// Initialize the tabbed interface.
	initTabs();
}

// Initial set up of the tabs.
function initTabs(){
	var i = 0;
	var oNav = null;
	var oPanel = null;
	var n = 0;
	
	if((window.createPopup) || ((!window.createPopup) && (!document.all))){
		for(i = 0; i < 4; i++){							
			oNav = document.getElementById('tab' + i);
			oNav.nID = i;
			oPanel = document.getElementById('panel' + i);
			oPanel.className = "panel";
			oNav.onclick = selectTab;
			
			// Display the first panel as the default.
			if(i==0){
				oPanel.style.visibility = "visible";
			}
		}			
	}
}

function selectTab(tabIndex){
	var oPanel = null;
	var oItem = null;
	var oLink = null;
	
	if(isNaN(tabIndex)){
		tabIndex = this.nID;
	}
	
	if(nCurrent != tabIndex){
		nCurrent = tabIndex;
		turnAllTabsOff();
		oPanel = document.getElementById('panel' + tabIndex);
		oItem = document.getElementById('tab' + tabIndex);
		oLink = oItem.getElementsByTagName('a')[0];
		oPanel.style.visibility = "visible";
		oLink.className = "here";
	}
}

function turnAllTabsOff() {
	var i = 0;
	var oPanel = null;
	var oItem = null;
	var oLink = null;
	
	for(i = 0; i < 4; i++) {
		oPanel = document.getElementById('panel' + i);	
		oItem = document.getElementById('tab' + i);
		oLink = oItem.getElementsByTagName('a')[0];			
		oPanel.style.visibility = "hidden";
		oLink.className = "";			
	}
}

function setToDefault(){
	var frmSetts = document.getElementById("frmSettings");
	curTimeptNr = 5;
	curLags = 1;
	var i = 0;
	var curElement = null;
	
	// Reset the settings form.
	frmSetts.reset();
	
	// Hide the attrition rates section.
	displayAttrSection('tdAttrRates', false);
	
	// Display the design matrix textboxes.
	displayCtrlArray('tdRandMat', curTimeptNr, MAX_TIMEPT_NR);
	
	// Reset the dirty flag on the first correlation term's value.
	dirtyFirstCorr = false;
	// Set all the correlation terms back to their default values.
	initCorrTerms();
	// Display only the first correlation term.
	displayCtrlArray('tdCorr', 1, MAX_TIMEPT_NR - 1);
	
	// Go through all the elements in the form and if their style is set 
	// to the invalid value red textbox style, reset it to the default style.
	for(i = 0; i < frmSetts.elements.length; i++){
		curElement = frmSetts.elements[i];
		if(curElement.className == "redTextBox"){
			curElement.className = "";
			// Clear the "invalid entry" tooltip on the control, if present.
			if(curElement.title == "invalid entry"){
				curElement.title = "";
			}
		}
	}
	
	// Enable/disabled the effect size, treatment by interaction and # of
	// correlated lags.
	document.getElementById("txtMeanDiff").disabled = false;
	document.getElementById("txtTAU").disabled = true;
	document.getElementById("txtLags").disabled = true;
}

// Sets the correlation terms to their default values. MJ 2/19/2007
function initCorrTerms(){
	var i = 0;
	var curCtrl = document.getElementById('txtCorr0');
	var defValue = 0.5;
	var defFirstCorr = 0;
	
	// Set the first correlation term to 0.000.
	if(defFirstCorr.toFixed){
		defFirstCorr = defFirstCorr.toFixed(3);
	}
	curCtrl.value = defFirstCorr;
	curCtrl.title = "default value: " + defFirstCorr;
	
	// Set the rest of the correlation terms to their computed default 
	// values.
	for(i = 2; i < MAX_TIMEPT_NR; i++){
		curCtrl = document.getElementById('txtCorr' + (i-1));
		defValue = 0.5 / i;
		if(defValue.toFixed){
			defValue = defValue.toFixed(3);
		}
		curCtrl.value = defValue;
		curCtrl.title = "default value: " + defValue;
	}
}

function displayAttrSection(ctrlName, isChecked){
	var curCtrl = document.getElementById(ctrlName);
	var maxAttrRates = MAX_TIMEPT_NR - 1;
	
  if(isChecked){
		curCtrl.style.visibility = "";
		displayCtrlArray('tdAttr', curTimeptNr - 1, maxAttrRates);
	}else{
		curCtrl.style.visibility = "hidden";
		hideCtrlArray('tdAttr', maxAttrRates);
	}
}

function displayCtrlArray(ctrlName, maxVisible, arrLength){
	var curCtrl = null;
	var curLabel = null;
	var i = 0;
	
	for(i = 0; i < arrLength; i++){
		curCtrl = document.getElementById(ctrlName + i);
		curLabel = document.getElementById(ctrlName + "Lbl" + i);
		if(i < maxVisible){
			curCtrl.style.visibility = "";
			curLabel.style.visibility = "";
		}else{
			curCtrl.style.visibility = "hidden";
			curLabel.style.visibility = "hidden";
		}
	}
}

function hideCtrlArray(ctrlName, arrLength){
	var curCtrl = null;
	var curLabel = null;
	var i = 0;
	
	for(i = 0; i < arrLength; i++){
		curCtrl = document.getElementById(ctrlName + i);
		curLabel = document.getElementById(ctrlName + "Lbl" + i);
		curCtrl.style.visibility = "hidden";
		curLabel.style.visibility = "hidden";
	}
}

// Sets the visibility property of the controls dependent on the 
// number of timepoints.
function updateTimeptDepends(){
	var maxLessOne = MAX_TIMEPT_NR - 1;
	var chkAttrCtrl = document.getElementById("chkAttrition");
	var txtLagsCtrl = document.getElementById("txtLags");
	var ctrlLagsValue = parseInt(txtLagsCtrl.value);
	
	// Update the attrition rates textboxes only if the Attrition checkbox
	// is checked.
	if(chkAttrCtrl.checked){
		displayCtrlArray('tdAttr', curTimeptNr - 1, maxLessOne);
	}
	
	// Update the design matrix textboxes.
	displayCtrlArray('tdRandMat', curTimeptNr, MAX_TIMEPT_NR);
	
	// Correlation terms - if the correlated lags textbox is empty set 
	// its value and the number of current correlation lags to 1 (default).
	if(isNaN(ctrlLagsValue)){
		curLags = 1;
		txtLagsCtrl.value = curLags;
	}
	// If the correlated lags textbox contains a number >= the current number of 
	// timepoints, set its value and the the number of current correlation lags 
	// to curTimeptNr-1.
	else if(ctrlLagsValue >= curTimeptNr){
		curLags = curTimeptNr - 1;
		txtLagsCtrl.value = curLags;
	}else{
		// Let's say that curLags is 4, curTimeptNr is 5 and we change the value in the 
		// textbox to 7. This is considered invalid, so curLags remains 4 and only 4
		// correlation terms are displayed on the page. Then we go and change the number 
		// of timepoints to 10. 7 now becomes valid, so set curLags to 7, remove its 
		// red textbox style and display 7 correlation terms. MJ 9/06/2006
		curLags = ctrlLagsValue;
	}
	
	// By this point the lags textbox should contain a correct value, so clear
	// the red textbox property if previous value was invalid and redisplay the 
	// correlation terms.
	txtLagsCtrl.className = "";
	// Clear the "invalid entry" tooltip on the textbox, if present.
	if(txtLagsCtrl.title == "invalid entry"){
		txtLagsCtrl.title = "";
	}
	updateCorrTerms();
}

// Update the correlation term array when there's a change in either the 
// correlation structure, the number of lags or the number of timepoints.
function updateCorrTerms(){
	var maxLessOne = MAX_TIMEPT_NR - 1;
	var firstCorr = document.getElementById("txtCorr0");
	var curRadBtn = document.getElementById("radCorr0");
	var i = 0;
	var curDefValue = 0;
	
	// Set the first correlation term's value and display the other correlation 
	// terms, depending on which correlation structure of errors radio button
	// is currently selected. MJ 2/19/2007
	for(i = 0; i < arrDefFirstCorr.length; i++){
		curRadBtn = document.getElementById("radCorr" + i);
		if(curRadBtn.checked){
			// Obtain the appropriate default value.
			curDefValue = arrDefFirstCorr[i];
			// If possible, display the default value with 3 decimals.
			if(curDefValue.toFixed){
				curDefValue = curDefValue.toFixed(3);
			}
			
			// If the value of the first correlation term has not been modified by 
			// the user, display the appropriate default value for the selected
			// radio button.
			if(!dirtyFirstCorr){
				firstCorr.value = curDefValue;
			}
			firstCorr.title = "default value: " + curDefValue;
			
			// If the 'toeplitz (banded) matrix' radio button is checked, display
			// as many correlation terms as indicated in the '# of correlated lags"
			// textbox. Otherwise, display only the first correlation term.
			// MJ 2/19/2007
			if(i == 2){
				displayCtrlArray('tdCorr', curLags, maxLessOne);
			}else{
				displayCtrlArray('tdCorr', 1, maxLessOne);
			}
			i = arrDefFirstCorr.length;
		}
	}
}

// Computes the 'Treatment by time interaction' (TAU) and 'Effect size 
// at last timepoint' (ES) values based on the entered 'Mean difference   
// at last timepoint' (MD); or the MD and ES values based on the entered
// TAU depending on the 'Type of mean' radio button selected.
function computeMean(){
	var i = 0;
	var t1 = null;
	var arrCovar = new Array(curTimeptNr);
	var arrSD = new Array(curTimeptNr);
	var arrVar1 = new Array(3);
	var arrVar2 = new Array(3);
	var SIGMAE = parseFloat(document.getElementById("txtErrVar").value);
	var curN = curTimeptNr - 1;
	var ctrlMD1 = document.getElementById("txtMeanDiff");
	var ctrlTAU = document.getElementById("txtTAU");
	var ctrlES = document.getElementById("txtEffSize");
	var MD1 = parseFloat(ctrlMD1.value);
	var compTAU = parseFloat(ctrlTAU.value);
	var compES = parseFloat(ctrlES.value);
	var randMatLast = parseFloat(document.getElementById("txtRandMat" + curN).value);
	
	// Initialize the person-level and center-level covariance arrays.
	for(i = 0; i < 3; i++){
		arrVar1[i] = parseFloat(document.getElementById("txtPers" + i).value);
		arrVar2[i] = parseFloat(document.getElementById("txtCenter" + i).value);
	}
	
	// Compute TAU
	for(i = 0; i < curTimeptNr; i++){
		T1 = parseFloat(document.getElementById("txtRandMat" + i).value);
		arrCovar[i] = arrVar2[0] + arrVar1[0] + 2.0*T1*(arrVar2[1] + arrVar1[1]) + T1*T1*(arrVar2[2] + arrVar1[2]) + SIGMAE;
		arrSD[i] = Math.sqrt(arrCovar[i]);
	}
	
	// Disabled controls are not 'successful', i.e. they are not submitted to the server 
	// on a form submit. hdnTAU is used to explicitely send the TAU value to the server,
	// whether the 'Treatment by time interaction' box is disabled or not.
	document.getElementById("frmSettings").hdnTAU.value = compTAU;
	
	if(document.getElementById("radMean0").checked && MD1 != 0 && !isNaN(MD1)){		
		// Compute TAU based on mean difference at last timepoint.
		compTAU = MD1 / randMatLast;
		// The computed TAU value prior to rounding needs to be explicitely sent to the 
		// server.
		document.getElementById("frmSettings").hdnTAU.value = compTAU;
		
		// Round the displayed TAU value to 3 decimal digits.
		if(compTAU.toFixed){
			ctrlTAU.value = compTAU.toFixed(3);
		}else{
			ctrlTAU.value = compTAU;
		}
	}else if(document.getElementById("radMean1").checked && compTAU != 0 && !isNaN(compTAU)){
		// Compute mean difference at last timepoint based on entered TAU value.
		MD1 = compTAU * randMatLast;
		
		if(MD1.toFixed){
			ctrlMD1.value = MD1.toFixed(3);
		}else{
			ctrlMD1.value = MD1;
		}
	}
	
	if(MD1 != 0 && !isNaN(MD1)){
		// Compute effect size at last timepoint.
		compES = MD1 / Math.sqrt(arrCovar[curN]);
		if(compES.toFixed){
			ctrlES.value = compES.toFixed(3);
		}else{
			ctrlES.value = compES;
		}
	}
}

function submitSettings(){
	var validSettings = validateAll();
	var frmSetts = document.getElementById("frmSettings");
	
	if(validSettings){		
		// Pseudo-random number between 0 and 1 to be appended to the window name to make that window unique.
		var x = Math.random();
		// Title of the new window.
		var winName = "RMASS" + x;
		// Regexp used to remove "0." from the window title.  A "." is not allowed in the window name.
		var re = /0\./g;
		
		// Remove "0." from the window name.
		winName = winName.replace(re, "");
		
		window.open("", winName, "scrollbars=yes,resizable=yes,toolbar=yes,status=yes,menubar=yes,width=720,height=550");
		
		frmSetts.hdnInitTime.value = initTime;
		frmSetts.target = winName;
		frmSetts.submit();
	}
}