// define namespace if not yet defined
if ( typeof ( EDRV2 ) == 'undefined' )
{
	EDRV2 = {};
}

/****************************************************
EDR general utilities (static functions).

Provides bunch of general utility functions.
*****************************************************/
EDRV2 =
{
	displayObjectProperties: function ( obj, recurse, prefix, propsToIgnore )
	{
		/// <summary>Display object property values.</summary>
		/// <param name="obj">Object to enumerate.</param>
		/// <param name="recurse">True to recurse through properties.</param>
		/// <param name="prefix">Prefix for recursion.</param>
		/// <param name="propsToIgnore">Array of property names to ignore.</param>

		// flag whether to recurse
		var recursive = recurse || false;

		// prefix for the property/function name and it is passed in during the recursion
		// process
		var p = EDRV2.trim( prefix || '' );

		var ignoreList = propsToIgnore || [];
		if ( !( ignoreList instanceof Array ) )
		{
			ignoreList = [ignoreList];
		}

		// build msg
		var msg = '';
		if ( obj != null )
		{
			var typeOfProp = '';
			var skip = false;

			for ( var i in obj )
			{
				// skip this prop?
				skip = false;
				for ( var j = 0; j < ignoreList.length; j++ )
				{
					if ( ignoreList[j] == i )
						skip = true;
					else if ( ( i == 'EDRParent' ) || ( i == 'base' ) )
						skip = true;

					if ( skip ) break;
				}

				typeOfProp = typeof ( obj[i] );
				// EDRParent and base are 2 reserved property names for EDR framework objects
				// so we are not going to recurse through them
				if ( ( !skip ) && ( typeOfProp != 'function' ) )
				{
					try
					{
						if ( typeof obj[i] == 'object' )
						{

							if ( obj[i] != null )
								msg += p + i + '=[object]\n';
							else
								msg += p + i + '=(null)' + '\n';

							// check if we need to do recursive
							if ( recursive == true ) msg += EDRV2.displayObjectProperties( obj[i], recursive, p + i + '.' );
						}
						else
						{
							msg += p + i + '=' + obj[i] + '\n';
						}
					}
					catch ( e )
					{
						// error is thrown if failed to get the value
						msg += i + '--FAILED TO ENUMERATE--\n';
					}
				}
				else if ( typeOfProp != 'function' )
				{
					// EDRParent is specific for EDR JS object to link current object to its parent -- effectively creating circular reference
					if ( obj[i] != null )
						msg += p + i + '=[' + typeOfProp + ']\n';
					else
						msg += p + i + '=(null)' + '\n';
				}
			}
		}

		return msg;
	},

	trim: function ( value )
	{
		/// <summary>Trims leading and trailing whitespaces/</summary>
		/// <param name="value">String to trim.</param>

		// clean value
		var val = value || '';
		if ( val == '' ) return '';

		// use regexp to trim
		try
		{
			/*
			copied from http://blog.stevenlevithan.com/archives/faster-trim-javascript
			*/
			var str = val.replace( /^\s\s*/, '' );
			var ws = /\s/;
			var i = str.length;
			while ( ws.test( str.charAt( --i ) ) );

			return str.slice( 0, i + 1 );
		}
		catch ( e )
		{
			return '';
		}
	},

	copyObjectData: function ( src, dest )
	{
		/// <summary>Copies value of properties from src to dest objects.</summary>
		/// <param name="src">Object to copy from.</param>
		/// <param name="dest">Object to copy to.</param>
		/// <remarks>This method will only copy properties with the same name (case sensitive).</remarks>

		// nothing to do
		if ( ( src == null ) || ( dest == null ) ) return dest;

		var propTypeOf = null;
		for ( var destProp in dest )
		{
			propTypeOf = typeof ( src[destProp] );
			if ( ( propTypeOf != 'undefined' ) && ( propTypeOf != 'function' ) ) dest[destProp] = src[destProp];
		}

		return dest;
	},

	bindFunction: function ( fn, context )
	{
		/// <summary>Binds function execution to a specific context.</summary>
		/// <param name="fn">Function (pointer) to be called.</param>
		/// <param name="context">Context to execute function with (null := global context).</param>
		/// <remarks>
		/// Function binding is useful when creating callback function (which is parameterless) with parameter
		/// and also callback function to execute under different context. See unit test page for more
		/// examples.
		/// </remarks>
		if ( fn == null ) return null;

		// remove the first 2 arguments passed in to this function (fn and context)
		// args contains additional parameters to this function
		var args = Array.prototype.slice.call( arguments, 2 );

		// create a closure - this is how function binding works!
		return function ()
		{
			var innerArgs = Array.prototype.slice.call( arguments );
			var finalArgs = args.concat( innerArgs );

			// .apply() executes the function by settings 2 things:
			// 1. the context the function is executed in (null = global)
			// 2. final parameters list
			return fn.apply( context, finalArgs );
		};
	},
		
	getEnumKeyFromValue: function (enumTypes, enumValue)
	{
		/// <summary>Gets the key (or text) for the enum value</summary>
		/// <param name="enumTypes">The enumeration that the value is defined in</param>
		/// <param name="enumValue">The enum value to be used to search for the resulting key</param>
		
		//Loop the enum items to find a match, and then return the matching enumeration item name
		for (var type in enumTypes)
		{
			if (enumTypes[type] == enumValue) { return type.toLowerCase(); } //Hey look, we found a match, so return it!
		}
	}
	
};
/****************************************************
EDR general utilities (static functions).
*****************************************************/

