﻿// Avoids the background image flickering in IE 6 (http://www.mister-pixel.com/)
try
{
	document.execCommand("BackgroundImageCache", false, true);
}
catch(err) {}

Type.registerNamespace("Sunny.Web.UI");

window.$Sunny = window.SunnyCommonScripts = Sunny.Web.CommonScripts = {

    _rgbToHex : function(color)
    {
        //rgb(153, 0, 0);
        //becomes
        //#990000
        if (color.toLowerCase().indexOf("rgb") != -1)
        {
	        var hexValue = "#";
	        var colorReplace = function (val) {
		        var newVal = parseInt(val,10).toString(16);
		        hexValue = hexValue + (newVal.length == 1 ? "0"+newVal : newVal);
		        return val;
	        };
	        color=color.replace(/(\d+)/gi,colorReplace);
	        colorReplace = null;
	        return hexValue;
        }
        else
        {
	        return color;
        }
    },

    getOuterSize : function(element)
    {
        var size = $Sunny.getBounds(element);
        var marginBox = $Sunny.getMarginBox(element);

        return {
            width : size.width + marginBox.left + marginBox.right,
            height: size.height + marginBox.top + marginBox.bottom
        }
    },

    getOuterBounds : function(element)
    {
        var size = $Sunny.getBounds(element);
        var marginBox = $Sunny.getMarginBox(element);

        return {
            x :  size.x - marginBox.left,
            y : size.y -  marginBox.top,
            width : size.width + marginBox.left + marginBox.right,
            height: size.height + marginBox.top + marginBox.bottom
        }
    },

    getInvisibleParent : function(element)
	{
		while (element && element != document)
		{
			if ("none" == $Sunny.getCurrentStyle(element, "display", ""))
			{
				return element;
			}
			element = element.parentNode;
		}
		return null;
	},

	addParentVisibilityChangeHandler : function(element, handler)
	{
		if (element)
		{
			if ($Sunny.isIE)
			{
				$addHandler(element, "propertychange", handler);
			}
			else
			{
				element.addEventListener("DOMAttrModified", handler, false);
			}
		}
	},

	removeParentVisibilityChangeHandler : function(element, handler)
	{
	    if (element && handler)
		{
			if ($Sunny.isIE)
			{
				$removeHandler(element, "propertychange", handler);
			}
			else
			{
				element.removeEventListener("DOMAttrModified", handler, false);
			}
		}
	},

	//browser-provided scrollIntoView produces nasty side effects - flickers and/or scrolls the whole page in both IE and FF
	//if the body has scroll and elemenet sis
	//Here is an alternative implementation
	scrollIntoView : function(element)
	{
		//Make sure the element exists and it is a part of some DOM hyerarchy
		if (!element || !element.parentNode) return;

		//Try to find a scrollable parent
		var scrollableParent = null;

		//Apply the scrolling
		var parentHeight = 0;

		var parent = element.parentNode;
		while (parent != null)
		{
			if (parent.tagName == "BODY")
			{
				//The method could be called to find a scrollable parent for an element in a different iframe.
				//In FF the body element does not have its
				var doc = parent.ownerDocument;
				if (!$Sunny.isIE && doc.defaultView && doc.defaultView.frameElement)
				{
					//!Set the height to be equal to the height of the iframe, not the body element!
					parentHeight = doc.defaultView.frameElement.offsetHeight;
				}
				scrollableParent = parent;
				break;
			}

			var overflow = $Sunny.getCurrentStyle(parent, 'overflowY');//We want to know the vertical overflow
			if (overflow == "scroll" || overflow == "auto")
			{
				scrollableParent = parent;
				break;
			}

			parent = parent.parentNode;
		}
		if (!scrollableParent) return;

		//If parent height was not set, set it here
		if (!parentHeight) parentHeight = scrollableParent.offsetHeight;

		//Do the actual magic with 'scrolling into view'
		if (parentHeight < element.offsetTop + element.offsetHeight)//element is below the parent viewport
		{
			scrollableParent.scrollTop = (element.offsetTop + element.offsetHeight) - parentHeight;
		}
		else if (element.offsetTop < scrollableParent.scrollTop) //element is above the parent viewport
		{
			scrollableParent.scrollTop = element.offsetTop;
		}
	},
	
	
    isRightToLeft : function (element)
	{
		while (element && element.nodeType !== 9)
		{
			if (element.dir == "rtl" || $Sunny.getCurrentStyle(element, 'direction') == 'rtl')
				return true;

			element = element.parentNode;
		}
		return false;
	},

	getCorrectScrollLeft : function(element)
    {
        if($Sunny.isRightToLeft(element))
        {
            return -(element.scrollWidth - element.offsetWidth - Math.abs(element.scrollLeft));
        }
        else
        {
            return element.scrollLeft;
        }
    },

    getNextHtmlNode : function(element)
    {
        if (!element || !element.previousSibling) return null;
        while (element.previousSibling)
        {
            if (element.previousSibling.nodeType == 1) return element.previousSibling;
            element = element.nextSibling;
        }
    },

    getPreviousHtmlNode : function(element)
    {
        if (!element || !element.nextSibling) return null;
        while (element.nextSibling)
        {
            if (element.nextSibling.nodeType == 1) return element.nextSibling;
            element = element.nextSibling;
        }
    },

    //Returns the text content of an element
    getTextContent : function(element)
    {
        if (!element) return null;
        if (element.innerText != null) return element.innerText;
        if (element.textContent != null)
        {
            var text = element.textContent;
		    text = text.replace(/<!--(.|\s)*?-->/gi,"");
		    return text;
        }
		return null;
    },

	_borderStyleNames : ['borderTopStyle','borderRightStyle','borderBottomStyle','borderLeftStyle'],
	_borderWidthNames : ['borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth'],
	_paddingWidthNames : ['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft'],
	_marginWidthNames : ['marginTop', 'marginRight', 'marginBottom', 'marginLeft'],
	radControls : [],

	registerControl : function (control)
	{
		if (!Array.contains(this.radControls, control))
			Array.add(this.radControls, control);
	},

	unregisterControl : function (control)
	{
		Array.remove(this.radControls, control);
	},

	repaintChildren : function (parentControl)
	{
		var parentElement = parentControl.get_element();

		for (var i = 0, length = this.radControls.length; i < length; i ++)
		{
	        var control = this.radControls[i];

		    if (control.repaint && this.isDescendant(parentElement, control.get_element()))
				control.repaint();
		}
	},

	_borderThickness: function()
	{
		$Sunny._borderThicknesses = { };

		var div0 = document.createElement('div');
		var div1 = document.createElement('div');

		div0.style.visibility = 'hidden';
		div0.style.position = 'absolute';
		div0.style.fontSize = '1px';

		div1.style.height = '0px';
		div1.style.overflow = 'hidden';

		document.body.appendChild(div0).appendChild(div1);

		var base = div0.offsetHeight;
		div1.style.borderTop = 'solid black';

		div1.style.borderTopWidth = 'thin';
		$Sunny._borderThicknesses['thin'] = div0.offsetHeight - base;

		div1.style.borderTopWidth = 'medium';
		$Sunny._borderThicknesses['medium'] = div0.offsetHeight - base;

		div1.style.borderTopWidth = 'thick';
		$Sunny._borderThicknesses['thick'] = div0.offsetHeight - base;

		if (typeof(div0.removeChild) !== "undefined")
			div0.removeChild(div1);

		document.body.removeChild(div0);
		//Apparently, Safari does not like setting outerHTML on elements not in the document
		//throws NO_MODIFICATION_ALLOWED_ERR: DOM Exception 7
		if (!$Sunny.isSafari)
			div1.outerHTML = null;
		if (!$Sunny.isSafari)
			div0.outerHTML = null;
		div0 = null;
		div1 = null;
	},

	getCurrentStyle : function(element, attribute, defaultValue) {

        var currentValue = null;
        if (element) {
            if (element.currentStyle) {
                currentValue = element.currentStyle[attribute];
            } else if (document.defaultView && document.defaultView.getComputedStyle) {
                var style = document.defaultView.getComputedStyle(element, null);
                if (style) {
                    currentValue = style[attribute];
                }
            }

            if (!currentValue && element.style.getPropertyValue) {
                currentValue = element.style.getPropertyValue(attribute);
            }
            else if (!currentValue && element.style.getAttribute) {
                currentValue = element.style.getAttribute(attribute);
            }
        }

        if ((!currentValue || currentValue == "" || typeof(currentValue) === 'undefined')) {
            if (typeof(defaultValue) != 'undefined') {
                currentValue = defaultValue;
            }
            else {
                currentValue = null;
            }
        }
        return currentValue;
    },

    getInheritedBackgroundColor : function(element) {
        if (!element) return '#FFFFFF';
        var background = $Sunny.getCurrentStyle(element, 'backgroundColor');
        try {
            while (!background || background == '' || background == 'transparent' || background == 'rgba(0, 0, 0, 0)') {
                element = element.parentNode;
                if (!element) {
                    background = '#FFFFFF';
                } else {
                    background = $Sunny.getCurrentStyle(element, 'backgroundColor');
                }
            }
        } catch(ex) {
            background = '#FFFFFF';
        }
        return background;
    },

	getLocation : function(element) {

		// workaround for an issue in getLocation where it will compute the location of the document element.
		// this will return an offset if scrolled.
		//
		if (element === document.documentElement) {
			return new Sys.UI.Point(0,0);
		}

		// Workaround for IE6 bug in getLocation (also required patching getBounds - remove that fix when this is removed)

		//TEKI: When in IE7 in a scenario when item is in a FRAMESET, the location value is wrong. However, using the IE6 code below it works fine
		if (Sys.Browser.agent == Sys.Browser.InternetExplorer /*&& Sys.Browser.version < 7*/) {
			if (element.window === element || element.nodeType === 9 || !element.getClientRects || !element.getBoundingClientRect) return new Sys.UI.Point(0,0);

			// Get the first bounding rectangle in screen coordinates
			var screenRects = element.getClientRects();
			if (!screenRects || !screenRects.length) {
				return new Sys.UI.Point(0,0);
			}
			var first = screenRects[0];

			// Delta between client coords and screen coords
			var dLeft = 0;
			var dTop = 0;

			var inFrame = false;
			try {
				inFrame = element.ownerDocument.parentWindow.frameElement;
			} catch(ex) {
				// If accessing the frameElement fails, a frame is probably in a different
				// domain than its parent - and we still want to do the calculation below
				inFrame = true;
			}

			// If we're in a frame, get client coordinates too so we can compute the delta
			if (inFrame) {
				// Get the bounding rectangle in client coords
				var clientRect = element.getBoundingClientRect();
				if (!clientRect) {
					return new Sys.UI.Point(0,0);
				}

				// Find the minima in screen coords
				var minLeft = first.left;
				var minTop = first.top;
				for (var i = 1; i < screenRects.length; i++) {
					var r = screenRects[i];
					if (r.left < minLeft) {
						minLeft = r.left;
					}
					if (r.top < minTop) {
						minTop = r.top;
					}
				}

				// Compute the delta between screen and client coords
				dLeft = minLeft - clientRect.left;
				dTop = minTop - clientRect.top;
			}

			// Subtract 2px, the border of the viewport in IE6 and IE7(It can be changed in IE6 by applying a border style to the HTML element,
			// but this is not supported by ASP.NET AJAX, and it cannot be changed in IE7.), and also subtract the delta between
			// screen coords and client coords
			var ownerDocument = element.document.documentElement;
            var viewportBorderIE = (Sys.Browser.version < 8) ? 2 : 0;
            
			var position = new Sys.UI.Point(first.left - viewportBorderIE - dLeft + $Sunny.getCorrectScrollLeft(ownerDocument), 
			                                first.top - viewportBorderIE - dTop + ownerDocument.scrollTop);

			if ($Sunny.quirksMode)
			{
				position.x += $Sunny.getCorrectScrollLeft(document.body);
				position.y += document.body.scrollTop;
			}

			return position;
		}

		var position = Sys.UI.DomElement.getLocation(element);

		if ($Sunny.isOpera)
		{
			var parent = element.offsetParent;

			while (parent && parent.tagName.toUpperCase() != 'BODY'
				&& parent.tagName.toUpperCase() != 'HTML')
			{
				position.x -= $Sunny.getCorrectScrollLeft(parent);
				position.y -= parent.scrollTop;
				parent = parent.offsetParent;
			}
		}

		if ($Sunny.isSafari)
		{
			var parent = element.parentNode;

			var parentTD = null;
			var parentTABLE = null;

			// Workaround for a problem with parent TABLES - when you have a parent TABLE element with border,
			// Safari acts as if the TABLE/TD has no border and calculates X and Y incorrectly.
			// That is why we need to add the borders manually. In case this is fixed in a future verion of the browser
			// we will need to remove this code.
			if($Sunny.isSafari3 || $Sunny.isSafari2)
			{
			    while (parent && parent.tagName.toUpperCase() != 'BODY'
				    && parent.tagName.toUpperCase() != 'HTML')
			    {
				    if(parent.tagName.toUpperCase() == "TD")
			        {
			            parentTD = parent;
			        }
                    else if(parent.tagName.toUpperCase() == "TABLE")
                    {
                        parentTABLE = parent;
                    }
                    else
                    {
                        // In case we have a positioned parent, we need to add the border to the calculated location.
                        var parentPosition = $Sunny.getCurrentStyle(parent, 'position');
                        if(parentPosition == 'absolute' || parentPosition == 'relative')
                        {
                            var borderTopWidth = $Sunny.getCurrentStyle(parent, 'borderTopWidth', 0);
                            var borderLeftWidth = $Sunny.getCurrentStyle(parent, 'borderLeftWidth', 0);

                            position.x += parseInt(borderTopWidth);
                            position.y += parseInt(borderLeftWidth);
                        }
                    }

                    //This works around a bug: the scroll position of a relatively/absolutely positioned parent
                    //is not taken into account by Sys.UI.DomElement.getLocation in Safari & Chrome.
                    var parentPosition = $Sunny.getCurrentStyle(parent, 'position');

                    if(parentPosition == 'absolute' || parentPosition == 'relative')
                    {
                        position.x -= parent.scrollLeft;
                        position.y -= parent.scrollTop;
                    }

                    if(parentTD && parentTABLE)
                    {
                        position.x += parseInt($Sunny.getCurrentStyle(parentTABLE, 'borderTopWidth'));
                        position.y += parseInt($Sunny.getCurrentStyle(parentTABLE, 'borderLeftWidth'));

                        // In case the TABLE has borderCollapse:collapse, we need to take the borderWidth of either
                        // the TABLE or the TD.
                        if($Sunny.getCurrentStyle(parentTABLE, 'borderCollapse') != 'collapse')
                        {
                            position.x += parseInt($Sunny.getCurrentStyle(parentTD, 'borderTopWidth'));
                            position.y += parseInt($Sunny.getCurrentStyle(parentTD, 'borderLeftWidth'));
                        }

                        parentTD = null;
                        parentTABLE = null;
                    }
                    // In case we use getLocation for a TD element, we need to calculate the borderWidth of its TABLE
                    // only in case that TABLE has no borderCollapse:collapse.
                    else if(parentTABLE)
                    {
                        if($Sunny.getCurrentStyle(parentTABLE, 'borderCollapse') != 'collapse')
                        {
                            position.x += parseInt($Sunny.getCurrentStyle(parentTABLE, 'borderTopWidth'));
                            position.y += parseInt($Sunny.getCurrentStyle(parentTABLE, 'borderLeftWidth'));
                        }
                        parentTABLE = null;
                    }

				    parent = parent.parentNode;
                }
                // END of Workaround for a problem with parent TABLES
			}
		}

		if ($Sunny.isIE && $Sunny.quirksMode)
		{
			position.x += $Sunny.getCorrectScrollLeft(document.body);
			position.y += document.body.scrollTop;
		}

		return position;
	},

    setLocation : function(element, point) {
        Sys.UI.DomElement.setLocation(element, point.x, point.y);
    },

    findControl : function(parent, id)
    {
        var children = parent.getElementsByTagName("*");
        for(var i = 0, l = children.length; i < l; i++)
        {
            var childID = children[i].id;
            if (childID && childID.endsWith(id))
                return $find(childID);
        }

        return null;
    },

    findElement : function(parent, id)
    {
        var children = parent.getElementsByTagName("*");
        for(var i = 0, l = children.length; i < l; i++)
        {
            var childID = children[i].id;
            if (childID && childID.endsWith(id))
                return $get(childID);
        }

        return null;
    },

    getContentSize : function(element) {
        /// <summary>
        /// Gets the "content-box" size of an element.
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <returns type="Object">
        /// Size of the element (in the form {width,height})
        /// </returns>
        /// <remarks>
        /// The "content-box" is the size of the content area *inside* of the borders and
        /// padding of an element. The "content-box" size does not include the margins around
        /// the element.
        /// </remarks>

        if (!element) {
            throw Error.argumentNull('element');
        }
        var size = $Sunny.getSize(element);
        var borderBox = $Sunny.getBorderBox(element);
        var paddingBox = $Sunny.getPaddingBox(element);
        return {
            width :  size.width - borderBox.horizontal - paddingBox.horizontal,
            height : size.height - borderBox.vertical - paddingBox.vertical
        }
    },

    getSize : function(element) {
        /// <summary>
        /// Gets the "border-box" size of an element.
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <returns type="Object">
        /// Size of the element (in the form {width,height})
        /// </returns>
        /// <remarks>
        /// The "border-box" is the size of the content area *outside* of the borders and
        /// padding of an element.  The "border-box" size does not include the margins around
        /// the element.
        /// </remarks>

        if (!element) {
            throw Error.argumentNull('element');
        }
        return {
            width:  element.offsetWidth,
            height: element.offsetHeight
        };
    },

    setContentSize : function(element, size) {
        /// <summary>
        /// Sets the "content-box" size of an element.
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <param name="size" type="Object">
        /// Size of the element (in the form {width,height})
        /// </param>
        /// <remarks>
        /// The "content-box" is the size of the content area *inside* of the borders and
        /// padding of an element. The "content-box" size does not include the margins around
        /// the element.
        /// </remarks>

        if (!element) {
            throw Error.argumentNull('element');
        }
        if (!size) {
            throw Error.argumentNull('size');
        }
        // FF respects -moz-box-sizing css extension, so adjust the box size for the border-box
        if($Sunny.getCurrentStyle(element, 'MozBoxSizing') == 'border-box' || $Sunny.getCurrentStyle(element, 'BoxSizing') == 'border-box') {
            var borderBox = $Sunny.getBorderBox(element);
            var paddingBox = $Sunny.getPaddingBox(element);
            size = {
                width: size.width + borderBox.horizontal + paddingBox.horizontal,
                height: size.height + borderBox.vertical + paddingBox.vertical
            };
        }
        element.style.width = size.width.toString() + 'px';
        element.style.height = size.height.toString() + 'px';
    },

    setSize : function(element, size) {
        /// <summary>
        /// Sets the "border-box" size of an element.
        /// </summary>
        /// <remarks>
        /// The "border-box" is the size of the content area *outside* of the borders and
        /// padding of an element.  The "border-box" size does not include the margins around
        /// the element.
        /// </remarks>
        /// <param name="element" type="Sys.UI.DomElement">DOM element</param>
        /// <param name="size" type="Object">Size of the element (in the form {width,height})</param>
        /// <returns />

        if (!element) {
            throw Error.argumentNull('element');
        }
        if (!size) {
            throw Error.argumentNull('size');
        }
        var borderBox = $Sunny.getBorderBox(element);
        var paddingBox = $Sunny.getPaddingBox(element);
        var contentSize = {
            width:  size.width - borderBox.horizontal - paddingBox.horizontal,
            height: size.height - borderBox.vertical - paddingBox.vertical
        };
        $Sunny.setContentSize(element, contentSize);
    },

	getBounds : function(element) {
        /// <summary>Gets the coordinates, width and height of an element.</summary>
        /// <param name="element" domElement="true"/>
        /// <returns type="Sys.UI.Bounds">
        ///   A Bounds object with four fields, x, y, width and height, which contain the pixel coordinates,
        ///   width and height of the element.
        /// </returns>

        var offset = $Sunny.getLocation(element);
        return new Sys.UI.Bounds(offset.x, offset.y, element.offsetWidth || 0, element.offsetHeight || 0);
    },

	setBounds : function(element, bounds) {
        /// <summary>
        /// Sets the "border-box" bounds of an element
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <param name="bounds" type="Object">
        /// Bounds of the element (of the form {x,y,width,height})
        /// </param>
        /// <remarks>
        /// The "border-box" is the size of the content area *outside* of the borders and
        /// padding of an element.  The "border-box" size does not include the margins around
        /// the element.
        /// </remarks>

        if (!element) {
            throw Error.argumentNull('element');
        }
        if (!bounds) {
            throw Error.argumentNull('bounds');
        }
        $Sunny.setSize(element, bounds);
        $Sunny.setLocation(element, bounds);
    },

    getClientBounds : function() {
        /// <summary>
        /// Gets the width and height of the browser client window (excluding scrollbars)
        /// </summary>
        /// <returns type="Sys.UI.Bounds">
        /// Browser's client width and height
        /// </returns>

        var clientWidth;
        var clientHeight;
        switch(Sys.Browser.agent) {
            case Sys.Browser.InternetExplorer:
                clientWidth = document.documentElement.clientWidth;
                clientHeight = document.documentElement.clientHeight;
                if (clientWidth == 0 && clientHeight == 0)
                {
                    //no doctype. use the body settings
                    clientWidth = document.body.clientWidth;
                    clientHeight = document.body.clientHeight;
                }
                break;
            case Sys.Browser.Safari:
                clientWidth = window.innerWidth;
                clientHeight = window.innerHeight;
                break;
            case Sys.Browser.Opera:
                clientWidth = Math.min(window.innerWidth, document.body.clientWidth);
                clientHeight = Math.min(window.innerHeight, document.body.clientHeight);
                break;
            default:  // Sys.Browser.Firefox, etc.
                clientWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
                clientHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);
                break;
        }
        return new Sys.UI.Bounds(0, 0, clientWidth, clientHeight);
    },

    getMarginBox : function(element) {
        /// <summary>
        /// Gets the entire margin box sizes.
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <returns type="Object">
        /// Element's margin box sizes (of the form {top,left,bottom,right,horizontal,vertical})
        /// </returns>
        if (!element) {
            throw Error.argumentNull('element');
        }
        var box = {
            top: $Sunny.getMargin(element, Sunny.Web.BoxSide.Top),
            right: $Sunny.getMargin(element, Sunny.Web.BoxSide.Right),
            bottom: $Sunny.getMargin(element, Sunny.Web.BoxSide.Bottom),
            left: $Sunny.getMargin(element, Sunny.Web.BoxSide.Left)
        }

        box.horizontal = box.left + box.right;
        box.vertical = box.top + box.bottom;
        return box;
    },

    getPaddingBox : function(element) {
        /// <summary>
        /// Gets the entire padding box sizes.
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <returns type="Object">
        /// Element's padding box sizes (of the form {top,left,bottom,right,horizontal,vertical})
        /// </returns>

        if (!element) {
            throw Error.argumentNull('element');
        }
        var box = {
            top: $Sunny.getPadding(element, Sunny.Web.BoxSide.Top),
            right: $Sunny.getPadding(element, Sunny.Web.BoxSide.Right),
            bottom: $Sunny.getPadding(element, Sunny.Web.BoxSide.Bottom),
            left: $Sunny.getPadding(element, Sunny.Web.BoxSide.Left)
        }
        box.horizontal = box.left + box.right;
        box.vertical = box.top + box.bottom;
        return box;
    },

    getBorderBox : function(element) {
        /// <summary>
        /// Gets the entire border box sizes.
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <returns type="Object">
        /// Element's border box sizes (of the form {top,left,bottom,right,horizontal,vertical})
        /// </returns>

        if (!element) {
            throw Error.argumentNull('element');
        }
        var box = {
            top: $Sunny.getBorderWidth(element, Sunny.Web.BoxSide.Top),
            right: $Sunny.getBorderWidth(element, Sunny.Web.BoxSide.Right),
            bottom: $Sunny.getBorderWidth(element, Sunny.Web.BoxSide.Bottom),
            left: $Sunny.getBorderWidth(element, Sunny.Web.BoxSide.Left)
        }
        box.horizontal = box.left + box.right;
        box.vertical = box.top + box.bottom;
        return box;
    },

	isBorderVisible : function(element, boxSide) {
        /// <summary>
        /// Gets whether the current border style for an element on a specific boxSide is not 'none'.
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <param name="boxSide" type="Sunny.Web.BoxSide">
        /// Side of the element
        /// </param>
        /// <returns type="Boolean">
        /// Whether the current border style for an element on a specific boxSide is not 'none'.
        /// </returns>

        if (!element) {
            throw Error.argumentNull('element');
        }
        if(boxSide < Sunny.Web.BoxSide.Top || boxSide > Sunny.Web.BoxSide.Left) {
            throw Error.argumentOutOfRange(String.format(Sys.Res.enumInvalidValue, boxSide, 'Sunny.Web.BoxSide'));
        }
        var styleName = $Sunny._borderStyleNames[boxSide];
        var styleValue = $Sunny.getCurrentStyle(element, styleName);
        return styleValue != "none";
    },
    getMargin : function(element, boxSide) {
        /// <summary>
        /// Gets the margin thickness of an element on a specific boxSide.
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <param name="boxSide" type="Sunny.Web.BoxSide">
        /// Side of the element
        /// </param>
        /// <returns type="Number" integer="true">
        /// Margin thickness on the element's specified side
        /// </returns>

        if (!element) {
            throw Error.argumentNull('element');
        }
        if(boxSide < Sunny.Web.BoxSide.Top || boxSide > Sunny.Web.BoxSide.Left) {
            throw Error.argumentOutOfRange(String.format(Sys.Res.enumInvalidValue, boxSide, 'Sunny.Web.BoxSide'));
        }
        var styleName = $Sunny._marginWidthNames[boxSide];
        var styleValue = $Sunny.getCurrentStyle(element, styleName);

        try { return $Sunny.parsePadding(styleValue); } catch(ex) { return 0; }
    },

    getBorderWidth : function(element, boxSide) {
        /// <summary>
        /// Gets the border thickness of an element on a specific boxSide.
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <param name="boxSide" type="Sunny.Web.BoxSide">
        /// Side of the element
        /// </param>
        /// <returns type="Number" integer="true">
        /// Border thickness on the element's specified side
        /// </returns>

        if (!element) {
            throw Error.argumentNull('element');
        }
        if(boxSide < Sunny.Web.BoxSide.Top || boxSide > Sunny.Web.BoxSide.Left) {
            throw Error.argumentOutOfRange(String.format(Sys.Res.enumInvalidValue, boxSide, 'Sunny.Web.BoxSide'));
        }
        if(!$Sunny.isBorderVisible(element, boxSide)) {
            return 0;
        }
        var styleName = $Sunny._borderWidthNames[boxSide];
        var styleValue = $Sunny.getCurrentStyle(element, styleName);
        return $Sunny.parseBorderWidth(styleValue);
    },

    getPadding : function(element, boxSide) {
        /// <summary>
        /// Gets the padding thickness of an element on a specific boxSide.
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// DOM element
        /// </param>
        /// <param name="boxSide" type="Sunny.Web.BoxSide">
        /// Side of the element
        /// </param>
        /// <returns type="Number" integer="true">
        /// Padding on the element's specified side
        /// </returns>

        if (!element) {
            throw Error.argumentNull('element');
        }
        if(boxSide < Sunny.Web.BoxSide.Top || boxSide > Sunny.Web.BoxSide.Left) {
            throw Error.argumentOutOfRange(String.format(Sys.Res.enumInvalidValue, boxSide, 'Sunny.Web.BoxSide'));
        }
        var styleName = $Sunny._paddingWidthNames[boxSide];
        var styleValue = $Sunny.getCurrentStyle(element, styleName);
        return $Sunny.parsePadding(styleValue);
    },

    parseBorderWidth : function(borderWidth) {
        /// <summary>
        /// Parses a border-width string into a pixel size
        /// </summary>
        /// <param name="borderWidth" type="String" mayBeNull="true">
        /// Type of border ('thin','medium','thick','inherit',px unit,null,'')
        /// </param>
        /// <returns type="Number" integer="true">
        /// Number of pixels in the border-width
        /// </returns>

        if(borderWidth) {
            switch(borderWidth) {
                case 'thin':
                case 'medium':
                case 'thick':
                    return $Sunny._borderThicknesses[borderWidth];
                case 'inherit':
                    return 0;
            }
            var unit = $Sunny.parseUnit(borderWidth);
            return unit.size;
        }
        return 0;
    },

    parsePadding : function(padding) {
        /// <summary>
        /// Parses a padding string into a pixel size
        /// </summary>
        /// <param name="padding" type="String" mayBeNull="true">
        /// Padding to parse ('inherit',px unit,null,'')
        /// </param>
        /// <returns type="Number" integer="true">
        /// Number of pixels in the padding
        /// </returns>

        if(padding) {
            if(padding == 'auto' || padding == 'inherit') {
                return 0;
            }
            var unit = $Sunny.parseUnit(padding);
            return unit.size;
        }
        return 0;
    },

    parseUnit : function(value) {
        /// <summary>
        /// Parses a unit string into a unit object
        /// </summary>
        /// <param name="value" type="String" mayBeNull="true">
        /// Value to parse (of the form px unit,% unit,em unit,...)
        /// </param>
        /// <returns type="Object">
        /// Parsed unit (of the form {size,type})
        /// </returns>

        if (!value) {
            throw Error.argumentNull('value');
        }

        value = value.trim().toLowerCase();
        var l = value.length;
        var s = -1;
        for(var i = 0; i < l; i++) {
            var ch = value.substr(i, 1);
            if((ch < '0' || ch > '9') && ch != '-' && ch != '.' && ch != ',') {
                break;
            }
            s = i;
        }
        if(s == -1) {
            throw Error.create('No digits');
        }
        var type;
        var size;
        if(s < (l - 1)) {
            type = value.substring(s + 1).trim();
        } else {
            type = 'px';
        }
        size = parseFloat(value.substr(0, s + 1));
        if(type == 'px') {
            size = Math.floor(size);
        }
        return {
            size: size,
            type: type
        };
    },

    containsPoint : function(rect, x, y) {
        /// <summary>
        /// Tests whether a point (x,y) is contained within a rectangle
        /// </summary>
        /// <param name="rect" type="Object">The rectangle</param>
        /// <param name="x" type="Number">The x coordinate of the point</param>
        /// <param name="y" type="Number">The y coordinate of the point</param>

        //ORIGINAL TOOLKIT SCRIPT CHANGE: instead of rect.height it was written rect.width (!!!) Clearly a major bug!!!!
        return x >= rect.x && x <= (rect.x + rect.width) && y >= rect.y && y <= (rect.y + rect.height);
    },

    isDescendant : function(ancestor, descendant) {
        /// <summary>
        /// Whether the specified element is a descendant of the ancestor
        /// </summary>
        /// <param name="ancestor" type="Sys.UI.DomElement">Ancestor node</param>
        /// <param name="descendant" type="Sys.UI.DomElement">Possible descendant node</param>
        /// <returns type="Boolean" />

        for (var n = descendant.parentNode; n != null; n = n.parentNode) {
            if (n == ancestor) return true;
        }
        return false;
    },

	isDescendantOrSelf : function(ancestor, descendant) {
        /// <summary>
        /// Whether the specified element is a descendant of the ancestor or the same as the ancestor
        /// </summary>
        /// <param name="ancestor" type="Sys.UI.DomElement">Ancestor node</param>
        /// <param name="descendant" type="Sys.UI.DomElement">Possible descendant node</param>
        /// <returns type="Boolean" />

        if (ancestor === descendant)
            return true;
        return $Sunny.isDescendant(ancestor, descendant);
    },

	setOuterHeight : function (element, height)
	{
		if (height <= 0 || height == "")
		{
			element.style.height = "";
		}
		else
		{
			element.style.height = height + "px";
			var diff = element.offsetHeight - height;
			var newHeight = height - diff;
			if (newHeight > 0) {
				element.style.height = newHeight + "px";
			} else {
				element.style.height = "";
			}
		}
	},

    setOpacity : function(element, value) {
        /// <summary>
        /// Set the element's opacity
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// Element
        /// </param>
        /// <param name="value" type="Number">
        /// Opacity of the element
        /// </param>

        if (!element) {
            throw Error.argumentNull('element');
        }
        try
        {
            if (element.filters) {
                var filters = element.filters;
                var createFilter = true;
                if (filters.length !== 0) {
                    var alphaFilter = filters['DXImageTransform.Microsoft.Alpha'];
                    if (alphaFilter) {
                        createFilter = false;
                        alphaFilter.opacity = value * 100;
                    }
                }
                if (createFilter) {
                    element.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + (value * 100) + ')';
                }
            }
            else {
                element.style.opacity = value;
            }
        }
        catch (ex) {}
    },

    getOpacity : function(element) {
        /// <summary>
        /// Get the element's opacity
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement" domElement="true">
        /// Element
        /// </param>
        /// <returns type="Number">
        /// Opacity of the element
        /// </returns>

        if (!element) {
            throw Error.argumentNull('element');
        }

        var hasOpacity = false;
        var opacity;

        try
        {
            if (element.filters) {
                var filters = element.filters;
                if (filters.length !== 0) {
                    var alphaFilter = filters['DXImageTransform.Microsoft.Alpha'];
                    if (alphaFilter) {
                        opacity = alphaFilter.opacity / 100.0;
                        hasOpacity = true;
                    }
                }
            }
            else {
                opacity = $Sunny.getCurrentStyle(element, 'opacity', 1);
                hasOpacity = true;
            }
        }
        catch (ex) {}

        if (hasOpacity === false) {
            return 1.0;
        }
        return parseFloat(opacity);
    },

    addCssClasses : function(element, classNames) {
        /// <summary>
        /// Adds multiple css classes to a DomElement
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement">The element to modify</param>
        /// <param name="classNames" type="Array">The class names to add</param>

        for(var i = 0; i < classNames.length; i++) {
            Sys.UI.DomElement.addCssClass(element, classNames[i]);
        }
    },

    removeCssClasses : function(element, classNames) {
        /// <summary>
        /// Removes multiple css classes to a DomElement
        /// </summary>
        /// <param name="element" type="Sys.UI.DomElement">The element to modify</param>
        /// <param name="classNames" type="Array">The class names to remove</param>

        for(var i = 0; i < classNames.length; i++) {
            Sys.UI.DomElement.removeCssClass(element, classNames[i]);
        }
    },
	setOuterWidth : function (element, width)
	{
		if (width <= 0 || width == "")
		{
			element.style.width = "";
		}
		else
		{
			element.style.width = width + "px";
			var diff = element.offsetWidth - width;
			var newWidth = width - diff;
			if (newWidth > 0) {
				element.style.width = newWidth + "px";
			} else {
				element.style.width = "";
			}
		}
	},

	getScrollOffset : function(element, recursive)
	{
		var left = 0;
		var top = 0;
		var parent = element;

		while (parent != null && parent.scrollLeft != null) {
			left += $Sunny.getCorrectScrollLeft(parent);
			top += parent.scrollTop;
			// Don't include anything below the body.
			if (!recursive || (parent == document.body && (parent.scrollLeft != 0 || parent.scrollTop != 0)))
				break;

			parent = parent.parentNode;
		}

		return { x: left, y: top };
	},

	getElementByClassName : function(element, className, tagName)
	{
		var children = null;
		if (tagName)
		{
			children = element.getElementsByTagName(tagName);
		}
		else
		{
			children = element.getElementsByTagName("*");
		}

		for (var i = 0, length = children.length; i < length; i++)
		{
			var child = children[i];

			if (Sys.UI.DomElement.containsCssClass(child, className))
			{
				return child;
			}
		}

		return null;
	},

	//The $addHandler and $removeHandler only work with DOM HTML elements.
	//In products that use iframes (RadWindow, RadEditor, EditorPopup) events need to be attached to the iframes' document and/or contentWindow.
	//In addition to this to construct an event object, the MS AJAX framework attempts to use the window.event - which is null in the main page, when the event originates from a child frame
	//Thus, the need to provide an alternative to the MS AJAX framework arises
	addExternalHandler : function(element, eventName, handler)
	{
		if (element.addEventListener)
		{
			element.addEventListener(eventName, handler, false);
		}
		else if (element.attachEvent)
		{
			element.attachEvent("on" + eventName, handler);
		}
	},
	removeExternalHandler : function(element, eventName, handler)
	{
		if (element.addEventListener)
		{
			element.removeEventListener(eventName, handler, false);
		}
		else if (element.detachEvent)
		{
			element.detachEvent("on" + eventName, handler);
		}
	},

	cancelRawEvent : function(e)
	{
		if (!e) return false;
		if (e.preventDefault) e.preventDefault();
		if (e.stopPropagation) e.stopPropagation();
		e.cancelBubble = true;
		e.returnValue = false;
		return false;
	},

	getOuterHtml : function(element)
	{
		if (element.outerHTML)
		{
			return element.outerHTML;
		}
		else
		{
			var elementCopy = element.cloneNode(true);
			var tmpDiv = element.ownerDocument.createElement("DIV");
			tmpDiv.appendChild(elementCopy);
			return tmpDiv.innerHTML;
		}
	},

	setVisible : function(e, value)
	{
		if (!e) return;

		if (value != $Sunny.getVisible(e)) {

			if (value) {
				if (e.style.removeAttribute) {
					e.style.removeAttribute("display");
				} else {
				   e.style.removeProperty("display");
				}
			}
			else {
				e.style.display = 'none';
			}

			e.style.visibility = value ? 'visible' : 'hidden';
		}
	},

	getVisible : function(e)
	{
		if (!e) return false;

		return (("none" != $Sunny.getCurrentStyle(e, "display")) &&
        ("hidden" != $Sunny.getCurrentStyle(e, "visibility")));
	},

	getViewPortSize : function()
	{
		var width = 0;
		var height = 0;

		var canvas = document.body;

		if (!$Sunny.quirksMode && !$Sunny.isSafari)
		{
			canvas = document.documentElement;
		}

		if (window.innerWidth)
		{
			width = window.innerWidth;
			height = window.innerHeight;
		}
		else
		{
			width = canvas.clientWidth;
			height = canvas.clientHeight;
		}

		width += canvas.scrollLeft;
		height += canvas.scrollTop;

		return { width : width - 6, height : height - 6 };
	},

	elementOverflowsTop : function (element)
	{
		return $Sunny.getLocation(element).y < 0;
	},

	elementOverflowsLeft : function (element)
	{
		return $Sunny.getLocation(element).x < 0;
	},

	elementOverflowsBottom : function (screenSize, element)
	{
		var bottomEdge = $Sunny.getLocation(element).y + element.offsetHeight;
		return bottomEdge > screenSize.height;
	},

	elementOverflowsRight : function (screenSize, element)
	{
		var rightEdge = $Sunny.getLocation(element).x + element.offsetWidth;
		return rightEdge > screenSize.width;
	},

	getDocumentRelativeCursorPosition : function(e)
	{
		var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
		var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
		var left = e.clientX + scrollLeft;
		var top = e.clientY + scrollTop;
		return {left:left, top:top};
	},

