/* FROM http://www.crockford.com/javascript/inheritance.html */
Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

/* FROM http://www.crockford.com/javascript/remedial.html */
function isAlien(a) {
   return isObject(a) && typeof a.constructor != 'function';
}

function isArray(a) {
    return isObject(a) && a.constructor == Array;
}

function isBoolean(a) {
    return typeof a == 'boolean';
}

function isEmpty(o) {
    var i, v;
    if (isObject(o)) {
        for (i in o) {
            v = o[i];
            if (isUndefined(v) && isFunction(v)) {
                return false;
            }
        }
    }
    return true;
}

function isFunction(a) {
    return typeof a == 'function';
}

function isNull(a) {
    return typeof a == 'object' && !a;
}

function isNumber(a) {
    return typeof a == 'number' && isFinite(a);
}

function isObject(a) {
    return (a && typeof a == 'object') || isFunction(a);
}

function isString(a) {
    return typeof a == 'string';
}

function isUndefined(a) {
    return typeof a == 'undefined';
} 

String.
    method('entityify', function () {
        return this.replace(/&/g, "&amp;").replace(/</g,
            "&lt;").replace(/>/g, "&gt;");
    }).
    /*method('quote', (isThisNetscape4) ? function () {
        var c, i, l = this.length, o = '"';
        for (i = 0; i < l; i += 1) {
            c = this.charAt(i);
            if (c >= ' ') {
                if (c == '\\' || c == '"') {
                    o += '\\';
                }
                o += c;
            } else {
                switch (c) {
                case '\b':
                    o += '\\b';
                    break;
                case '\f':
                    o += '\\f';
                    break;
                case '\n':
                    o += '\\n';
                    break;
                case '\r':
                    o += '\\r';
                    break;
                case '\t':
                    o += '\\t';
                    break;
                default:
                    c = c.charCodeAt();
                    o += '\\u00' + Math.floor(c / 16).toString(16) +
                        (c % 16).toString(16);
                }
            }
        }
        return o + '"';
    }).*/
    method('supplant', function (o) {
        var i, j, s = this, v;
        for (;;) {
            i = s.lastIndexOf('{');
            if (i < 0) {
                break;
            }
            j = s.indexOf('}', i);
            if (i + 1 >= j) {
                break;
            }
            v = o[s.substring(i + 1, j)];
            if (!isString(v) && !isNumber(v)) {
                break;
            }
            s = s.substring(0, i) + v + s.substring(j + 1);
        }
        return s;
    }).
    method('trim', function () {
        return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
    }); 
    
    
if (!isFunction(Function.apply)) {
    Function.method('apply', function (o, a) {
        var r, x = '____apply';
        if (!isObject(o)) {
            o = {};
        }
        o[x] = this;
        switch ((a && a.length) || 0) {
        case 0:
            r = o[x]();
            break;
        case 1:
            r = o[x](a[0]);
            break;
        case 2:
            r = o[x](a[0], a[1]);
            break;
        case 3:
            r = o[x](a[0], a[1], a[2]);
            break;
        case 4:
            r = o[x](a[0], a[1], a[2], a[3]);
            break;
        case 5:
            r = o[x](a[0], a[1], a[2], a[3], a[4]);
            break;
        case 6:
            r = o[x](a[0], a[1], a[2], a[3], a[4], a[5]);
            break;
        default:
            alert('Too many arguments to apply.');
        }
        delete o[x];
        return r;
    });
} 

if (!isFunction(Array.prototype.pop)) {
    Array.method('pop', function () {
        return this.splice(this.length - 1, 1)[0];
    });
}

if (!isFunction(Array.prototype.push)) {
    Array.method('push', function () {
        this.splice.apply(this,
            [this.length, 0].concat(Array.prototype.slice.apply(arguments)));
        return this.length;
    });
}

if (!isFunction(Array.prototype.shift)) {
    Array.method('shift', function () {
        return this.splice(0, 1)[0];
    });
}