/****************************************************
EDRV2.HTTP utilities class.

Provides utilities for posting to URL.
*****************************************************/
EDRV2.HTTP =
{
    /*
    UserAgent
		
    User agent to use when using HTTP request object.
    */
    userAgent: 'Mozilla/5.0 (compatible; MSIE 9.0; EDR DVG JSLib;)',
	
	htmlReservedCharacters: { '&': '&amp;', '<': '&lt;', '>': '&gt;' },
	
	encodeHTMLReservedChar: function (charToEncode)
	{
        /// <summary>Encodes HTML reserved chars.</summary>
        /// <param name="charToEncode">Character to encode.</summary>
		
		charToEncode = charToEncode || '';
		if (charToEncode == '') return '';
		
		return EDRV2.HTTP.htmlReservedCharacters[charToEncode] || charToEncode;
	},
	
	htmlEncode: function (html)
	{
        /// <summary>Encodes HTML reserved chars.</summary>
        /// <param name="html">HTML string to encode.</summary>
		
		// set to empty string if not specified
		html = html || '';
		if (html == '') return '';
		
		return html.replace(/[&<>]/g, EDRV2.HTTP.encodeHTMLReservedChar);
	},

    createHTTPRequest: function ()
    {
        /// <summary>Creates HTTP request object.</summary>
        var httpReq = null;

        if (window.XMLHttpRequest)
            httpReq = new XMLHttpRequest(); // new browsers
        else if (window.ActiveXObject)
            httpReq = new ActiveXObject('Microsoft.XMLHTTP'); // IE

        return httpReq;
    },

    requestGet: function (url)
    {
        /// <summary>Post to URL using GET method.</summary>
        /// <param name="url">URL to post to.</summary>

        try
        {
            // get HTTP req object
            var httpReq = EDRV2.HTTP.createHTTPRequest();
            if (httpReq == null) throw new Error('Unable execute HTTP GET: Unable to create HTTP request object.');

            var usrAgent = navigator.userAgent || EDRV2.HTTP.userAgent;

            // post to URL
            httpReq.open('GET', url, false);
            httpReq.setRequestHeader('User-Agent', usrAgent);
            httpReq.send(null);

            // parse content type
            var contentType = EDRV2.HTTP.parseContentType(httpReq.getResponseHeader('Content-Type'));

            // retrieve data
            var resp = { contentType: contentType.contentType, encodingType: contentType.encodingType, contentLength: httpReq.getResponseHeader('Content-Length'), data: httpReq.responseText };

            delete httpReq;
            httpReq = null;

            return resp;
        }
        catch (e)
        {
            throw e
        }
    },

    requestPost: function (url, data, fullContentType, execOnAsynchComplete, asynchData)
    {
        /// <summary>Post to URL using POST method.</summary>
        /// <param name="url">URL to post to.</param>
        /// <param name="data">Data to post.</param>
        /// <param name="fullContentType">Content type (if null application/x-www-form-urlencoded will be used.</param>
        /// <param name="execOnAsynchComplete">Function pointer for callback method (asynch) - params must be (response) Ex. function setData(resp){...}</param>
        /// <param name="asynchData">The data that is to be attached to the callback for asynch requests</param>
        try
        {
            //Set our asynch indicator
            var isAsynchRequested = false;
            if ((typeof (execOnAsynchComplete) != 'undefined') && (execOnAsynchComplete != null)) { isAsynchRequested = true; }

            // get HTTP req object
            var httpReq = EDRV2.HTTP.createHTTPRequest();
            if (httpReq == null) throw new Error('Unable to execute HTTP POST: Unable to create HTTP request object.');

            //Setup up the ready state change event handler if asynch
            if (isAsynchRequested)
            {
                httpReq.onreadystatechange = function ()
                {
                    if (httpReq.readyState == 4)
                    {
                        if (httpReq.status >= 200 && httpReq.status < 300 || httpReq.status == 304)
                        {                                                                              
                            // parse content type
                            var contentType = EDRV2.HTTP.parseContentType(httpReq.getResponseHeader('Content-Type'));

                            // retrieve data
                            var resp = { contentType: contentType.contentType, encodingType: contentType.encodingType, contentLength: httpReq.getResponseHeader('Content-Length'), data: httpReq.responseText, contextData: asynchData };

                            delete httpReq;
                            httpReq = null;

                            //Execute the callback function
                            execOnAsynchComplete(resp);

                        }
                        else { throw new Error("Request was unsuccessful: " + httpReq.status); }
                    }
                }
            }

            // post to URL
            httpReq.open('POST', url, isAsynchRequested);

            var usrAgent = navigator.userAgent || EDR.HTTP.UserAgent;
            httpReq.setRequestHeader('User-Agent', usrAgent);

            if (fullContentType)
                httpReq.setRequestHeader('Content-Type', fullContentType);
            else
                httpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

            if (data)
                httpReq.setRequestHeader('Content-Length', data.length);
            else
                httpReq.setRequestHeader('Content-Length', 0);

            httpReq.send(data);

            if (!isAsynchRequested)
            {
                // parse content type
                var contentType = EDRV2.HTTP.parseContentType(httpReq.getResponseHeader('Content-Type'));

                // retrieve data
                var resp = { contentType: contentType.contentType, encodingType: contentType.encodingType, contentLength: httpReq.getResponseHeader('Content-Length'), data: httpReq.responseText };

                delete httpReq;
                httpReq = null;

                return resp;
            }
            else { return; }
        }
        catch (e)
        {
            throw e;
        }
    },

    parseContentType: function (contentType)
    {
        /// <summary>Parse value from Content-Type header.</summary>
        /// <param name="contentType">Value from Content-Type header.</param>

        // resp object
        var resp = { contentType: null, encodingType: null };

        if (contentType == null) return resp;

        // split by ;
        var tokens = contentType.split(';');

        resp.contentType = tokens[0];
        resp.encodingType = tokens[1];

        return resp;
    },

    createDataString: function (nameValuePairs)
    {
        /// <summary>Creates the data string that can be used to send to httphandler</summary>
        /// <param name="nameValuePairs">JSON objects consisting of name / value properties</param>
        var result = '';
        for (var i = 0; i < nameValuePairs.length; i++)
        {
            if (i > 0) result += '&';
            result += nameValuePairs[i].name + '=' + nameValuePairs[i].value;
        }
        return result;
    },

    createDataStringWithURL: function (url, nameValuePairs)
    {
        /// <summary>Creates the data string that can be used to send to httphandler - will examine url parameters if present</summary>
        /// <param name="nameValuePairs">JSON objects consisting of name / value properties</param>

        //Validate and prep
        if (url == null) { return ""; }
        url = EDRV2.trim(url);
        var finalNameValuePairs = [];
        var finalURLWithParams = '';
        if (nameValuePairs == null) { nameValuePairs = []; }

        //Parse URL and see if we need to add the items to the nameValuePairs array
        var queryString = url.split("?");
        var params = [];
        if (queryString.length == 2) { params = queryString[1].split("&"); }
        var param = [];
        var paramToAdd = null;
        var itemPresent = false;
        for (var i = 0; i < params.length; i++)
        {
            //If it is not already in the nameValuePair listing then add it
            param = params[i].split("=");
            if (param.length == 2)
            {
                paramToAdd = ({ name: param[0], value: param[1] });
                itemPresent = false;
                for (var j = 0; j < nameValuePairs.length; j++)
                {
                    if (paramToAdd.name == nameValuePairs[j].name)
                    {
                        //Item present in the nameValuePairs so we can just exit
                        itemPresent = true;
                        break;
                    }
                }
                if (!itemPresent) { finalNameValuePairs.push(paramToAdd); } //Not in there, so we need to add it to our url array						
            }
        }

        //Now build the final url with the parameters (specified nameValuePairs will override current url params if both are present
        for (var i = 0; i < nameValuePairs.length; i++)
        {
            finalNameValuePairs.push(nameValuePairs[i]);
        }

        //Build the param string
        var paramString = EDRV2.HTTP.createDataString(finalNameValuePairs);
        finalURLWithParams = queryString[0];
        if (paramString.length > 0) { finalURLWithParams += '?'; }
        finalURLWithParams += paramString;

        //Build and return the final url with params
        return finalURLWithParams;
    }

};
/****************************************************
EDRV2.HTTP utilities class.
*****************************************************/