//	//Lini: this code is not needed anymore. It will be removed for the Q1 2008 release.
//	makeCompatible : function(type)
//	{
//		/// <exclude />
//		/// <summary>
//		///		Doubles the get_propertyName, set_propertyName, add_event, remove_event
//		///		methods with get_PropertyName, set_PropertyName, etc. ones, to save troubles for
//		///		users already having client-side code with the mistaken client-side convention.
//		///
//		///     Doubles the methodName(...) with MethodName(...) member to save troubles for
//	    ///		users already having client-side code with the mistaken client-side convention.
//		/// </summary>

//		var proto = type.prototype;
//		for (var memberName in proto)
//		{
//			if (/([gs]et|add|remove|raise)_[a-z].*/.test(memberName))
//			{
//				var propNameStart = RegExp.$1.length + 1;
//				var oldPropName = memberName.substr(0, propNameStart) + memberName.charAt(propNameStart).toUpperCase() + memberName.substr(propNameStart + 1);
//				proto[oldPropName] = proto[memberName];
//			}
//			else if (/^[a-z][a-zA-Z]+$/.test(memberName) &&
//		             proto.hasOwnProperty(memberName) &&
//		             typeof(proto[memberName]) == "function" &&
//		             memberName != "initialize" &&
//		             memberName != "dispose")
//		    {
//		        var oldMethodName = memberName.charAt(0).toUpperCase() + memberName.substr(1);
//		        proto[oldMethodName] = proto[memberName];
//		    }
//		}
//	},

	getFirstChildByTagName : function (element, tagName, index)
	{
		if (!element || !element.childNodes)
		{
			return null;
		}

		var currentNode = element.childNodes[index] || element.firstChild;

		while (currentNode)
		{
			if (currentNode.nodeType == 1 && currentNode.tagName.toLowerCase() == tagName)
				return currentNode;

			currentNode = currentNode.nextSibling;
		}

		return null;
	},

	getChildByClassName : function(element, className, index)
	{
		var currentNode = element.childNodes[index] || element.firstChild;
		while (currentNode)
		{
			if (currentNode.nodeType == 1 && currentNode.className.indexOf(className) > -1)
				return currentNode;
			currentNode = currentNode.nextSibling;
		}
		return null;
	},

	getChildrenByTagName : function (element, tagName)
	{
		var children = new Array();
		var childNodes = element.childNodes;
		if ($Sunny.isIE)
			childNodes = element.children;

		for (var i = 0, length = childNodes.length; i < length; i++)
		{
			var child = childNodes[i];
			if (child.nodeType == 1 && child.tagName.toLowerCase() == tagName)
				Array.add(children, child);
		}
		return children;
	},

	getChildrenByClassName : function (element, className)
	{
		var children = new Array();
		var childNodes = element.childNodes;
		if ($Sunny.isIE)
			childNodes = element.children;

		for (var i = 0, length = childNodes.length; i < length; i++)
		{
			var child = childNodes[i];
			if (child.nodeType == 1 && child.className.indexOf(className) > -1)
				Array.add(children, child);
		}
		return children;
	},

	isMouseOverElement : function(element, e)
	{
		var elementBounds = $Sunny.getBounds(element);
		var cursor = $Sunny.getDocumentRelativeCursorPosition(e);

		return $Sunny.containsPoint(elementBounds, cursor.left, cursor.top);
	},
	
	isMouseOverElementEx : function(element, e)
	{
	    var rect = null;
        //Can throw exception if called by body onclick eventhandler after AJAX update
        try
        {
           rect = $Sunny.getOuterBounds(element);        
        }
        catch(e)
        {
            return false;
        }
                
        if (e && e.target)
        {
            //BUG in IE6: If there is a select element in the dropdown [heavyweight object], clientX and clientY come with bad values, and the contains
            //Mozilla bug - option elements in a select cause the mouse to return incorrect mouse offsets    
            var tagName = e.target.tagName;                        
            if (tagName == "SELECT" || tagName == "OPTION") return true;
            if (e.clientX < 0 || e.clientY < 0) return true;            
        }
                                        
        //See if targetControl rect contains the mouse x,y
        var docElem = document.documentElement;
        var body = document.body;
        
        // For scrollLeft/scrollTop use the sum of the documentElement and body as there are case, which the following does not cover:
        // (document.compatMode && document.compatMode!="BackCompat") ? document.documentElement : document.body
        // For example, in Safari and Chrome, even though (document.compatMode && document.compatMode!="BackCompat") is true, the BODY
        // element displays scrollbars.
        var x = e.clientX + ($Sunny.getCorrectScrollLeft(docElem) + $Sunny.getCorrectScrollLeft(body));
        var y = e.clientY + (docElem.scrollTop + body.scrollTop);                        
                
        //When mouse is taken out slowly  e.clientX and  e.clientY return values on the 'border' of the element - technically - still within it        
        rect.x += 2;
        rect.y += 2;
        rect.width -= 4;
        rect.height -= 4;
        var toKeep = $Sunny.containsPoint(rect, x,y);        
        return toKeep;
	}
}

