﻿// Create Root RealAge Namespace
if(typeof(RealAge) == "undefined") RealAge = {};

// Add Singleton Instance of Utils Class to RealAge Namespace
if(typeof(RealAge.Utils) == "undefined") RealAge.Utils = new function()
{
    var strUserAgent = navigator.userAgent.toLowerCase();
    
    this.Browser = 
    {
        /// <summary>Determines which browser is being used</summary>
        isIE8: /msie 8.0/.test(strUserAgent),
        isIE6: /msie 6.0/.test(strUserAgent),
        isIE7: /msie 7.0/.test(strUserAgent),
        isFF2: /firefox\/2/.test(strUserAgent),
        isFF3: /firefox\/3/.test(strUserAgent),
        isChrome: /chrome/.test(strUserAgent),
        isSafari: /safari/.test(strUserAgent),
        isIphone: /iphone/.test(strUserAgent)
    }

    this.BrowserFeatures =
    {
        XPath: (!!document.evaluate)
    }

    this.CreateXmlHttp = function() 
    {
        /// <summary>Creates XmlHttp Object</summary>
	    var XmlHttp = null;
	    try 
	    {
		    XmlHttp = new ActiveXObject('Msxml2.XMLHTTP');
	    } 
	    catch (e) 
	    {
		    try 
		    {
			    XmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
		    } 
		    catch (e) 
		    {
        	    try 
        	    {
        		    XmlHttp = new XMLHttpRequest();
        	    }
        	    catch (e) 
        	    {
        		    return null;
        	    }
		    }
	    }
	    
	    return XmlHttp;
    }
    
    this.declareNamespace = function(strNamespace)
    {
        /// <summary>
        /// Declares a namespace if it does not already exist. (Does not overwrite existing objects.)
        ///</summary>
        var nsBase = window;
        var nsParts = strNamespace.split(".");
        var newBase;
        
        for(i=0;i<nsParts.length; i++)
        {
            if(!nsBase[nsParts[i]]) nsBase[nsParts[i]] = {};
            nsBase = nsBase[nsParts[i]];
        }
    }
    
    this.registerClass = function(classObj, args)
    {
        /// <summary>
        /// Registers a class, and sets up class to receive initialize and load events. 
        /// The "init" function, if it is implemented in class, is called with arguments used to create class.
        /// The "load" function, if implemented in class, is called on page load with arguments used to create class. 
        ///</summary>

        // Call Initialize on Object Creation
        if (typeof classObj.init == "function") 
            classObj.init.apply( classObj, args );        
        
        // Call Class Load Function on Page Load
        if ( typeof classObj.load == "function" ) 
            RealAge.Utils.addPageLoadEvent(function() { classObj.load.apply(classObj, args); });
    }

    this.createDelegate = function(object, method)
    {
        /// <summary>Restores proper "this" reference when calling a function</summary>
        return function() { method.apply(object, arguments); }
    }

    this.addPageLoadEvent = function( fn ) 
    {
        /// <summary>Adds a function to window.load event queue.</summary>
        /// <param name="fn" type="function">Function to call when window.onload event is fired.</param>
        if ( window.addEventListener ) 
        {
            window.addEventListener( "load", fn, false );
        }
        else 
        {
            // IE Does not handle attachEvent for window.load correctly
            // so I use this old school method.
            var oldfn = window.onload;
		
		    if (typeof(oldfn) == 'function') 
		    {
			    window.onload = function() { oldfn(window.event); fn(window.event); }
		    } 
		    else 
		    {
			    window.onload = fn;
			}
        }
    }
    
    this.addEvent = function( obj, type, fn ) 
    {
        /// <summary>Adds Event Listener to DOM Element</summary>
        /// <param name="obj" type="object">DOM obj to attach event to</param>
        /// <param name="type" type="string">Event type without "on" prefix. (mouseover, keydown, etc.)</param>
        /// <param name="fn" type="function">Function to call</param>
        if ( obj.addEventListener ) 
        {
            obj.addEventListener( type, fn, false );
        }
        else 
        {
            obj['e'+type+fn] = fn;
            obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
            obj.attachEvent( 'on'+type, obj[type+fn] );
        }

    }

    this.removeEvent = function( obj, type, fn ) 
    {
        /// <summary>Removes Event Listener from DOM Element</summary>
        /// <param name="obj" type="object">DOM obj to attach event to</param>
        /// <param name="type" type="string">Event type without "on" prefix. (mouseover, keydown, etc.)</param>
        /// <param name="fn" type="function">function to call</param>
        if ( obj.removeEventListener ) 
        {
            obj.removeEventListener( type, fn, false );
        }
        else 
        {
            obj.detachEvent( 'on'+type, obj[type+fn] );
            obj[type+fn] = null;
        }
    }

    this.getX = function(el)
    {
        /// <summary>Get Element X Position (left)</summary>
        xPos = el.offsetLeft;
        tempEl = el.offsetParent;
        while (tempEl != null) 
        {
            xPos += tempEl.offsetLeft;
            tempEl = tempEl.offsetParent;
        }
        return (xPos || 0);
    }
    
    this.getY = function(el)
    {
        /// <summary>Get Element Y Position (top)</summary>
        yPos = el.offsetTop;
        tempEl = el.offsetParent;
        while (tempEl != null) 
        {
            yPos += tempEl.offsetTop;
            tempEl = tempEl.offsetParent;
        }
        return (yPos || 0);
    }
    
    this.getWidth = function(el)    
    {
        /// <summary>Gets element width</summary>
        return (el.offsetWidth || 0 ); 
    }
    
    this.getHeight = function(el)
    { 
        /// <summary>Gets element height</summary>
        return (el.offsetHeight || 0); 
    }
    
    this.getPosition = function(el)
    {
        /// <summary>Get Element Position (x,y)</summary>
        var x = this.getX(el); 
        var y = this.getY(el); 
        return {x:x,y:y};
    }

    this.getBounds = function(el)
    {
        /// <summary>Get Element Bounds (x,y,width,height)</summary>
        var x = this.getX(el); 
        var y = this.getY(el); 
        var width = (el.offsetWidth || 0 );
        var height = (el.offsetHeight || 0 );
        return {x:x,y:y,width:width,height:height};
    }
    
    this.setPosition = function(el, x, y)
    {
        /// <summary>Set Element Position</summary>
        el.style.left   = x + "px";
        el.style.top    = y + "px";
    }
    
    this.setWidth  = function(el, width) 
    { 
        /// <summary>Sets Element Width</summary>
        el.style.width = width + "px"; 
    }
    
    this.setHeight = function(el, height) 
    { 
        /// <summary>Sets Element Height</summary>
        el.style.height = height + "px"; 
    }
    
    this.setBounds = function(el, x, y, width, height)
    {
        /// <summary>Sets Element Bounds</summary>
        this.setPosition(el,x,y);
        this.setWidth(el, width);
        this.setHeight(el, height);
    }

    this.hideElement = function(el) 
    { 
        /// <summary>Hide Element (visibility)</summary>
        el.style.visibility = 'hidden'; 
    }
    
    this.hideElementDisplay = function(el)
    {
        el.style.display = "none";
    }

    this.showElementDisplay = function(el)
    {
        el.style.display = "";
    }
    
    this.showElement = function(el) 
    { 
        /// <summary>Show Element (visibility)</summary>
        el.style.visibility = 'visible'; 
    }
    
	this.getViewportWidth = function()
	{
	  /// <summary>Get Browser View Area Width</summary>
	  var width = 0;
	  if( document.documentElement && document.documentElement.clientWidth ) 
	  {
		width = document.documentElement.clientWidth;
	  }
	  else if( document.body && document.body.clientWidth ) 
	  {
		width = document.body.clientWidth;
	  }
	  else if( window.innerWidth ) 
	  {
		width = window.innerWidth - 18;
	  }
	  return width;
	}

    this.displayProperties = function(objToScan)
    {
        /// <summary>Returns a string of all properties of an object</summary>
        var properties = "Properties:\n";
        for(props in objToScan) properties += props + "\n";
        return properties;
    }

	this.getViewportHeight = function()
	{
	  /// <summary>Gets Browser View Area Height</summary>
  	  var height = 0;
	  if( document.documentElement && document.documentElement.clientHeight ) 
	  {
		height = document.documentElement.clientHeight;
	  }
	  else if( document.body && document.body.clientHeight ) 
	  {
		height = document.body.clientHeight;
	  }
	  else if( window.innerHeight ) 
	  {
		height = window.innerHeight - 18;
	  }
	  return height;
	}
	
	this.getViewportDimensions = function()
	{
	    /// <summary>Gets Browser Viewable Area Dimensions (Width and Height)</summary>
	    var width = this.getViewportWidth();
	    var height = this.getViewportHeight();
	    return { width:width, height:height };
	}

	this.getScrollPosition = function()
	{
	    /// <summary>
	    /// Get Scroll Position (Offset from the top/left of the page to the
	    /// top/left of the viewable region.)
	    /// </summary>
		var scrollX = 0;
		var scrollY = 0;

		if (self.pageYOffset) 
		{
			// all except IE
			scrollX = self.pageXOffset;
			scrollY = self.pageYOffset;
		}
		else if (document.documentElement && document.documentElement.scrollTop)
		{
			// IE 6 Strict
			scrollX = document.documentElement.scrollLeft;
			scrollY = document.documentElement.scrollTop;
		}
		else if (document.body) // all other Explorers
		{
			// All other IE
			scrollX = document.body.scrollLeft;
			scrollY = document.body.scrollTop;
		}
		return {x:scrollX, y:scrollY};
	}
	
	this.getElementByIdWithin = function(id, parentElement)
	{
	    /// <summary>Get ElementById within parentElement</summary>
	    
	    // If no element was provided, use document as parentElement
        parentElement = parentElement || document;
        
        // If the browser allows getElementId on a node, then use that
        if (parentElement.getElementById) 
            return parentElement.getElementById(id);
        else
        {
            var nodeQueue = [];
            var childNodes = parentElement.childNodes;
            
            // Loop through child nodes until we have a match
            for (var i = 0; i < childNodes.length; i++) 
            {
                var node = childNodes[i];
                if (node.nodeType == 1) nodeQueue[nodeQueue.length] = node;
            }

            while (nodeQueue.length) 
            {
                node = nodeQueue.shift();
                
                // Return Matching Element if Found
                if (node.id == id) return node;
                
                childNodes = node.childNodes;
                
                for (i = 0; i < childNodes.length; i++) 
                {
                    node = childNodes[i];
                    if (node.nodeType == 1) nodeQueue[nodeQueue.length] = node;
                }
            }
        }
        
        // No Match Found
        return null;   
    }

    this.getElementsByXPath = function(expression, parentElement) 
    {
        /// <summary>Gets an element by XPath.  
        /// This is not supported by all browsers, check RealAge.Utils.BrowserFeatures.XPath first to
        /// verify that the current browser supports this feature.</summary>
        var matchingElements = [];
        parentElement = parentElement || document;
        var query = document.evaluate(expression, parentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        var length = query.snapshotLength;
        for (var i = 0; i < length; i++) matchingElements.push(query.snapshotItem(i));
        return matchingElements;
    }

    this.getElementsByClassName = function(className, parentElement) 
    {
        ///<summary>Get elements by CSS Class. Within the parentElement. (optional)</summary>
        var matchingElements = new Array();
        
        parentElement = parentElement || document;

        if(parentElement.getElementsByClassName)
        {
            // Super fast way to do this if browser supports it.
            matchingElements = parentElement.getElementsByClassName(className);
        }
        else
        {
            if (this.BrowserFeatures.XPath) 
            {
                // Fast way to do this if browser supports it.
                var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
                matchingElements = this.getElementsByXPath(q, parentElement);
            } 
            else 
            {
                // The slowest way to do this, but it works.
                var children = (parentElement || document.body).getElementsByTagName('*');
                var elements = [], child;
                var childLen = children.length;
                
                // Create RegEx
                var pattern = new RegExp("(^|\\s)"+className+"(\\s|$)");
                // Search Through Child Nodes for Matches
                for(i = 0, j = 0; i < childLen; i++) 
                {
                    if( pattern.test(children[i].className) ) 
                    {
                        matchingElements[j] = children[i];
                        j++;
                    }
                }
            }
        }
        return matchingElements;
    }

    this.trimString = function(srcString) 
    {
        ///<summary>Trims spaces from a string.</summary>
        return srcString.replace(/^\s+/, '').replace(/\s+$/, '');  
    }

    this.hasClassName = function(element, className) 
    {
        ///<summary>Returns true if the CSS className is found attached to the element.</summary>
        var elementClassName = element.className;
        return (elementClassName.length > 0 && (elementClassName == className ||
            new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
    }

    this.addClassName = function(element, className)
    {
        ///<summary>Adds a CSS class to the element if class does not already exist.</summary>
        if(!this.hasClassName(element, className))
        {
            element.className += (element.className ? ' ' : '') + className;
        }
        return element;
    }

    this.removeClassName = function(element, className)
    {
        ///<summary>Removes a CSS class from an element.</summary>
        if(element.className)
        {
            element.className = element.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ');
        }
        return element;
    }

    this.toggleClassName = function(element, className) 
    {
        ///<summary>Adds or removes the specified CSS class from an element.</summary>
        if (this.hasClassName(element, className)) this.removeClassName(element, className);
        else this.addClassName(element, className);
        return(element);
    }
 
}