/****************************************************
EDRV2.XML utilities class.

Provides utilities for working w/ XML.
*****************************************************/
EDRV2.XML =
{
	fromString: function ( xmlString )
	{
		/// <summary>Returns xmlString as XmlDocument object.</summary>
		/// <param name="xmlString">Xml formatted string data.</param>
		try
		{
			var parser = null;

			if ( window.ActiveXObject )
			{
				// IE
				parser = new ActiveXObject( 'Microsoft.XMLDOM' );
				parser.async = false;
				parser.loadXML( xmlString );
				return parser;
			}
			else if ( window.DOMParser )
			{
				// Mozilla
				parser = new DOMParser();
				return parser.parseFromString( xmlString, 'text/xml' );
			}

			// nothing found
			throw new Error( 'Unable to load XmlDocument: Unable to create Xml parser object.' );
		}
		catch ( e )
		{
			throw e;
		}
	},

	fromHTTPGet: function ( url )
	{
		/// <summary>Returns response from URL as XmlDocument.</summary>
		/// <param name="url">URL to post to.</param>

		try
		{
			// get data
			var resp = EDRV2.HTTP.requestGet( url );

			if ( resp.data == '' )
				throw new Error( 'Unable to load XmlDocument (HTTP GET): Server did not return any data.' );
			else
				return EDRV2.XML.fromString( resp.data ); // return XmlDoc
		}
		catch ( e )
		{
			throw e;
		}
	},

	fromHTTPPost: function ( url, data, contentType )
	{
		/// <summary>Returns response from URL as XmlDocument.</summary>
		/// <param name="url">URL to post to.</summary>
		/// <param name="data">Data to post.</summary>
		/// <param name="fullContentType">Content type (if null application/x-www-form-urlencoded will be used.</summary>

		try
		{
			// get data
			var resp = EDRV2.HTTP.requestPost( url, data, contentType );

			if ( resp.data == '' )
				throw new Error( 'Unable to load XmlDocument (HTTP POST): Server did not return any data.' );
			else
				return EDRV2.XML.fromString( resp.data ); // return XmlDoc
		}
		catch ( e )
		{
			throw e;
		}
	},

	createXPathEvaluator: function ()
	{
		/// <summary>Returns XPath evaluator (for X-path query).</summary>
		try
		{
			return new XPathEvaluator();
		}
		catch ( ex )
		{
			throw ex;
		}
	},

	serializeXML: function ( xmlDoc )
	{
		/// <summary>Returns Xml string representation of XmlDocument.</summary>
		/// <param name="xmlDoc">XmlDocument to be serialized.</param>

		try
		{
			// return empty string
			if (xmlDoc == null) return '';

			if (window.XMLSerializer)
			{
				// Mozilla and others (IE 9 supports the interface but
				// does not implement the function
				try
				{
					var ser = new XMLSerializer();
					return ser.serializeToString(xmlDoc.documentElement);
				}
				catch (e) 
				{
				}
			}
			
			if (xmlDoc.xml)
			{
				// IE
				return xmlDoc.xml;
			}

			// at this point nothing else we can do
			throw Error('Unable to serialize XML: Browser does not support interface.');
		}
		catch ( e )
		{
			throw e;
		}
	}
};
/****************************************************
EDRV2.XML utilities class.
*****************************************************/

/****************************************************
EDRV2.VALIDATION utilities class.

Provides basic validations utility.
*****************************************************/
EDRV2.VALIDATION =
{
	isValidEmailSyntax: function ( email )
	{
		/// <summary>Returns whether email has a valid syntax.</summary>
		/// <param name="email">Email to validate.</summary>

		//Preconditions
		email = EDRV2.trim( email || '' );
		if ( email == '' ) return false;

		//Regex matching		
		if ( email.match( /\s/ ) != null ) { return false; } //White space test
		if ( email.match( /[\.]{2}|[\-]{2}/ ) != null ) { return false; } //Multiple .. or --
		if ( email.match( /^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}$/ ) == null ) { return false; } //Invalid email syntax

		return true;  //Valid
	}
};
/****************************************************
EDRV2.VALIDATION utilities class.
*****************************************************/