if (typeof(Sys.Browser.WebKit) == "undefined")
{
	Sys.Browser.WebKit = {}; //Safari 3 is considered WebKit
}
if (typeof(Sys.Browser.Chrome) == "undefined")
{
	Sys.Browser.Chrome = {};
}

if(navigator.userAgent.indexOf("Chrome") > -1)
{
	//Sys.Browser.version = navigator.userAgent.match(/Chrome\/(\d+(\.\d+(\.\d+))?)/)[1];
	Sys.Browser.version = parseFloat(navigator.userAgent.match(/WebKit\/(\d+(\.\d+)?)/)[1]);
	Sys.Browser.agent = Sys.Browser.Chrome;
	Sys.Browser.name = "Chrome";
}
else if(navigator.userAgent.indexOf("WebKit/") > -1)
{
	Sys.Browser.version = parseFloat(navigator.userAgent.match(/WebKit\/(\d+(\.\d+)?)/)[1]);
	if (Sys.Browser.version < 500)
	{
		Sys.Browser.agent = Sys.Browser.Safari;
		Sys.Browser.name = "Safari";
	}
	else
	{
		Sys.Browser.agent = Sys.Browser.WebKit;
		Sys.Browser.name = "WebKit";
	}
}

$Sunny.isChrome = Sys.Browser.agent == Sys.Browser.Chrome;
$Sunny.isSafari3 = Sys.Browser.agent == Sys.Browser.WebKit || Sys.Browser.agent == Sys.Browser.Chrome;
$Sunny.isSafari2 = Sys.Browser.agent == Sys.Browser.Safari;
$Sunny.isSafari = $Sunny.isSafari2 || $Sunny.isSafari3;
$Sunny.isIE = Sys.Browser.agent == Sys.Browser.InternetExplorer;
$Sunny.isIE6 = $Sunny.isIE && Sys.Browser.version < 7;
$Sunny.isIE7 = $Sunny.isIE && Sys.Browser.version == 7;
$Sunny.isIE8 = $Sunny.isIE && Sys.Browser.version == 8;
$Sunny.isOpera = Sys.Browser.agent == Sys.Browser.Opera;
$Sunny.isFirefox = Sys.Browser.agent == Sys.Browser.Firefox;
$Sunny.isFirefox2 = $Sunny.isFirefox && Sys.Browser.version < 3;
$Sunny.isFirefox3 = $Sunny.isFirefox && Sys.Browser.version == 3;
$Sunny.quirksMode = $Sunny.isIE && document.compatMode != "CSS1Compat";
$Sunny.standardsMode = !$Sunny.quirksMode;

