function KeyValuePair(key, value)
{
	this.key = key;
	this.value = value;
}

function DictionaryStack(element)
{
	// private properties
	this.mElement = element;
	this.mList = new Array();
	
	// methods
	this.get_CurrentValue = function()
	{
		if (this.mList.length > 0)
			return this.mList[this.mList.length - 1].value;
		else
			return null;
	}
	
	this.push = function(key, value)
	{
		// check whether item with this key already exists, if it does, ignore this Push
		if (this.findByKey(key) != null)
			return;

		var lItem = new KeyValuePair(key, value);
		this.mList.push(lItem);
		
		this.refresh();
	}
	
	this.findByKey = function(key)
	{
		for (var i = 0; i < this.mList.length; i++)
		{
			var lItem = this.mList[i];
			if (lItem.key == key)
				return lItem;
		}
		return null;
	}
	
	this.remove = function(key)
	{
		var lItem = this.findByKey(key);
		if (lItem != null)
		{
			var lIndex = Array.indexOf(this.mList, lItem);
			this.mList.splice(lIndex, 1);
			
			this.refresh();
		}
	}
}

function EnableDisableValidators(element, enabled, validatorType)
{
	// process child elements of this element that are validators
	var validatorElements = element.getElementsByTagName("span");
	
	for (var i = 0; i < validatorElements.length; i++)
	{
		var validator = validatorElements[i];
		
		if (typeof (Page_Validators) != 'undefined')
		{
		   if (Array.indexOf(Page_Validators, validator) > -1 && (!validatorType || !validator.validatortype || validator.validatortype == validatorType))
		    {
			    var lValidatorEnabled = enabled;
			    if (lValidatorEnabled && validator.validatortype == "Required")
				    lValidatorEnabled = $getExt(validator.controltovalidate).get_RequiredStack().get_CurrentValue();

			    ValidatorEnable(validator, lValidatorEnabled);
		    }
		}
	}
}

Array.indexOf = function(array, element)
{
	for (var i = 0; i < array.length; i++)
	{
		if (array[i] == element)
			return i;
	}
	return -1;
}

String.prototype.startsWith = function(value)
{
	if (typeof(value) != "string")
		throw("IllegalArgumentException: Must pass a string to String.prototype.startsWith()");
	
	var lEnd = value.length;
	if (lEnd > this.length)
		return false;
	else
		return this.substring(0, lEnd) == value;
}

String.prototype.endsWith = function(value)
{
	if (typeof(value) != "string")
		throw("IllegalArgumentException: Must pass a string to String.prototype.endsWith()");
	
	var lStart = this.length - value.length;
	return this.substring(lStart) == value;
}

Number.prototype.toCurrencyString = function(useCommaSeparator)
{
	var lMinus = "";
	if (this < 0)
		lMinus = "-";

	var lNumberAndDecimal = this.toFixed(2).toString().split('.', 2);
	var lWholePart = lNumberAndDecimal[0];	
	var lDecimalPart = lNumberAndDecimal[1];
	
	lWholePart = Math.abs(lWholePart);
	var lStringNumber = lWholePart.toString();
	
	if (useCommaSeparator)
	{
		var lNewString = [];
		while (lStringNumber.length > 3)
		{
			var lThreeDigitNumber = lStringNumber.substr(lStringNumber.length - 3);
			lNewString.unshift(lThreeDigitNumber);
			lStringNumber = lStringNumber.substr(0, lStringNumber.length - 3);
		}

		if (lStringNumber.length > 0)
			lNewString.unshift(lStringNumber)

		var lDelimiter = ",";
		lStringNumber = lNewString.join(lDelimiter);
	}
	
	if(lStringNumber == "NaN")
	{
		lStringNumber = "0";
		lDecimalPart = "00";
	}
		
	var lFormattedString = lMinus + lStringNumber + "." + lDecimalPart;
	return lFormattedString;
}

Date.fromDDMMMYY = function(dateString)
{
	if (dateString == "")
		return;
	
	var lMonthAbbrevs = getMonthAbbrevsArray();
	var lIndex = -1, lMonth = -1;
	for (var i = 0; i < 12; i++)
	{
		if (dateString.indexOf(lMonthAbbrevs[i].toUpperCase()) > 0)
		{
			lIndex = dateString.indexOf(lMonthAbbrevs[i].toUpperCase());
			lMonth = i;
			break;
		}
	}
	
	if (lIndex == -1)
		throw "Could not find matching month";
	
	var lDay = dateString.substr(0, lIndex);
	var lYear = "20" + dateString.substr(lIndex + 3, lIndex + 5);

	if (lMonth != -1 && lDay != "" && lYear != "")
	{
		// Check if date is in the past and set to today's date
		var lDate = new Date(Number(lYear), lMonth, Number(lDay));
		return lDate;
	}
	else
	{
		throw "Invalid date";
	}
}