/****************************************************
EDRV2.DOM utilities class.

Provides DOM specific utilities.
*****************************************************/
EDRV2.DOM =
{
	getElement: function (elem)
	{
		/// <summary>Returns reference to the DOM element.</summary>
		/// <param name="elem">Element ID (if passed in as String) else assumed as DOM element object.</param>
		/// <remarks>
		/// elem is allowed to be passed in as either String (element ID) or DOM element itself to make it easier
		/// to generalize a function call but it is recommended to call this function just for element ID.
		/// </remarks>
		try
		{
			// nothing to do
			elem = elem || '';
			if (elem == '') return null;

			// check if elem is string - if so this is the ID
			if (typeof (elem) == 'string')
				return document.getElementById(elem); 	// min browser version supported by EDR JS is compatible w/ this  function - no need to do xbrowser check.
			else
				return elem;
		}
		catch (e)
		{
			throw e;
		}
	},

	getWindowSize: function ()
	{
		/// <summary>Returns viewable browser window size.</summary>
		var width = 0;
		var height = 0;
		var browserType = 'UNKNOWN';

		try
		{
			if ((typeof (window.innerWidth) == 'number') || (typeof (window.innerHeight) == 'number'))
			{
				// new browsers
				browserType = 'NewBrowser';
				width = window.innerWidth;
				height = window.innerHeight;
			}
			else if ((document.documentElement) && (document.documentElement.clientWidth || document.documentElement.clientHeight))
			{
				// ie 6
				browserType = 'IE 6';
				width = document.documentElement.clientWidth;
				height = document.documentElement.clientHeight;
			}
			else if ((document.body) && (document.body.clientWidth || document.body.clientHeight))
			{
				browserType = 'IE Old';
				width = document.body.clientWidth;
				height = document.body.clientHeight;
			}

			return { height: height, width: width, browserType: browserType };
		}
		catch (e)
		{
			throw e;
		}
	},

	getWindowTotalSize: function ()
	{
		/// <summary>Returns total browser window size (including scrollable area).</summary>
		var width = 0;
		var height = 0;
		var browserType = 'UNKNOWN';

		try
		{
			if (document.body.scrollWidth && document.body.scrollHeight)
			{
				// all but Explorer Mac         
				browserType = 'IE';
				height = document.body.scrollHeight;
				width = document.body.scrollWidth;
			}
			else if ((typeof (window.innerWidth) == 'number') || (typeof (window.innerHeight) == 'number'))
			{
				// new browsers
				browserType = 'NewBrowser';
				width = window.innerWidth + window.scrollMaxX;
				height = window.innerHeight + window.scrollMaxY;
			}
			else if (document.body.offsetHeight && document.body.offsetWidth)
			{
				// works in Explorer 6 Strict, Mozilla (not FF) and Safari         
				browserType = 'Offset Values';
				height = document.body.offsetHeight;
				width = document.body.offsetWidth;
			}
			else if ((document.documentElement) && (document.documentElement.clientWidth || document.documentElement.clientHeight))
			{
				// ie 6
				browserType = 'IE 6';
				width = document.documentElement.clientWidth;
				height = document.documentElement.clientHeight;
			}
			else if ((document.body) && (document.body.clientWidth || document.body.clientHeight))
			{
				browserType = 'IE Old';
				width = document.body.clientWidth;
				height = document.body.clientHeight;
			}

			return { height: height, width: width, browserType: browserType };
		}
		catch (e)
		{
			throw e;
		}
	},

	getScrollOffset: function ()
	{
		/// <summary>Returns the current scroll coordinates.</summary>
		var y = 0;
		var x = 0;

		try
		{
			var pageOffset = self.pageYOffset || null;
			var docElem = document.documentElement || null;
			var docBody = document.body || null;

			if (pageOffset != null) // all except Explorer   
			{
				y = self.pageYOffset;
				x = self.pageXOffset;
			}
			else if ((docElem != null) && (docElem.scrollTop != null))
			{
				// Explorer 6 Strict   
				y = document.documentElement.scrollTop;
				x = document.documentElement.scrollLeft;
			}
			else if (docBody != null)
			{
				// all other Explorers   
				y = document.body.scrollTop;
				x = document.body.scrollLeft;
			}

			return { scrollX: x, scrollY: y };
		}
		catch (e)
		{
			throw e;
		}
	},

	getElementPosition: function (elem)
	{
		/// <summary>Returns the element position.</summary>
		/// <param name="elem">DOM element.</param>
		try
		{
			var curTop = curLeft = 0;

			if ((elem != null) && (elem.offsetParent))
			{
				do
				{
					curTop += elem.offsetTop;
					curLeft += elem.offsetLeft;

				} while (elem = elem.offsetParent);
			}

			return { top: curTop, left: curLeft };
		}
		catch (e)
		{
			throw e;
		}
	},

	getElementSize: function (elem)
	{
		/// <summary>Returns the element size.</summary>
		/// <param name="elem">DOM element.</param>

		try
		{
			var retVal = { width: 0, height: 0 };

			if (elem != null)
			{
				// check if element is visible or not because if the element is not visible offsetHeight and offsetWidth
				// is 0

				var isVis = EDRV2.DOM.isElementVisible(elem, null);
				if (isVis == false)
				{
					EDRV2.DOM.showElement(elem, false);
					retVal.width = elem.offsetWidth;
					retVal.height = elem.offsetHeight;
					EDRV2.DOM.hideElement(elem, false);
				}
				else
				{
					retVal.width = elem.offsetWidth;
					retVal.height = elem.offsetHeight;
				}
			}

			return retVal;
		}
		catch (e)
		{
			throw e;
		}
	},

	setElementPosition: function (elem, position, useWindowAsContainer)
	{
		/// <summary>Set element to a specific position on the browser.</summary>
		/// <param name="elem">DOM element.</param>
		/// <param name="position">One of EDRV2.DOM.popupDIV.prototype.POSITIONS values.</param>
		/// <param name="useWindowAsContainer">True to calculate based on browser viewport, False to calculate based on parent.</param>

		// validation
		if ((typeof (elem) == 'undefined') || (elem == null)) return false;

		try
		{
			// get elem size
			var elemSize = EDRV2.DOM.getElementSize(elem);
			if (elemSize == null) throw new Error('Div size is not available.');

			// get parent size
			var parSize = null;
			if (useWindowAsContainer)
				parSize = EDRV2.DOM.getWindowSize();
			else
				parSize = EDRV2.DOM.getElementSize(elem.offsetParent);

			// validate parent
			if (parSize == null) throw new Error('Parent element size is not available.');

			// calculate top and left
			var top = 0;
			var left = 0;

			switch (position)
			{
				case EDRV2.DOM.popupDIV.prototype.POSITIONS.TopLeft:
					top = 0;
					left = 0;
					break;

				case EDRV2.DOM.popupDIV.prototype.POSITIONS.TopMiddle:
					top = 0;
					left = (parSize.width - elemSize.width) / 2;
					break;

				case EDRV2.DOM.popupDIV.prototype.POSITIONS.TopRight:
					top = 0;
					left = parSize.width - elemSize.width;
					break;

				case EDRV2.DOM.popupDIV.prototype.POSITIONS.MiddleLeft:
					top = (parSize.height - elemSize.height) / 2;
					left = 0;
					break;

				case EDRV2.DOM.popupDIV.prototype.POSITIONS.MiddleMiddle:
					top = (parSize.height - elemSize.height) / 2;
					left = (parSize.width - elemSize.width) / 2;
					break;

				case EDRV2.DOM.popupDIV.prototype.POSITIONS.MiddleRight:
					top = (parSize.height - elemSize.height) / 2;
					left = parSize.width - elemSize.width;
					break;

				case EDRV2.DOM.popupDIV.prototype.POSITIONS.BottomLeft:
					top = parSize.height - elemSize.height;
					left = 0;
					break;

				case EDRV2.DOM.popupDIV.prototype.POSITIONS.BottomMiddle:
					top = parSize.height - elemSize.height;
					left = (parSize.width - elemSize.width) / 2;
					break;

				case EDRV2.DOM.popupDIV.prototype.POSITIONS.BottomRight:
					top = parSize.height - elemSize.height;
					left = parSize.width - elemSize.width;
					break;

				default:
					throw new Error('Invalid position: ' + position);
			}

			// get the screen off set if the parent is window
			if (useWindowAsContainer)
			{
				var winOffset = EDRV2.DOM.getScrollOffset();
				top += winOffset.scrollY;
				left += winOffset.scrollX;
			}

			// change top left
			EDRV2.DOM.applyElementStyle(elem, 'top: ' + top + 'px; left: ' + left + 'px;');
		}
		catch (e)
		{
			e.message = 'Unable to set element position: ' + e.message;
			throw e;
		}
	},

	applyElementStyle: function (elem, cssStyle)
	{
		/// <summary>Applies CSS style to element.</summary>
		/// <param name="elem">DOM element.</param>
		/// <param name="cssStyle">CSS formatted style (attribute=value - multiple separated by semi-colon).</param>
		/// <remarks>cssStyle must be in CSS format such as background-color: Green; border: 1px solid Blue;</remarks>

		try
		{
			// validate
			if ((typeof (elem) == 'undefined') || (elem == null)) return;
			if ((typeof (elem.style) == 'undefined') || (elem.style == null)) return;

			cssStyle = EDRV2.trim(cssStyle);
			if (cssStyle == '') return;

			// split style by ;
			var tokens = cssStyle.split(';');
			var token = '';
			var style = null;

			for (i = 0; i < tokens.length; i++)
			{
				// trim
				token = EDRV2.trim(tokens[i]);
				if (token != '')
				{
					// split by :
					style = token.split(':');

					// expecting 2 tokens
					if (style.length == 2)
					{
						// element 0 is the stylename - lowercase for later use
						style[0] = EDRV2.trim(style[0]).toLowerCase();
						style[1] = EDRV2.trim(style[1]);

						// convert stylename to the property name
						// all properties starts w/ lowecase
						// multi-words property name is camel case, multi-words string stylename is separated by -
						// so run regexp that capatilize the first char after - and remove the - itself (thus, we convert string stylename to propertyname)
						style[0] = style[0].replace(/(\-[a-zA-Z])/gi, function (m) { return m.charAt(1).toUpperCase(); });

						// set tyle
						elem.style[style[0]] = style[1];
					}
				}
			}

			return;
		}
		catch (e)
		{
			throw e;
		}
	},

	getElementStyle: function (elem, cssAttributeNames)
	{
		/// <summary>Returns element style in CSS format.</summary>
		/// <param name="elem">DOM element.</param>
		/// <param name="cssAttributeNames">CSS attribute name or an array of CSS attribute names (null or not specified will return all).</param>

		try
		{
			// validate
			if ((typeof (elem) == 'undefined') || (elem == null)) throw new Error('Unable to get DOM element style: Invalid DOM element.');
			if ((typeof (elem.style) == 'undefined') || (elem.style == null)) throw new Error('Unable to get DOM element style: DOM element does not have style object.');

			var cssAttrs = [];
			var isSingleAttr = false;
			if ((typeof (cssAttributeNames) != 'undefined') && (cssAttributeNames != null))
			{
				if (cssAttributeNames instanceof Array)
				{
					// use the specified array
					cssAttrs = cssAttributeNames;
				}
				else
				{
					// assume it is a single attribubte
					isSingleAttr = true;
					cssAttrs.push(cssAttributeNames);
				}
			}

			// get style collection
			var styleColl = elem.currentStyle || elem.style;

			// use the new standard to pull css styles if available
			var useComputedStyle = false;
			if (document.defaultView && document.defaultView.getComputedStyle) useComputedStyle = true;

			// splitting the logic into 2 to make it easier
			var css = '';
			var cssProp = '';
			var cssKey = '';
			var cssValue = '';

			if (cssAttrs.length == 0)
			{
				// get all styles
				for (cssProp in styleColl)
				{
					// replace capital letter with - + the char
					cssKey = cssProp.replace(/([A-Z])/g, function (m) { return '-' + m.toLowerCase(); });

					if (useComputedStyle)
					{
						css += cssKey + ': ' + document.defaultView.getComputedStyle(elem, "").getPropertyValue(cssKey) + '; ';
					}
					else
					{
						if ((typeof (styleColl[cssProp]) != 'function') && (styleColl[cssProp] != null) && (styleColl[cssProp] != ''))
						{
							css += cssKey + ': ' + styleColl[cssProp] + '; ';
						}
					}
				}
			}
			else
			{
				// get specific
				for (var i = 0; i < cssAttrs.length; i++)
				{
					// convert for attribute format to property format
					cssProp = cssAttrs[i].replace(/(\-[a-zA-Z])/gi, function (m) { return m.charAt(1).toUpperCase(); });

					if (useComputedStyle)
					{
						if (isSingleAttr)
							return document.defaultView.getComputedStyle(elem, "").getPropertyValue(cssAttrs[i]);
						else
							css += cssAttrs[i] + ': ' + document.defaultView.getComputedStyle(elem, "").getPropertyValue(cssAttrs[i]) + '; ';
					}
					else
					{
						if ((typeof (styleColl[cssProp]) != 'function') && (styleColl[cssProp] != null) && (styleColl[cssProp] != ''))
						{
							if (isSingleAttr)
								return styleColl[cssProp];
							else
								css += cssAttrs[i] + ': ' + styleColl[cssProp] + '; ';
						}
					}
				}
			}

			if (isSingleAttr)
				return null;
			else
				return css;
		}
		catch (e)
		{
			throw e;
		}
	},

	isElementVisible: function (elem, useCSSVisibility)
	{
		/// <summary>Returns whether element is visible or not.</summary>
		/// <param name="elem">DOM element.</param>
		/// <param name="">True check visibility value, False check display value, null (or not specified) check both.</param>

		try
		{
			// validation
			if (elem == null) throw new Error('Unable to check DOM element visibility: DOM element does not exist.');

			// get status for both values
			var isVisibilityVisible = true;
			var isDisplayVisible = true;

			var visibilityValue = EDRV2.trim(EDRV2.DOM.getElementStyle(elem, 'visibility'));
			var displayValue = EDRV2.trim(EDRV2.DOM.getElementStyle(elem, 'display'));

			if (visibilityValue.toLowerCase() == 'hidden') isVisibilityVisible = false;
			if (displayValue.toLowerCase() == 'none') isDisplayVisible = false;

			if ((typeof (useCSSVisibility) == 'undefined') || (useCSSVisibility == null))
			{
				return (isDisplayVisible && isVisibilityVisible)
			}
			else if (useCSSVisibility == true)
			{
				return isVisibilityVisible;
			}
			else
			{
				return isDisplayVisible;
			}
		}
		catch (e)
		{
			throw e;
		}
	},

	toggleElementVisibility: function (elem, useCSSVisibility)
	{
		/// <summary>Toogles DOM element visibility.</summary>
		/// <param name="elem">DOM element.</param>
		/// <param name="">True - change visibility value, False - change display value (default).</param>

		try
		{
			useCSSVisibility = useCSSVisibility || false;

			// get current status
			var isVisible = EDRV2.DOM.isElementVisible(elem, useCSSVisibility);
			if (isVisible)
				EDRV2.DOM.hideElement(elem, useCSSVisibility);
			else
				EDRV2.DOM.showElement(elem, useCSSVisibility);
		}
		catch (e)
		{
			throw e;
		}
	},

	hideElement: function (elem, useCSSVisibility)
	{
		/// <summary>Hide DOM element.</summary>
		/// <param name="elem">DOM element.</param>
		/// <param name="">True - change visibility value, False - change display value (default).</param>

		try
		{
			useCSSVisibility = useCSSVisibility || false;

			if (useCSSVisibility)
				elem.style.visibility = 'hidden';
			else
				elem.style.display = 'none';
		}
		catch (e)
		{
			throw e;
		}
	},

	showElement: function (elem, useCSSVisibility)
	{
		/// <summary>Show DOM element.</summary>
		/// <param name="elem">DOM element.</param>
		/// <param name="">True - change visibility value, False - change display value (default).</param>

		try
		{
			useCSSVisibility = useCSSVisibility || false;

			if (useCSSVisibility)
				elem.style.visibility = 'visible';
			else
				elem.style.display = 'block';
		}
		catch (e)
		{
			throw e;
		}
	}
};
/****************************************************
EDRV2.DOM utilities class.
*****************************************************/