//Initialize the thickness of borders based on their style
try {
    $Sunny._borderThickness();
} catch (err){}

Sunny.Web.UI.Orientation = function() {
    /// <summary>
    /// The Sunny.Web.UI.Orientation enumeration is used to specify
    /// the orientation of a given asset
    /// </summary>
    /// <field name="Horizontal" type="Number" integer="true"/>
    /// <field name="Vertical" type="Number" integer="true"/>
    throw Error.invalidOperation();
}
Sunny.Web.UI.Orientation.prototype = {
    Horizontal : 0,
    Vertical : 1
}
Sunny.Web.UI.Orientation.registerEnum('Sunny.Web.UI.Orientation', false);

Sunny.Web.UI.RadWebControl = function(element)
{
    Sunny.Web.UI.RadWebControl.initializeBase(this, [element]);

    this._clientStateFieldID = null;
}

Sunny.Web.UI.RadWebControl.prototype =
{
    initialize: function()
    {
        Sunny.Web.UI.RadWebControl.callBaseMethod(this, 'initialize');

        $Sunny.registerControl(this);

        if(!this.get_clientStateFieldID()) return;

        var input = $get(this.get_clientStateFieldID());

        if(!input) return;

        input.setAttribute('autocomplete', 'off');
    },

    dispose: function()
    {
        $Sunny.unregisterControl(this);

        var element = this.get_element();

        Sunny.Web.UI.RadWebControl.callBaseMethod(this, 'dispose');

        if (element)
        {
			element.control = null;

			var dispose = true;
            if (element._events) {
                for (var e in element._events) {
                    if (element._events[e].length > 0) {
                        dispose = false;
                        break;
                    }
                }

                if (dispose)
                    element._events = null;
            }
		}
    },

    raiseEvent : function(eventName, eventArgs) {
        /// <summary>
        /// Raise the event
        /// </summary>
        /// <param name="eventName" type="String" mayBeNull="false">
        /// Name of the event to be raised
        /// </param>
        /// <param name="eventArgs" type="Sys.EventArgs" mayBeNull="true">
        /// Event arguments for the given event
        /// </param>
        /// <returns />

		var handler = this.get_events().getHandler(eventName);
		if (handler) {
			if (!eventArgs) {
				eventArgs = Sys.EventArgs.Empty;
			}
			handler(this, eventArgs);
        }
    },

    updateClientState: function()
    {
        /// <summary>
        /// Call this function to update the client state hidden field.
        /// Use this function with caution, because it is resource hungry.
        /// </summary>
		this.set_clientState(this.saveClientState());
    },

    saveClientState: function()
    {
        /// <summary>
        /// This function should return the serialized client state of the control.
        /// </summary>
        /// <example>
		/// saveClientState: function()
		/// {
		///		var state =
		///		{
		///			Collapsed	: this.get_collapsed(),
		///			Width		: this.get_width(),
		///			Height		: this.get_height()
		///		};
		///		return Sys.Serialization.JavaScriptSerializer.serialize(state);
		/// }
        /// </example>
         return null;
    },

    get_clientStateFieldID : function()
    {
        /// <value type="String">
        /// ID of the hidden field used to store the client state
        /// </value>
        return this._clientStateFieldID;
    },
    set_clientStateFieldID : function(value)
    {
        if (this._clientStateFieldID != value)
        {
            this._clientStateFieldID = value;
            this.raisePropertyChanged('ClientStateFieldID');
        }
    },

    get_clientState : function() {
        /// <value type="String">
        /// Client state
        /// </value>
        if (this._clientStateFieldID)
        {
            var input = document.getElementById(this._clientStateFieldID);
            if (input)
            {
                return input.value;
            }
        }
        return null;
    },
    set_clientState : function(value)
    {
        if (this._clientStateFieldID)
        {
            var input = document.getElementById(this._clientStateFieldID);
            if (input)
            {
                input.value = value;
            }
        }
    },

    _getChildElement : function(id)
	{
		return $get(this.get_id() + "_" + id);
	},

	_findChildControl : function(id)
	{
		return $find(this.get_id() + "_" + id);
	}
}