Object.extend = function(destination, source)
{
  for (var property in source)
    destination[property] = source[property];
  return destination;
}

if (!window.RequiredStacks) var RequiredStacks = { };

if (!window.Element) var Element = { };

Element.Methods =
{
	// begin Visible property
	get_Visible : function(element)
	{
		return element.style.display == "";
	},
	set_Visible : function(element, visible)
	{
		element.style.display = (visible) ? "" : "none";
		EnableDisableValidators(element, visible);
	},
	// end Visible property
	
	// begin Enabled property
	get_Enabled : function(element)
	{
		return !element.disabled;
	},
	set_Enabled : function(element, enabled)
	{
		// process child elements of this element that are input fields
		var inputElements = element.getElementsByTagName("input");
		for (var i = 0; i < inputElements.length; i++)
			inputElements[i].disabled = !enabled;
			
		// process child elements of this element that are select fields
		inputElements = element.getElementsByTagName("select");
		for (var i = 0; i < inputElements.length; i++)
			inputElements[i].disabled = !enabled;
			
		// process child elements of this element that are anchor tags
		inputElements = element.getElementsByTagName("a");
		for (var i = 0; i < inputElements.length; i++)
		    inputElements[i].disabled = !enabled;

		// process child elements of this element that are span tags
		inputElements = element.getElementsByTagName("span");
		for (var i = 0; i < inputElements.length; i++)
		    inputElements[i].disabled = !enabled;

		element.disabled = !enabled;
		//ASP.NET renders a SPAN tag around checkbox which it disables server-side
		if( element.type == "checkbox"
		    && element.parentElement != null
		    && element.parentElement.type == undefined)
		{
		    if( ! enabled )
		        element.parentElement.setAttribute('disabled', 'true');
		    else
		        element.parentElement.removeAttribute('disabled');
		}
		    
		
		EnableDisableValidators(element, enabled);
	},
	// end Enabled property
	
	// begin Required property
	set_Required : function(element, enabled)
	{
		EnableDisableValidators(element, enabled, "Required");
	},
	// end Required property
	
	// begin RequiredStack property
	get_RequiredStack : function(element)
	{
		if (!RequiredStacks[element.id])
		{
			var lRequiredStack = new DictionaryStack(element);
			lRequiredStack.refresh = function()
			{
				var lCurrentValue = this.get_CurrentValue();
				if (lCurrentValue == null) lCurrentValue = false;
				//this.mElement.set_Required(lCurrentValue); // Bug occuring when using this method.
				EnableDisableValidators(this.mElement, lCurrentValue, "Required");
			}
			RequiredStacks[element.id] = lRequiredStack;
		}
		
		return RequiredStacks[element.id];
	},
	// end RequiredStack property
	
	// begin toggleRequired method
	toggleRequired : function(element, key, value, container)
	{
		if (element.get_RequiredStack().findByKey(key) == null)
		{
			if (value != null)
				element.get_RequiredStack().push(key, value);
		}
		else if (value == null)
		{
			element.get_RequiredStack().remove(key);
		}
		
		EnableDisableValidators(container, true);
	},
	// end toggleRequired method
	
	// begin toggleVisibility method
	toggleVisibility : function(element, enableDisableValidators)
	{
		if (enableDisableValidators)
			element.set_Visible(!element.get_Visible());
		else
			element.style.display = (element.style.display == "none") ? "" : "none";
	}
	// end toggleVisibility method
}

var $A = Array.from = function(iterable)
{
	if (!iterable) return [];
	if (iterable.toArray)
	{
		return iterable.toArray();
	}
	else
	{
		var results = [];
		for (var i = 0, length = iterable.length; i < length; i++)
			results.push(iterable[i]);
		return results;
	}
}

Element.extend = function(element)
{
    if (!element || element._extended)
        return element;

    var methods = {}, cache = Element.extend.cache;
    Object.extend(methods, Element.Methods);

    for (var property in methods)
    {
        var value = methods[property];
        if (typeof value == 'function' && !(property in element))
            element[property] = cache.findOrStore(value);
    }
    
    //Dolphin: Break IE memory leaks in update panel
    element.dispose = function()
	{
	    element.get_Visible = null;
	    element.set_Visible = null;
	    element.get_Enabled = null;
	    element.set_Enabled = null;
	    element.set_Required = null;
	    element.get_RequiredStack = null;
	    element.toggleRequired = null;
	    element.toggleVisibility = null;
	    element._extended = null;
	}

    element._extended = function() { };
}

Element.extend.cache =
{
	findOrStore : function(value)
	{
		return this[value] = this[value] || function() {
			return value.apply(null, [this].concat($A(arguments)));
		}
	}
};

//Get's requested control and extends it to include client side validation related properties and methods
function $getExt(id)
{
	var lElement = document.getElementById(id);

	if (lElement == null)
		return null;
	
	Element.extend(lElement);
	
	return lElement;
}