/****************************************************
EDRV2.DOM.EVENT utilities class.

Provides DOM specific event utilities.
*****************************************************/
EDRV2.DOM.EVENT =
{
	getEvent: function ( event )
	{
		/// <summary>Returns event object (x-browser).</summary>
		/// <param name="event">DOM event object from browser.</param>
		return event ? event : window.event;
	},

	getEventTarget: function ( event )
	{
		/// <summary>Returns the DOM element that TRIGGERED the event.</summary>
		/// <param name="event">DOM event object from browser.</param>
		try
		{
			if ( ( typeof ( event ) == 'undefined' ) || ( event == null ) ) throw new Error( 'Unable to get event target: Invalid event object.' );
			return event.target || event.srcElement;
		}
		catch ( e )
		{
			throw e;
		}
	},

	getEventSourceTarget: function ( event, elem )
	{
		/// <summary>Returns DOM element that TRAPS the event.</summary>
		/// <param name="event">DOM event object from browser.</param>
		/// <param name="elem">DOM element that TRAPS the event (shortcut for IE calls).</param>
		/// <remarks>IE does not support .currentTarget (element that actually traps the event). So this method will return the .srcElement instead.</remarks>
		try
		{
			if ((typeof (event) == 'undefined') || (event == null)) throw new Error('Unable to get event source target: Invalid event object.');
			return event.currentTarget || elem || event.srcElement;
		}
		catch ( e )
		{
			throw e;
		}
	},

	addEventHandler: function ( elem, eventName, eventHandler, useCapturePhase )
	{
		/// <summary>Adds event handler.</summary>
		/// <param name="elem">DOM element to trap event for.</param>
		/// <param name="eventName">DOM event name.</param>
		/// <param name="eventHandler">Function pointer to event handler.</param>
		/// <param name="useCapturePhase">True to use the capture phase, False to use bubble phase (default).</param>
		/// <returns> JSON { domElement: elem, eventName: eventName, handler: evt, useCapturePhase: useCapturePhase }</returns>
		try
		{
			// validate
			if ( elem == null ) throw new Error( 'Unable to add event handler: Invalid DOM element.' );
			if ( EDRV2.trim( eventName ) == '' ) throw new Error( 'Unable to add event handler: Invalid event name.' );
			if ( eventHandler == null ) throw new Error( 'Unable to add event handler: Invalid event callback function.' );

			// default to bubble phase
			useCapturePhase = useCapturePhase ? useCapturePhase : false;

			// if this is IE - create a closure to set the currentTarget property
			var evt = null;
			if ( window.event )
				evt = EDRV2.bindFunction( eventHandler, elem );
			else
				evt = eventHandler;

			if ( elem.addEventListener )
			{
				elem.addEventListener( eventName, evt, useCapturePhase );
			}
			else if ( elem.attachEvent )
			{
				elem.attachEvent( 'on' + eventName, evt );
			}
			else
			{
				// just assign it as property
				elem['on' + eventName] = evt;
			}

			return { domElement: elem, eventName: eventName, handler: evt, useCapturePhase: useCapturePhase };
		}
		catch ( e )
		{
			throw e;
		}
	},

	removeEventHandler: function ( elem, eventName, eventHandler, useCapturePhase )
	{
		/// <summary>Removes event handler.</summary>
		/// <param name="elem">DOM element to trap event for.</param>
		/// <param name="eventName">DOM event name.</param>
		/// <param name="eventHandler">Function pointer to event handler.</param>
		/// <param name="useCapturePhase">True to use the capture phase, False to use bubble phase (default).</param>

		try
		{
			// validate
			if ( elem == null ) throw new Error( 'Unable to remove event handler: Invalid DOM element.' );
			if ( EDRV2.trim( eventName ) == '' ) throw new Error( 'Unable to remove event handler: Invalid event name.' );

			// default to bubble phase
			useCapturePhase = useCapturePhase ? useCapturePhase : false;

			if ( elem.removeEventListener )
			{
				elem.removeEventListener( eventName, eventHandler, useCapturePhase );
			}
			else if ( elem.detachEvent )
			{
				elem.detachEvent( 'on' + eventName, eventHandler );
			}
			else
			{
				// just assign it as property
				elem['on' + eventName] = null;
			}
		}
		catch ( e )
		{
			throw e;
		}
	},

	stopPropagation: function ( event )
	{
		/// <summary>Stops event propagation (bubbling).</summary>
		/// <param name="event">DOM event object.</param>

		try
		{
			if ( event.stopPropagation )
				event.stopPropagation();
			else
				event.cancelBubble = true;
		}
		catch ( e )
		{
			throw e;
		}
	},

	preventDefault: function ( event )
	{
		/// <summary>Prevents default event behavior from being executed.</summary>
		/// <param name="event">DOM event object.</param>

		try
		{
			if ( event.preventDefault )
				event.preventDefault();
			else
				event.returnValue = false;
		}
		catch ( e )
		{
			throw e;
		}
	}
};
/****************************************************
EDRV2.DOM.EVENT utilities class.
*****************************************************/