Sunny.Web.UI.RadWebControl.registerClass('Sunny.Web.UI.RadWebControl', Sys.UI.Control);

Sunny.Web.Timer = function() {
    Sunny.Web.Timer.initializeBase(this);

    this._interval = 1000;
    this._enabled = false;
    this._timer = null;

    this._timerCallbackDelegate = Function.createDelegate(this, this._timerCallback);
}

Sunny.Web.Timer.prototype = {
    get_interval: function() {

        return this._interval;
    },
    set_interval: function(value) {

        if (this._interval !== value) {
            this._interval = value;
            this.raisePropertyChanged('interval');

            if (!this.get_isUpdating() && (this._timer !== null)) {
                this._stopTimer();
                this._startTimer();
            }
        }
    },

    get_enabled: function() {

        return this._enabled;
    },
    set_enabled: function(value) {

        if (value !== this.get_enabled()) {
            this._enabled = value;
            this.raisePropertyChanged('enabled');
            if (!this.get_isUpdating()) {
                if (value) {
                    this._startTimer();
                }
                else {
                    this._stopTimer();
                }
            }
        }
    },


    add_tick: function(handler) {
        this.get_events().addHandler("tick", handler);
    },

    remove_tick: function(handler) {
        this.get_events().removeHandler("tick", handler);
    },

    dispose: function() {
        this.set_enabled(false);
        this._stopTimer();

        Sunny.Web.Timer.callBaseMethod(this, 'dispose');
    },

    updated: function() {
        Sunny.Web.Timer.callBaseMethod(this, 'updated');

        if (this._enabled) {
            this._stopTimer();
            this._startTimer();
        }
    },

    _timerCallback: function() {
        var handler = this.get_events().getHandler("tick");
        if (handler) {
            handler(this, Sys.EventArgs.Empty);
        }
    },

    _startTimer: function() {
        this._timer = window.setInterval(this._timerCallbackDelegate, this._interval);
    },

    _stopTimer: function() {
        window.clearInterval(this._timer);
        this._timer = null;
    }
}