if (!isFunction(Array.prototype.splice)) {
    Array.method('splice', function (s, d) {
        var max = Math.max,
            min = Math.min,
            a = [], // The return value array
            e,  // element
            i = max(arguments.length - 2, 0),   // insert count
            k = 0,
            l = this.length,
            n,  // new length
            v,  // delta
            x;  // shift count

        s = s || 0;
        if (s < 0) {
            s += l;
        }
        s = max(min(s, l), 0);  // start point
        d = max(min(isNumber(d) ? d : l, l - s), 0);    // delete count
        v = i - d;
        n = l + v;
        while (k < d) {
            e = this[s + k];
            if (!isUndefined(e)) {
                a[k] = e;
            }
            k += 1;
        }
        x = l - s - d;
        if (v < 0) {
            k = s + i;
            while (x) {
                this[k] = this[k - v];
                k += 1;
                x -= 1;
            }
            this.length = n;
        } else if (v > 0) {
            k = 1;
            while (x) {
                this[n - k] = this[l - k];
                k += 1;
                x -= 1;
            }
        }
        for (k = 0; k < i; ++k) {
            this[s + k] = arguments[k + 2];
        }
        return a;
    });
}

if (!isFunction(Array.prototype.unshift)) {
    Array.method('unshift', function () {
        this.splice.apply(this,
            [0, 0].concat(Array.prototype.slice.apply(arguments)));
        return this.length;
    });
} 

/* THINGS ADDED BY TOWER */

String.method('startsWith', function(prefix)
{
    var prefixLength = prefix.length;
    var thisLength = this.length;
    
    if (prefixLength == thisLength)
    {
        return prefix == this;
    }
    else if (prefixLength < thisLength)
    {
        return this.indexOf(prefix) == 0;
    }
    else
    {
        return false;
    }
});

String.method('endsWith', function(prefix)
{
    var prefixLength = prefix.length;
    var thisLength = this.length;
    
    if (prefixLength == thisLength)
    {
        return prefix == this;
    }
    else if (prefixLength < thisLength)
    {
        return this.indexOf(prefix) == thisLength - prefixLength;
    }
    else
    {
        return false;
    }    
});


//the method looks obvisous but i think i shoudl add in some comment
//this one basically returns true if the parameter string equals the current string
//how to use
// var str1 = "hello World";
// str1.equalsIgnoreCase("HELLO WOrld") would return true.
String.method('equalsIgnoreCase', function(str)
{
	return this.toLowerCase() == str.toLowerCase();
});

// W3C HTML 4.01 doesn't support name attribute in div or span, so we have to use getAttribute
// returns the first element with the given title in the collection of document.TagNames
function getElementByAttribute(tagName, attribute, value)
{
	var elements = document.getElementsByTagName(tagName);

    for (var j=0; j<elements.length; j++) 
    {
        for (var k=0; k<elements[j].attributes.length; k++) 
        {
            if (elements[j].attributes.item(k).nodeName == attribute) 
            {
                if (elements[j].attributes.item(k).nodeValue == value) 
                {
                    return elements[j];
                }
            }
        }
    }
}

//returnt the first element with the given name in the colleciton of TagName
//Example: ele = getElementByName('select', 'udf-documenttype'); will get the name element name udf-documenttype in all the select thingo
function getElementByName(tagName, elementName, type)	//type is for text

{
	var elements = document.getElementsByTagName(tagName);
	
	for(var i = 0; i < elements.length; i++)
	{		
		var ele = elements[i];

		if(ele && ele.name == elementName)
		{	
			return ele;
		}
	}
}

/*
get the text field byname
name is the name of the text field
type is what type it is: text, hidden, select, etc...
this will return the first element that it see, else return nothing. */
function getInputFieldByName(name, type)
{	
	elems = document.getElementsByTagName('input');
	
	for(var i = 0; i < elems.length; i++)
	{
		if(elems[i].type == type && elems[i].name == name)
		{
			return  elems[i];			
		}
	}
	
	return null;
}