/****************************************************
EDRV2.ObjectBase base class.

Provides base class for EDR JS objects.
*****************************************************/
EDRV2.ObjectBase = function ()
{
	/// <summary>Creates new instance of EDRV2.ObjectBase.</summary>
	if ( this instanceof EDRV2.ObjectBase )
	{
		this.base = null;
		this.isUsable = true;
	}
	else
	{
		return new EDRV2.ObjectBase();
	}
};

// Inheritance Properties
EDRV2.ObjectBase.prototype.constructor = EDRV2.ObjectBase;
EDRV2.ObjectBase.prototype.base = null; 		// set by derive class

// Properties
EDRV2.ObjectBase.prototype.isUsable = true;
EDRV2.ObjectBase.prototype.errorMessage = '';
EDRV2.ObjectBase.prototype.disposableDOMEvents = [];	// array of DOM events added by using EDRV2.DOM.EventUtil.addEventHandler()

// Methods
EDRV2.ObjectBase.prototype.dispose = function ()
{
	// <summary>Disposes current instance (reclaim expensive resources).</summary>
	this.isUsable = false;

	if ( this.disposableDOMEvents != null )
	{
		var evt = null;

		for ( var i = 0; i < this.disposableDOMEvents.length; i++ )
		{
			// remove event handler
			// { domElement: elem, eventName: eventName, handler: evt, useCapturePhase: useCapturePhase }
			evt = this.disposableDOMEvents[i];

			EDRV2.DOM.EVENT.removeEventHandler(evt.domElement, evt.eventName, evt.handler, evt.useCapturePhase);

			// deref
			this.disposableDOMEvents[i] = null;
		}

		delete this.disposableDOMEvents;
		this.disposableDOMEvents = [];
	}

	return null;
};

EDRV2.ObjectBase.prototype.buildErrorMessage = function ( header, msgs, isHTML )
{
	/// <summary>Build error message.</summary>
	/// <param name="header">Error header.</param>
	/// <param name="msgs">Error messages (displayed as bullets if passed in as array).</param>
	/// <param name="isHTML">Build error message as HTML (using UL).</param>

	//if ( ( typeof ( header ) == 'undefined' ) || ( header == null ) )
	//{
	//	header = 'Unspecified error';
	//}

	var errMsgs = null;

	if ( ( typeof ( msgs ) == 'undefined' ) || ( msgs == null ) )
	{
		// not specified - empty array.
		errMsgs = [];
	}
	else if ( msgs instanceof Array )
	{
		// already an array - just use it
		errMsgs = msgs;
	}
	else
	{
		// not an array - convert into array
		errMsgs = [];
		errMsgs.push( msgs );
	}

	if ( ( typeof ( isHTML ) == 'undefined' ) || ( isHTML == null ) )
	{
		isHTML = false;
	}

	// build error message
	var msg = '';

	if ( errMsgs.length == 0 )
	{
		msg = EDRV2.trim(header);
	}
	else
	{
		var lineBreak = '';
		if ( isHTML )
			lineBreak = '<br />\n';
		else
			lineBreak = '\n';

		var listStart = '\n', listEnd = '\n', itemStart = '- ', itemEnd = '\n';
		if ( isHTML )
		{
			listStart = '<ul>\n';
			listEnd = '</ul>\n';
			itemStart = '<li> ';
			itemEnd = '</li>\n';
		}
		
		if ( ( typeof ( header ) != 'undefined' ) && ( header != null ) )
		{
			msg = header + ':' + lineBreak;
		}
		msg += listStart;

		for ( var i = 0; i < errMsgs.length; i++ )
		{
			msg += itemStart + errMsgs[i] + itemEnd;
		}

		msg += listEnd;
	}

	return msg;
};