Sunny.Web.Timer.registerClass('Sunny.Web.Timer', Sys.Component);

Sunny.Web.BoxSide = function() {
}
Sunny.Web.BoxSide.prototype = {
    Top : 0,
    Right : 1,
    Bottom : 2,
    Left : 3
}
Sunny.Web.BoxSide.registerEnum("Sunny.Web.BoxSide", false);

if (Sys.CultureInfo.prototype._getAbbrMonthIndex) {
    try {
        Sys.CultureInfo.prototype._getAbbrMonthIndex('');
    } catch(ex) {
        Sys.CultureInfo.prototype._getAbbrMonthIndex = function(value) {
            if (!this._upperAbbrMonths) {
                this._upperAbbrMonths = this._toUpperArray(this.dateTimeFormat.AbbreviatedMonthNames);
            }
            return Array.indexOf(this._upperAbbrMonths, this._toUpper(value));
        }
        Sys.CultureInfo.CurrentCulture._getAbbrMonthIndex = Sys.CultureInfo.prototype._getAbbrMonthIndex;
        Sys.CultureInfo.InvariantCulture._getAbbrMonthIndex = Sys.CultureInfo.prototype._getAbbrMonthIndex;
    }
}

Sunny.Web.UI.EditorCommandEventArgs = function(commandName, tool, value)
{
	Sunny.Web.UI.EditorCommandEventArgs.initializeBase(this);
	this._name = this._commandName = commandName;
	this._tool = tool;
	this._value = value;
	//Backwards compatibility
	this.value = value;

	//NEW: Callback function
	this._callbackFunction = null;
}

