//=============================================================================
//
//  MiscFunctions.js
//		This file contains JavaScript functions to handle the miscellaneous 
//		client-side functions 
//
//=============================================================================
	
// Constants

// Functions

function TextAreaMaxLength (oTA, iMaxLength, sMsg) {

	if (oTA.value.length > iMaxLength) {
	
		// truncate value to max length
		oTA.value = oTA.value.substring(0, iMaxLength);
		
		// show message if message is passed
		if (sMsg.length > 0) { alert(sMsg);	}
	}
	
	return true;
}

function setText(o,sText){
	var bCreateTextNode = true
	var oTextNode

	if(o.childNodes.length > 0){
		while (o.firstChild != o.lastChild){
			o.removeChild(o.lastChild)
		}
		if(o.firstChild.nodeType != 3){
			o.removeChild(o.lastChild)
		}else{
			bCreateTextNode = false
		}
	}

	if(bCreateTextNode){
		oTextNode=o.ownerDocument.createTextNode(sText)
		o.appendChild(oTextNode)
	}else{
		o.firstChild.data = sText
	}
}

function getText(o){
	if(o.childNodes.length>0 && o.firstChild.nodeType == 3){
			return o.firstChild.data
	}else{
		return ''
	}
}

// ======================================================================================
//  Cross browser event attaching helper functions
// ======================================================================================

function createAddEventListener(o)
{
    if(!o.addEventListener && o.attachEvent)
    {
	    o.addEventListener = ieAddEventListener;
    }
}

function ieAddEventListener(eventName, handler, capture)
{
    this.attachEvent("on" + eventName, handler);
}

// ======================================================================================
//  Compiled Regular Expression to parse checkbox information
// ======================================================================================

// Submatch $1: Variable name for grid map object
// Submatch $2: Row index
// Submatch $3: Column index
var regExGridAttributes = new RegExp();
regExGridAttributes.compile("^(.+)_(\\d+)_(\\d+)$");

// ======================================================================================
//  "Object Security Control" Object Class
// ======================================================================================

// Constructor
function OSCObject()
{
    this.headers = new Array();
    this.checkboxRows = new Array();
    this.columnUncheckedCount = new Array();
    this.checkedCollection = new Array();
    this.uncheckedCollection = new Array();
}

// Arguments:
//    row - Array of all checkboxes from one row
OSCObject.prototype.addCheckboxRow = function (row)
{
    for(var j = row.length - 1; j >= 0; --j)
    {
        if(row[j].checked)
        {
            this.checkedCollection[j][row[j].id] = row[j];
        }
        else
        {
            this.columnUncheckedCount[j]++;
            this.uncheckedCollection[j][row[j].id] = row[j];
        }
    }
    
    this.checkboxRows.push(row);
}


// Arguments:
//    inputs   - Collection of all input (checkbox) objects in grid
//    colCount - Number of columns in grid
OSCObject.prototype.populate = function (inputs, colCount)
{
    var len = inputs.length; // len: Number of total checkboxes in grid
    var n = colCount;        // n:   Every non-header checkbox in grid
    var j;                   // j:   Current column index
    var row;                 // row: Array representing 1 row of checkboxes
    
    // Headers
    for(j = 0; j < colCount; ++j)
    {
        this.headers.push(inputs[j]);
        this.columnUncheckedCount.push(0);
        this.checkedCollection.push(new Object());
        this.uncheckedCollection.push(new Object());
    }
    
    // Non-headers
    while(n < len)
	{
	    row = new Array();
	    
	    for(j = colCount - 1; j >= 0; --j)
	    {
	        row.push(inputs[n++]);
	    }
	    
		this.addCheckboxRow(row);
	}
}


// This must be called only after populate()
//
// Arguments:
//    myName - String representing the, globally accessed, unique name for the desired OSCObject
//             to be bound to each checkbox.
OSCObject.prototype.init = function (myName)
{
    var row;
    var rows = this.checkboxRows;
    var rowCount = rows.length;
    
    // Headers
    for(var i = 0; i < this.headers.length; ++i)
    {
        this.headers[i].checked = (this.columnUncheckedCount[i] <= 0);
        createAddEventListener(this.headers[i]);
        this.headers[i].addEventListener("click", new Function("selectAll(" + myName + ", " + i + ");"), false);
    }
    
    // Non-headers
    // Do not addEventListener to individual checkboxes here,
    // it is 55% slower (using cross browser compatibility).
    // Instead, addEventListener for additional events and
    // let this be the fixed "onclick" handler.
    for(var i = rowCount - 1; i >= 0 ; --i)
    {
        for(var j = rows[i].length - 1; j >= 0; --j)
        {
            row = rows[i][j];
            row["onclick"] = syncLogic;
            row["gridAttributes"] = myName + "_" + i + "_" + j;
        }
    }
}