EDRV2.ObjectBase.prototype.toString = function ()
{
	/// <summary>Returns string representation of object.</summary>
	return EDRV2.displayObjectProperties( this, false );
};
/****************************************************
EDRV2.ObjectBase base class.
*****************************************************/

/****************************************************
EDRV2.DOM.popupDIV class.

Provides functionality to pop-up a DIV.
*****************************************************/

EDRV2.DOM.popupDIV = function (popupDivID, position, useWindow)
{
	/// <summary>Creates new popup DIV control.</summary>
	/// <param name="popupDivID">Main container for the popup.</summary>
	/// <param name="position">Popup position.</summary>
	/// <param name="useWindow">True - use entire browser window as container (default). False - use parent as container.</summary>

	if (this instanceof EDRV2.DOM.popupDIV)
	{
		try
		{
			// inheritance
			EDRV2.ObjectBase.apply(this, arguments);
			this.base = EDRV2.ObjectBase.prototype;

			// verify popup DIV
			var popup = EDRV2.DOM.getElement(popupDivID);
			if (popup == null) throw new Error('Invalid POPUP DIV id: ' + popupDivID);

			this.popupDivID = popupDivID;

			// verify position
			position = position || this.POSITIONS.Unknown;
			switch (position)
			{
				case this.POSITIONS.TopLeft:
				case this.POSITIONS.TopMiddle:
				case this.POSITIONS.TopRight:
				case this.POSITIONS.MiddleLeft:
				case this.POSITIONS.MiddleMiddle:
				case this.POSITIONS.MiddleRight:
				case this.POSITIONS.BottomLeft:
				case this.POSITIONS.BottomMiddle:
				case this.POSITIONS.BottomRight:
					// save position
					this.popupPosition = position;
					break;

				default:
					throw new Error('Invalid position: ' + position);
			}

			// use window
			if (typeof (useWindow) != 'undefined')
			{
				this.useWindowAsContainer = useWindow;
			}

			// all set
			this.isUsable = true;
		}
		catch (e)
		{
			this.isUsable = false;
			this.errorMessage = 'Unable to initialize popup addon: ' + e.message;
		}
	}
	else
		return new EDRV2.DOM.popupDIV(popupDivID, position, useWindow);
};

// inheritance
EDRV2.DOM.popupDIV.prototype = new EDRV2.ObjectBase();
EDRV2.DOM.popupDIV.prototype.constructor = EDRV2.DOM.popupDIV;

// events
EDRV2.DOM.popupDIV.prototype.onShow = null;
EDRV2.DOM.popupDIV.prototype.onClose = null;

// enums
EDRV2.DOM.popupDIV.prototype.POSITIONS = {Unknown: 0, TopLeft: 1, TopMiddle: 2, TopRight: 3, MiddleLeft: 4, MiddleMiddle: 5, MiddleRight: 6, BottomLeft: 7, BottomMiddle: 8, BottomRight: 9};

// properties
EDRV2.DOM.popupDIV.prototype.popupDivID = null;
EDRV2.DOM.popupDIV.prototype.popupPosition = 0;
EDRV2.DOM.popupDIV.prototype.useWindowAsContainer = true;

// methods
EDRV2.DOM.popupDIV.prototype.show = function ()
{
	/// <summary>Show popup.</summary>
	if (this.isUsable == false) return;

	try
	{
		// get elem size
		var elem = EDRV2.DOM.getElement(this.popupDivID);
		if (elem == null) throw new Error('Div element not available.');

		// set element position
		EDRV2.DOM.setElementPosition(elem, this.popupPosition, this.useWindowAsContainer);

		// open
		EDRV2.DOM.showElement(elem, false);

		// raise event
		if (this.onShow != null) this.onShow();
	}
	catch (e)
	{
		e.message = 'Unable to show popup: ' + e.message;
		throw e;
	}
};

EDRV2.DOM.popupDIV.prototype.hide = function ()
{
	/// <summary>Hides popup.</summary>
	if (this.isUsable == false) return;

	try
	{
		var elem = EDRV2.DOM.getElement(this.popupDivID);
		if (elem == null) throw new Error('Div element not available.');

		// close 
		EDRV2.DOM.hideElement(elem, false);

		// raise event
		if (this.onClose != null) this.onClose();
	}
	catch (e)
	{
		e.message = 'Unable to hide popup: ' + e.message;
		throw e;
	}
};

/****************************************************
EDRV2.DOM.popupDIV class.
*****************************************************/


/****************************************************
EDRV2.DOM.notificationWindow class.
*****************************************************/

EDRV2.DOM.notificationWindow = function (popupDivID, position, useWindow, headerDivID, contentDivID, closeElemID) {
	///<summary> Create a notification window </summary>
	/// <param name="popupDivID">Main container for the popup.</summary>
	/// <param name="position">Popup position.</summary>
	/// <param name="useWindow">True - use entire browser window as container (default). False - use parent as container.</summary>
	/// <param name="headerDivID">Div ID to display header text in.</summary>
	/// <param name="contentDivID">Div ID to display content in.</summary>
	/// <param name="closeElemID">Element ID to trigger close window.</summary>
	if (this instanceof EDRV2.DOM.notificationWindow) {
		try {
			//inheritance
			EDRV2.DOM.popupDIV.apply(this, arguments);
			this.base = EDRV2.DOM.popupDIV.prototype;

			var elem = null;
			
			// verify elements
			elem = EDRV2.DOM.getElement(headerDivID);
			if (elem == null) throw new Error('Header DIV not found.');
			
			elem = EDRV2.DOM.getElement(contentDivID);
			if (elem == null) throw new Error('Content DIV not found.');

			elem = EDRV2.DOM.getElement(closeElemID);
			if (elem == null) throw new Error('Close element not found.');

			//fill in the rest of the properties
			this.headerDivID = headerDivID;
			this.contentDivID = contentDivID;
			this.closeElemID = closeElemID;

			// trap click event on close elem (which should be the last item checked above
			var nw = this;
			this.disposableDOMEvents.push(EDRV2.DOM.EVENT.addEventHandler(elem, 'click', function () { nw.hide(); }));
		}
		catch (e) {
			this.isUsable = false;
			this.errorMessage = 'Unable to initialize notification window: ' + e.message;
		}
	}
	else {
		return new EDRV2.DOM.notificationWindow(popupDivID, position, useWindow, headerDivID, contentDivID, closeElemID);
	}
};

//inheritance
EDRV2.DOM.notificationWindow.prototype = new EDRV2.DOM.popupDIV();

//constructor
EDRV2.DOM.notificationWindow.prototype.constructor = EDRV2.DOM.notificationWindow;

//properties
EDRV2.DOM.notificationWindow.prototype.headerDivID = '';
EDRV2.DOM.notificationWindow.prototype.contentDivID = '';
EDRV2.DOM.notificationWindow.prototype.closeElemID = '';