Sunny.Web.UI.EditorCommandEventArgs.prototype =
{
	get_name : function() { return this._name; },
	get_commandName : function() { return this._commandName; },
	get_tool : function() { return this._tool; },
	get_value : function() { return this._value; },
	set_value : function(val) { this.value = val; this._value = val; },

	//NEW: Allow for alternative callback function to be set to dialogs
	set_callbackFunction : function(val) { this._callbackFunction = val; }

}
Sunny.Web.UI.EditorCommandEventArgs.registerClass("Sunny.Web.UI.EditorCommandEventArgs", Sys.CancelEventArgs);


Sunny.Web.IParameterConsumer = function() {
}
Sunny.Web.IParameterConsumer.prototype = {
	clientInit: function(parameters) { throw Error.notImplemented(); }
}
Sunny.Web.IParameterConsumer.registerInterface('Sunny.Web.IParameterConsumer');

Type.registerNamespace("Sunny.Web.UI.Dialogs");

Sunny.Web.UI.Dialogs.CommonDialogScript = function()
{
}

Sunny.Web.UI.Dialogs.CommonDialogScript.get_windowReference = function()
{
	if (window.radWindow)
	{
		return window.radWindow;
	}
	if (window.frameElement && window.frameElement.radWindow)
	{
		return window.frameElement.radWindow;
	}
	//If using classic windows (window.open)
	//Cache the reference, as a window can open a second window and the reference would be replaced.
	if (!window.__localRadEditorRadWindowReference && window.opener.__getCurrentRadEditorRadWindowReference)
	{
		window.__localRadEditorRadWindowReference = window.opener.__getCurrentRadEditorRadWindowReference();
	}
	return window.__localRadEditorRadWindowReference;
};

Sunny.Web.UI.Dialogs.CommonDialogScript.registerClass('Sunny.Web.UI.Dialogs.CommonDialogScript', null);

Sunny.Web.UI.WebServiceLoaderEventArgs = function(context)
{
	Sunny.Web.UI.WebServiceLoaderEventArgs.initializeBase(this);
	this._context = context;
}

Sunny.Web.UI.WebServiceLoaderEventArgs.prototype =
{
	get_context : function ()
	{
		return this._context;
	}
}

Sunny.Web.UI.WebServiceLoaderEventArgs.registerClass('Sunny.Web.UI.WebServiceLoaderEventArgs', Sys.EventArgs);


// ---------- WebServiceLoaderSuccessEventArgs Class ----------
Sunny.Web.UI.WebServiceLoaderSuccessEventArgs = function(data, context)
{
	Sunny.Web.UI.WebServiceLoaderSuccessEventArgs.initializeBase(this, [context]);
	this._data = data;
}

Sunny.Web.UI.WebServiceLoaderSuccessEventArgs.prototype =
{
	get_data : function ()
	{
		return this._data;
	}
}

Sunny.Web.UI.WebServiceLoaderSuccessEventArgs.registerClass('Sunny.Web.UI.WebServiceLoaderSuccessEventArgs', Sunny.Web.UI.WebServiceLoaderEventArgs);


// ---------- WebServiceLoaderErrorEventArgs Class ----------
Sunny.Web.UI.WebServiceLoaderErrorEventArgs = function(message, context)
{
	Sunny.Web.UI.WebServiceLoaderErrorEventArgs.initializeBase(this, [context]);
	this._message = message;
}

Sunny.Web.UI.WebServiceLoaderErrorEventArgs.prototype =
{
	get_message : function ()
	{
		return this._message;
	}
}

Sunny.Web.UI.WebServiceLoaderErrorEventArgs.registerClass('Sunny.Web.UI.WebServiceLoaderErrorEventArgs', Sunny.Web.UI.WebServiceLoaderEventArgs);


// ---------- WebServiceLoader Class ----------
Sunny.Web.UI.WebServiceLoader = function(webServiceSettings)
{
	this._webServiceSettings = webServiceSettings;
	this._events = null;
	this._onWebServiceSuccessDelegate = Function.createDelegate(this, this._onWebServiceSuccess);
	this._onWebServiceErrorDelegate = Function.createDelegate(this, this._onWebServiceError);
	this._currentRequest = null;
}

Sunny.Web.UI.WebServiceLoader.prototype =
{
	// Public properties
	get_webServiceSettings : function ()
	{
		return this._webServiceSettings;
	},

	get_events: function ()
	{
		if (!this._events)
		{
			this._events = new Sys.EventHandlerList();
		}

		return this._events;
	},


	// Public methods
	loadData : function (params, context)
	{
		var webServiceSettings = this.get_webServiceSettings();
		this.invokeMethod(this._webServiceSettings.get_method(), params, context);
	},

	invokeMethod : function(webMethod, params, context)
	{
		var webServiceSettings = this.get_webServiceSettings();
		if (webServiceSettings.get_isEmpty())
		{
			alert("Please, specify valid web service and method.");
			return;
		}

		this._raiseEvent("loadingStarted", new Sunny.Web.UI.WebServiceLoaderEventArgs(context));

		var webServicePath = webServiceSettings.get_path();
		var useHttpGet = webServiceSettings.get_useHttpGet();
		this._currentRequest = Sys.Net.WebServiceProxy.invoke(webServicePath, webMethod, useHttpGet, params,
			this._onWebServiceSuccessDelegate, this._onWebServiceErrorDelegate, context);
	},


	// Events
	add_loadingStarted : function(handler)
	{
		this.get_events().addHandler("loadingStarted", handler);
	},

	add_loadingError : function(handler)
	{
		this.get_events().addHandler("loadingError", handler);
	},

	add_loadingSuccess : function(handler)
	{
		this.get_events().addHandler("loadingSuccess", handler);
	},


	// Private methods
	_serializeDictionaryAsKeyValuePairs : function (dictionary)
	{
		var result = [];
		
		for (var key in dictionary)
			result[result.length] = {Key : key, Value : dictionary[key]};
			
		return result;
	},
	
	_onWebServiceSuccess : function (data, context)
	{
		var successEventArgs = new Sunny.Web.UI.WebServiceLoaderSuccessEventArgs(data, context);
		this._raiseEvent("loadingSuccess", successEventArgs);
	},

	_onWebServiceError : function (error, context)
	{
		var errorEventArgs = new Sunny.Web.UI.WebServiceLoaderErrorEventArgs(error.get_message(), context);
		this._raiseEvent("loadingError", errorEventArgs);
	},

	_raiseEvent : function (eventName, eventArgs)
	{
		var handler = this.get_events().getHandler(eventName);

		if (handler)
		{
			if (!eventArgs)
			{
				eventArgs = Sys.EventArgs.Empty;
			}

			handler(this, eventArgs);
		}
	}
}

Sunny.Web.UI.WebServiceLoader.registerClass('Sunny.Web.UI.WebServiceLoader');