function isNumeric(sText)
{
   var ValidChars = "0123456789.";
   var IsNumber=true;
   var Char;

 
   for (i = 0; i < sText.length && IsNumber == true; i++) 
   { 
        Char = sText.charAt(i); 
        if (ValidChars.indexOf(Char) == -1) 
        {
            IsNumber = false;
        }
   }
   return IsNumber;
   
}

//Returnt the next sibling of the specified node element
function getNextElementSibling(node)
{
	do
	{		
		node = node.nextSibling;
		
	}
	while(node && !node.tagName)
	
	return node;
}



/*
ASSOCIATIVE ARRAY - Util for the associative array 
*/

function AssociativeArray()
{}

//check to see if the associative array is empty
AssociativeArray.isEmpty = function (array)
{
	var empty = true;
	
	for(var i in array)
	{
		if(array[i])
		{
			empty = false;
			break;
		}
	}
	
	return empty;	
}

/*
<para> month </para> Has the value of 0 to 11 which mean jan to dec respectively
<output>string </output> return the short name of the month: eg pass in 1 will get Feb, 5 will get Jun etc...
*/

Date.prototype.toShortMonthString = function(month)
{
	var monthShortNames = {0:"Jan", 1:"Feb", 2:"Mar", 3:"Apr", 4:"May", 5:"Jun", 6:"Jul", 7:"Aug", 8:"Sep", 9:"Oct", 10:"Nov", 11:"Dec" };
	
	if(month)
	{
		return monthShortNames[month];	// todo:tong is this file the best place to put this function???
	}
	
	return monthShortNames[this.getMonth()];
}

/**remove  whitespace
*/
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/, ''); };


/**
*Use to throw exception.
*/
function Error(msg)
{
	this.message = msg;
}



function Debug(){}

/**
*setup the div used for debugging purpose. 
*/
Debug.setup = function()
{	
	if(!document.getElementById('debug-info'))
	{
		var debug = document.createElement('div');
		debug.id = 'debug-root';
		
		var ele = document.createElement('div');	
		ele.className = 'debug-info';
		ele.id = 'debug-info';
		debug.insertBefore(ele, null);
		
		var head = document.createElement('div');
		head.innerHTML = "<h1> <font face='Verdana' color='red'> - EAC TRIM DEBUG INFO - </font> </h1> \r \r";
		document.getElementById('body-area-left').insertBefore(head, null);	
		debug.insertBefore(head,ele)
		
		document.getElementById('body-area-left').insertBefore(debug, null);	
	}
	
}

/**
* The Debug function below is only used during development within Tower. This area is at the bottom of the page
* print out the g_content in a readable format
*/
Debug.printGC = function ()
{
	Debug.setup();
	
	var debug = document.getElementById('debug-info');		
	var html = [];
	
	html.push('<br>');
	for(var i in g_content)
	{	
		html.push("<b>" + i + "</b>");
		html.push(' : ');
		
		if(isString(g_content[i]))
		{
			html.push(g_content[i]);
			html.push('<br>');
		}	
		
		if(isObject(g_content[i]))
		{	
			var obj = g_content[i];
			
			html.push(obj.toSource())			
			html.push("<br>");
		}
		
		html.push('<br>');
	}
		
	debug.innerHTML = html.join('');	
	
	window.scroll(0, debug.offsetTop - 20 );
}

/**
*Clear the debug info text
*/
Debug.clear = function()
{
	var debug = document.getElementById('debug-root');	
	debug.innerHTML = "";	
}

/**
*Print out whatever value to the debug area.
*/
Debug.print = function(val)
{
	Debug.setup();
	
	var debug = document.getElementById('debug-info');
	
	debug.innerHTML += val + "<br>"	;
}

/***** Added for the TIPS integration *****/
function newWindow(urlToShow)
{
	var strShowOption = null;
	strShowOptions = "toolbar=0" +
			",resizable=1" + 
			",menubar=0" +
			",scrollbars=1" +
			",status=0" +
			",titlebar=0";
	strShowOptions += ",height=500";
	strShowOptions += ",width=700";

	window.open(urlToShow,'', strShowOptions);
}