//methods
EDRV2.DOM.notificationWindow.prototype.show = function (header, content, useContentAsIs) {
	///<summary> Display the notification window </summary>
	/// <param name="header">Header text.</summary>
	/// <param name="content">Content text.</summary>
	/// <param name="useContentAsIs">True to use the content as is, False to run it through buildErrorMessage().</summary>
	///<remarks> Extends the EDRV2.DOM.popupDIV.show method. </remarks>
	try {
		if (this.isUsable == false) return false;

		//update the header text and content
		var headerContainer = EDRV2.DOM.getElement(this.headerDivID); 
		if (headerContainer != null) headerContainer.innerHTML = EDRV2.trim(header);

		var contentContainer = EDRV2.DOM.getElement(this.contentDivID); 
		if (contentContainer != null) 
		{
			// don't run through buildErrorMessage() if request to use content as is
			if (useContentAsIs)
				contentContainer.innerHTML = content;
			else
				contentContainer.innerHTML = this.buildErrorMessage(null, content, true);
		}

		//call the parent's show method
		this.base.show.call(this);
		
		return true;
	}
	catch (e) 
	{
		e.message = 'Unable to show notification window: ' + e.message;
		throw e;
	}
};
/****************************************************
EDRV2.DOM.notificationWindow class.
*****************************************************/


/****************************************************
EDRV2.NameValue class.

Provides name-value object.
*****************************************************/
EDRV2.NameValue = function ( name, value )
{
	if ( this instanceof EDRV2.NameValue )
	{
		// inheritance
		EDRV2.ObjectBase.apply( this, arguments );
		this.base = EDRV2.ObjectBase.prototype;

		this.name = name || '';
		this.value = value || null;
	}
	else
		return new EDRV2.NameValue( name, value );
};

EDRV2.NameValue.prototype = new EDRV2.ObjectBase();
EDRV2.NameValue.prototype.constructor = EDRV2.NameValue;

EDRV2.NameValue.prototype.name = '';
EDRV2.NameValue.prototype.value = null;

EDRV2.NameValue.prototype.toString = function ()
{
	return 'name: [' + this.name + '] value: [' + this.value + ']';
};
/****************************************************
EDRV2.NameValue class.
*****************************************************/

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Name:     EDRV2.EventCollector
//Purpose:  Allows registration and execution of events and their subscriptions
//Desc:     This class implements an augmented singleton pattern that allows for private / public variables and methods
EDRV2.EventCollector = function()
{
    //Private variables
    var m_handlers = {};

    function addHandlerExecute(type, handler)
    {
        //Check to see if we have handlers for the type already defined
        if (typeof m_handlers[type] == "undefined") { m_handlers[type] = []; }  //Not yet defined, so do so
        m_handlers[type].push(handler);  //Add the handler
    };

    function fireExecute(event)
    {
        //Prep - ensure we have a target
        if (!event.target) { event.target = this; } //Ensure there is a target for the event

        //If we have handlers, then call them one by one
        if (m_handlers[event.type] instanceof Array)
        {
            var handlers = m_handlers[event.type]
            for (var i = 0; i < handlers.length; i++)
            {
                handlers[i](event); //call it!
            }
        }
    };

    function removeHandlerExecute(type, handler)
    {
        //If we have items, then find the match and delete it
        if (m_handlers[type] instanceof Array)
        {
            var handlers = m_handlers[event.type]
            for (var i = 0; i < handlers.length; i++)
            {
                if (handlers[i] === handler) { break; }  //Find the match, exit when found
            }

            //Remove the item at the index of the match
            handlers.splice(i, 1);
        }
    };

    //Public methods and properties
    var eventObserverSingleton =
    {
        addHandler: function (type, handler)
        {
            addHandlerExecute(type, handler); //Forward the call
        },
        fire: function (event)
        {
            fireExecute(event);  //Forward the call
        },
        removeHandler: function (type, handler)
        {
            removeHandlerExecute(type, handler);  //Forward the call to unregister the event handler
        }
    }
    return eventObserverSingleton;
} ();


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Name:     EDRError
//Purpose:  Custom implementation of the Error class
//Desc:     Adds EDR specific functionality to the base Error class
EDRV2.EDRError = function (message)
{
    ///<summary>EDRError represents a custom derived error class that allows for data items</summary>
    ///<remarks>Extends Error</remarks>
    if (this instanceof EDRV2.EDRError)
    {
        Error.apply(this, arguments);
        this.base = Error.prototype;
    }
    else
    {
        return new EDRV2.EDRError(message);
    }
};
EDRV2.EDRError.prototype = new Error();
EDRV2.EDRError.prototype.constructor = EDRV2.EDRError;
EDRV2.EDRError.prototype.data = []; //Format {source:, name:, value: }

EDRV2.rethrowError = function (err, errDataItems, dataItemMethod)
{
    ///<summary>Rethrows an EDRError with the dataitems concatenated</summary>
    /// <param name="err">The error thrown in the caller</summary>
    /// <param name="errDataItems">The data items to be added</summary>

    //Declare work variables
    var eError = null;

    //Preconditions
    if ((typeof (err) == 'undefined') || (err == null)) { throw new Error("err is required"); }
    if ((typeof (errDataItems) == 'undefined') || (errDataItems == null)) { errDataItems = []; }
    if (!(errDataItems instanceof Array))
    {
        //Not an array, so make it one!
        var dataItem = errDataItems;
        errDataItems = [];
        errDataItems.push(dataItem);
    }

    //Make sure we have an EDRError
    if (err instanceof EDRV2.EDRError) { eError = err; } //We have a EDRError, so we are good
    else
    {
        //Not an EDRError, so create it
        eError = new EDRV2.EDRError();
        eError.message = err.message;
        eError.number = err.number;
        eError.name = err.name;
        delete err;
    }

    //Update the method values on the data where not set, using the param is supplied
    if (EDRV2.trim(dataItemMethod) != '')
    {
        for (i = 0; i < errDataItems.length; i++)
        {
            if ((typeof (errDataItems[i].method) == 'undefined') || (errDataItems[i].method == null) || (errDataItems[i].method == '')) { errDataItems[i].method = dataItemMethod; }
        }
    }

    //Now set the data and return the updated / new EDR error
    eError.data = eError.data.concat(errDataItems);
    throw eError;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Name:     EDRErrorData
//Purpose:  Data container for EDRErrors
//Desc:     Allows data details to be created
EDRV2.EDRErrorData = function (errData)
{
    ///<summary>Represents error data for use in the EDRError object</summary>
    /// <param name="errData">The error data: ex. { method: "DKTest.testErrors", message: "somename", showable: true, value: 'someval' }</summary>
    if (this instanceof EDRV2.EDRErrorData)
    {
        if (errData != null) { EDRV2.copyObjectData(errData, this); } //convert from JSON to our object so all default values, etc. are correctly set
    }
    else { return new EDRV2.EDRErrorData(errData); }
};
EDRV2.EDRErrorData.prototype.constructor = EDRV2.EDRErrorData;
EDRV2.EDRErrorData.prototype.method = '';
EDRV2.EDRErrorData.prototype.message = '';
EDRV2.EDRErrorData.prototype.showable = false;
EDRV2.EDRErrorData.prototype.value = '';