Sunny.Web.UI.WebServiceSettings = function(serializedWebServiceSettings)
{
	this._path = null;
	this._method = null;
	this._useHttpGet = false;

	//Add a check for the parameter existance
	if (!serializedWebServiceSettings) serializedWebServiceSettings = {};

	if (typeof(serializedWebServiceSettings.path) != "undefined")
	{
		this._path = serializedWebServiceSettings.path;
	}

	if (typeof(serializedWebServiceSettings.method) != "undefined")
	{
		this._method = serializedWebServiceSettings.method;
	}

	if (typeof(serializedWebServiceSettings.useHttpGet) != "undefined")
	{
		this._useHttpGet = serializedWebServiceSettings.useHttpGet;
	}
}

Sunny.Web.UI.WebServiceSettings.prototype =
{
	get_isWcf : function ()
	{
		return /\.svc$/.test(this._path);
	},
	
	get_path : function ()
	{
		return this._path;
	},

	set_path : function (value)
	{
		this._path = value;
	},

	get_method : function ()
	{
		return this._method;
	},

	set_method : function (value)
	{
		this._method = value;
	},

	get_useHttpGet : function ()
	{
		return this._useHttpGet;
	},

	set_useHttpGet : function (value)
	{
		this._useHttpGet = value;
	},

	get_isEmpty : function ()
	{
		/// <value type="Boolean">
		///		A value indicating wether the web service settings contain
		///		a non-null and non-empty service path and method.
		/// </value>
		var path = this.get_path();
		var method = this.get_method();

		return (!(path && method))
	}
}

Sunny.Web.UI.WebServiceSettings.registerClass('Sunny.Web.UI.WebServiceSettings');

// ---------- AnimationType Enum ----------
Sunny.Web.UI.AnimationType = function () { };

Sunny.Web.UI.AnimationType.toEasing = function (value)
{
		return "ease" + Sunny.Web.UI.AnimationType.toString(value);
}

Sunny.Web.UI.AnimationType.prototype =
{
	None: 0,
	Linear: 1,

	InQuad: 2,
	OutQuad: 3,
	InOutQuad: 4,

	InCubic: 5,
	OutCubic: 6,
	InOutCubic: 7,

	InQuart: 8,
	OutQuart: 9,
	InOutQuart: 10,

	InQuint: 11,
	OutQuint: 12,
	InOutQuint: 13,

	InSine: 14,
	OutSine: 15,
	InOutSine: 16,

	InExpo: 17,
	OutExpo: 18,
	InOutExpo: 19,

	InBack: 20,
	OutBack: 21,
	InOutBack: 22,

	InBounce: 23,
	OutBounce: 24,
	InOutBounce: 25,

	InElastic: 26,
	OutElastic: 27,
	InOutElastic: 28
}

Sunny.Web.UI.AnimationType.registerEnum("Sunny.Web.UI.AnimationType");

// ---------- AnimationSettings Class ----------
Sunny.Web.UI.AnimationSettings = function(serializedAnimationSettings)
{
	this._type = Sunny.Web.UI.AnimationType.OutQuart;
	this._duration = 300;

	if (typeof(serializedAnimationSettings.type) != "undefined")
	{
		this._type = serializedAnimationSettings.type;
	}

	if (typeof(serializedAnimationSettings.duration) != "undefined")
	{
		this._duration = serializedAnimationSettings.duration;
	}
}

Sunny.Web.UI.AnimationSettings.prototype =
{
	get_type : function ()
	{
		return this._type;
	},

	set_type : function(value)
	{
		this._type = value;
	},

	get_duration : function ()
	{
		return this._duration;
	},

	set_duration : function(value)
	{
		this._duration = value;
	}
}

Sunny.Web.UI.AnimationSettings.registerClass('Sunny.Web.UI.AnimationSettings');

/* ActionsManager - used by editor, spell, file explorer and other controls that need undo/redo functionality */
Sunny.Web.UI.ActionsManager = function(contentWindow)
{
	Sunny.Web.UI.ActionsManager.initializeBase(this);
	this._actions = [];
	this._currentActionIndex = -1; //index of the last (un)executed action
}

Sunny.Web.UI.ActionsManager.prototype =
{
	get_actions: function()
	{
		return this._actions;
	},

	shiftPointerLeft: function()
	{
		this._currentActionIndex--;
	},

	shiftPointerRight: function()
	{
		this._currentActionIndex++;
	},

	get_currentAction: function()
	{
		return this.get_actions()[this._currentActionIndex];
	},

	get_nextAction: function()
	{
		return this.get_actions()[this._currentActionIndex + 1];
	},

	addAction: function(action)
	{
		//debugger;
		if (action)
		{
			var args = new Sunny.Web.UI.ActionsManagerEventArgs(action);
			this.raiseEvent("executeAction", args);
			//If there are actions to redo - remove them
			this._clearActionsToRedo();
			Array.add(this._actions, action);
			this._currentActionIndex = this._actions.length - 1;
			return true;
		}
		return false;
	},

	undo: function(depth)
	{
		if (depth == null) depth = 1;
		if (depth > this._actions.length) depth = this._actions.length;

		var cmdCount = 0;
		var action = null;

		while (0 < depth--
				&& 0 <= this._currentActionIndex
				&& this._currentActionIndex < this._actions.length)
		{
			action = this._actions[this._currentActionIndex--];
			if (action)
			{
				var args = new Sunny.Web.UI.ActionsManagerEventArgs(action);
				this.raiseEvent("undoAction", args);
				cmdCount++;
			}
		}

	},

	redo: function(depth)
	{
		if (depth == null) depth = 1;
		if (depth > this._actions.length) depth = this._actions.length;

		var cmdCount = 0;
		var action = null;

		var actionIndex = this._currentActionIndex + 1;
		while (0 < depth--
				&& 0 <= actionIndex
				&& actionIndex < this._actions.length)
		{
			action = this._actions[actionIndex];
			if (action)
			{
				var args = new Sunny.Web.UI.ActionsManagerEventArgs(action);
				this.raiseEvent("redoAction", args);
				this._currentActionIndex = actionIndex;
				cmdCount++;
			}
			actionIndex++;
		}
	},

	//Called by the AJAX spellchecker
	removeActionAt: function(index)
	{
		this._actions.splice(index, 1);
		if (this._currentActionIndex >= index) this._currentActionIndex--;
	},

	canUndo: function()
	{
		return (-1 < this._currentActionIndex);
	},

	canRedo: function()
	{
		return (this._currentActionIndex < this._actions.length - 1);
	},

	//Called by the undo/redo dropdowns
	getActionsToUndo: function()
	{
		if (this.canUndo())
		{
			return (this._actions.slice(0, this._currentActionIndex + 1)).reverse();
		}
		return [];
	},

	//Called by the undo/redo dropdowns
	getActionsToRedo: function()
	{
		if (this.canRedo())
		{
			return this._actions.slice(this._currentActionIndex + 1);
		}
		return [];
	},

	_clearActionsToRedo: function()
	{
		if (this.canRedo())
		{
			this._actions.splice(this._currentActionIndex + 1, this._actions.length - this._currentActionIndex);
		}
	},

	//===========================================================================================================//
	add_undoAction: function(handler)
	{
		this.get_events().addHandler("undoAction", handler);
	},

	remove_undoAction: function(handler)
	{
		this.get_events().removeHandler("undoAction", handler);
	},

	add_redoAction: function(handler)
	{
		this.get_events().addHandler("redoAction", handler);
	},

	remove_redoAction: function(handler)
	{
		this.get_events().removeHandler("redoAction", handler);
	},

	add_executeAction: function(handler)
	{
		this.get_events().addHandler("executeAction", handler);
	},

	remove_executeAction: function(handler)
	{
		this.get_events().removeHandler("executeAction", handler);
	},

	raiseEvent: function(eventName, args)
	{
		var handler = this.get_events().getHandler(eventName);
		if (handler)
		{
			handler(this, args);
		}
	}
};

Sunny.Web.UI.ActionsManager.registerClass("Sunny.Web.UI.ActionsManager", Sys.Component);

Sunny.Web.UI.ActionsManagerEventArgs = function(action)
{
	Sunny.Web.UI.ActionsManagerEventArgs.initializeBase(this);
	this._action = action;
}

Sunny.Web.UI.ActionsManagerEventArgs.prototype =
{
	get_action: function()
	{
		return this._action;
	}
}

Sunny.Web.UI.ActionsManagerEventArgs.registerClass("Sunny.Web.UI.ActionsManagerEventArgs", Sys.CancelEventArgs);


Sunny.Web.StringBuilder = function ()
{
	this._buffer = [];
},

Sunny.Web.StringBuilder.prototype =
{
	append : function (value)
	{
		this._buffer[this._buffer.length] = value;
        return this;
	},

	toString : function ()
	{
		return this._buffer.join("");
	}
};

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();