function $openPopupWindow(href, name, width, height)
{
	window.open(href, name, "width=" + width + ", height=" + height + ", menubar=no, resizable=yes, scrollbars=yes");
	return false;
}

var postBackElement;

///////////////////////
//AJAX beginrequest event handler to display the UpdateProgress control when a control that causes
//the prices to be recalculated has been clicked
///////////////////////
function showUpdateProg(sender, args)
{
    var prm = Sys.WebForms.PageRequestManager.getInstance();

    if (prm.get_isInAsyncPostBack())
        args.set_cancel(true);

    postBackElement = args.get_postBackElement();

    //Array is build up through serverside calls to RegisterArrayDeclaration
    if (gProgressTriggersArray )
    {
        var index = Array.indexOf( gProgressTriggersArray, postBackElement.id );
        if( index > -1)
        {
            var updProg = $get('upd_prog');
            if (updProg)
            {
                updProg.style.display = 'block';
                if (gProgressTextArray[index] != '') //Only override the default progress update text if the array entry has been populated
                {
                    var updLbl = updProg.getElementsByTagName("span")[0];
                    updLbl.childNodes[0].data = gProgressTextArray[index];
                }
            }
        }
    }
}

///////////////////////
//AJAX beginrequest event handler to hide the UpdateProgress control after the ASYNC postback
//has completed
///////////////////////
function hideUpdateProg(sender, args)
{
    if (gProgressTriggersArray &&
        postBackElement &&
        Array.indexOf(gProgressTriggersArray, postBackElement.id) > -1) 
    {
        $get('upd_prog').style.display = 'none';

        var lElement = document.getElementById("executePostScripts");

        if (lElement != null && lElement != undefined) 
        {
            eval(lElement.value);
        }
    }
}

///////////////////////
// Utility method called on startup to wire in the above event handlers
///////////////////////
function initUpdateProgHandlers()
{
    // If partial page rendering is disabled Sys.WebForms will be undefined
    if( typeof( Sys.WebForms ) != "undefined" )
    {
        var prm = Sys.WebForms.PageRequestManager.getInstance();
        prm.remove_beginRequest(showUpdateProg); //To avoid adding it multiple times
        prm.add_beginRequest(showUpdateProg);
        prm.remove_endRequest(hideUpdateProg);
        prm.add_endRequest(hideUpdateProg);
    }
}


///////////////////////
//SJAX-as-AJAX substitute XMLHttpRequest object
//See http://weblogs.asp.net/bleroy/archive/2005/12/15/433278.aspx
///////////////////////
var __asyncXmlHttpRequest;

var __syncXmlHttpRequest = function() {
    var _xmlHttp = null;
    if (!__asyncXmlHttpRequest) {
        try {
            _xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch (ex) { }
    }
    else {
        _xmlHttp = new __asyncXmlHttpRequest();
    }

    if (!_xmlHttp) return null;

    this.abort = function() { return _xmlHttp.abort(); }
    this.getAllResponseHeaders = function() { return _xmlHttp.getAllResponseHeaders(); }
    this.getResponseHeader = function(header) { return _xmlHttp.getResponseHeader(header); }
    this.open = function(method, url, async, user, password) {
        return _xmlHttp.open(method, url, false, user, password);
    }
    this.send = function(body) {
        _xmlHttp.send(body);
        this.readyState = _xmlHttp.readyState;
        this.responseBody = _xmlHttp.responseBody;
        this.responseStream = _xmlHttp.responseStream;
        this.responseText = _xmlHttp.responseText;
        this.responseXML = _xmlHttp.responseXML;
        this.status = _xmlHttp.status;
        this.statusText = _xmlHttp.statusText;
        this.onreadystatechange();
    }
    this.setRequestHeader = function(name, value) { return _xmlHttp.setRequestHeader(name, value); }
}

function SetAjaxSyncMode(syncMode) {

    if (!__asyncXmlHttpRequest)
        __asyncXmlHttpRequest = window.XMLHttpRequest;
        
    if (syncMode)
        window.XMLHttpRequest = __syncXmlHttpRequest;
    else
        window.XMLHttpRequest = __asyncXmlHttpRequest;
}

function IsAjaxInSyncMode() {
    return (window.XMLHttpRequest == __syncXmlHttpRequest);
}

function TextAreaAutoSize(sender,max)
{   
    
    var cols = sender.cols;
    var length = Math.round(sender.value.length * 1.1);
    // work out the number of rows we require based on the textarea columns and value length
    var rows = Math.floor(length / cols) + 1;

    // limit rows to the max value (if set)
    if (max != null && max > 0 && rows > max)
        rows = max;

   // alert('max:'+max + ' ,cols:' + cols + ', rows:' + rows + ', length:' + length );

    // set the rows
    sender.rows = rows;
}

function MultiToggle(classToHide, classToShow)
{
    $j('.' + classToHide).hide();
    $j('.' + classToShow).show();
    $j('.' + classToShow).removeAttr('disabled');
}