// ======================================================================================
//  "Object Security Control" event handlers
// ======================================================================================

// Header checkbox clicked
// 
// Arguments:
//    o   - OSCObject instance
//    col - Index of column to toggle
function selectAll(o, col)
{
    var box, nextColumn;
    var checked = o.headers[col].checked;
    var rows = o.checkboxRows;
    var ncc = o.columnUncheckedCount;
    
    var fromCollection, toCollection, incNoCheckCount;
    
    // Get execution values
    if(checked)
    {
        fromCollection = o.uncheckedCollection[col];
        toCollection   = o.checkedCollection[col];
        increment      = -1;
    }
    else
    {
        fromCollection = o.checkedCollection[col];
        toCollection   = o.uncheckedCollection[col];
        increment      = 1;
    }
    
    // Toggle necessary checkboxes
    for(x in fromCollection)
    {
        box = fromCollection[x];
        
        if(box.disabled)
        {
            continue;
        }
        
        box.checked = checked;
        toCollection[x] = box;
        delete fromCollection[x];
        ncc[col] += increment;
    }
    
    nextColumn = col + increment;
    
    if(o.headers[nextColumn])
    {
        o.headers[nextColumn].checked = checked;
        arguments.callee(o, nextColumn);
    }
}

// Individual checkbox clicked
// 
// Arguments:
//    e - Event object for some browsers
function syncLogic(e)
{
    var gridAttributes = (e && e.target ? e.target : (window.event && window.event.srcElement ? window.event.srcElement : new Object()))["gridAttributes"];
    
    // No event handling mechanism found
    if(!gridAttributes)
    {
        return;
    }
    
    regExGridAttributes.exec(gridAttributes);
    
    var o   = window[RegExp.$1];   // Submatch $1
    var row = parseInt(RegExp.$2); // Submatch $2
    var col = parseInt(RegExp.$3); // Submatch $3
    
    var rows = o.checkboxRows;
    var box = rows[row][col];
    var checked = box.checked;
    
    var fromCollection, toCollection, increment;
    
    if(checked)
    {
        fromCollection = o.uncheckedCollection;
        toCollection = o.checkedCollection;
        increment = -1;
    }
    else
    {
        fromCollection = o.checkedCollection;
        toCollection = o.uncheckedCollection;
        increment = 1;
    }
    
    do
    {
        if(box.disabled)
        {
            continue;
        }
        
        box.checked = checked;
        toCollection[col][box.id] = rows[row][col];
        delete fromCollection[col][box.id];
        o.columnUncheckedCount[col] += increment;
        
        o.headers[col].checked = (o.columnUncheckedCount[col] <= 0); // Check the select all
        
        while((box = rows[row][col += increment]) && box.disabled); // Skip over disabled boxes
    }
    while(box && box.checked != checked);
}

// ======================================================================================
//  Timer Class
// ======================================================================================

// Constructor
function Timer()
{
    this.times = new Array();
}

Timer.prototype.addCheckpoint = function()
{
    this.times.push(getMilliseconds());
}

Timer.prototype.getReport = function()
{
    var result = "======================";
    
    if(this.times.length > 1)
    {
        result += "\nTotal time: " + this.getElapsedTime();
        result += "\n======================";
    }
    
    for(var i = 0; i < this.times.length - 1; i++)
    {
        result += "\nBlock " + (i + 1) + "'s execution time:\n";
        result += (this.times[i+1] - this.times[i]);
        result += "\n======================";
    }
    
    return result;
}

Timer.prototype.showReport = function()
{
    alert(this.getReport());
}

Timer.prototype.getElapsedTime = function()
{
    return (this.times.length > 0) ? (this.times[this.times.length - 1] - this.times[0]) : Number.NaN;
}

// Arguments:
//    d - (Optional) Date() object
function getMilliseconds(d)
{
    if(arguments.length < 1)
    {
        d = new Date();
    }
    
	return ((d.getHours() * 60 + d.getMinutes()) * 60 + d.getSeconds()) * 1000 + d.getMilliseconds();
}

// ======================================================================================

function disableCtl(CtlID, disabled){
	if (document.getElementById(CtlID)) {
		document.getElementById(CtlID).disabled=disabled
	}
}

// ======================================================================================

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
