///////////////////////////////////////////////////////////////////////////////
// PRIDE: Element Wrapper/Helper object
///////////////////////////////////////////////////////////////////////////////

/// <summary>
/// Simple exception class for the ElementWrapper type.
/// </summary>
var ElementWrapperException = function(msg)
{
    this.Message = msg;
}

//
///////////////////////////////////////////////////////////////////////////////
//

/*
var IECSSStyleDeclaration = function(element)
{
    this.element = element;
    
    var renderCssText = function()
    {
        throw new Exception("Not yet supported.");
    }
    
    this.cssText = renderCssText();
    this.parentRule = null;
    this.length = 0;
}

IECSSStyleDeclaration.prototype = 
{
    getPropertyValue: function(propertyName)
    {
        var value = this.element.currentStyle[propertyName];
        return value;
    },
    
    getPropertyCSSValue: function(propertyName)
    {
    },
    
    removeProperty: function(propertyName)
    {
        throw new Exception("Not yet supported.");
    },
    
    getPropertyPriority: function(propertyName)
    {
        throw new DOMException("Priority is currently not supported.");
    },
    
    setProperty: function(propertyName, value, priority)
    {
        if (priority != null && priority != 'undefined')
        {
            throw new DOMException("Priority is currently not supported.");
        }
        
        this.element.currentStyle[propertyName] = value;
    },
    
    item: function(index)
    {
    }
}
*/

/// <summary>
/// Creates a new element wrapper around the element
/// with the specified id.
/// </summary>
var ElementWrapper = function(elID)
{
    this.elementID = elID;
    this.element = document.getElementById(elID);
    this.isValid = (this.element != null);
    
    this.pixelX = 0;
    this.pixelY = 0;
    this.pixelWidth = 0;
    this.pixelHeight = 0;
    
    this.pageX = null;
    this.pageY = null;
    
    // Set coordinates
    if (this.isValid)
    {
        this.pixelX = this.element.offsetLeft;
        this.pixelY = this.element.offsetTop;
        this.pixelWidth = this.element.offsetWidth;
        this.pixelHeight = this.element.offsetHeight;
    }
    
    this.getComputedStyle = function()
    {
//        if (window.getComputedStyle)
//        {
//            var style = window.getComputedStyle(this.element, null);
//            alert(propName);
//            return (style ? style[propName] : null);
//        }
//        else
//        {
//            var value = element.currentStyle[propName];
//            return value;
//        }
    }
    
    this.getComputedStyleValue = function(propName)
    {
        ElementWrapper.getComputedStyleValue(this.element, propName);
    }
}

ElementWrapper.getComputedStyleValue = function(element, propName)
{
    if (window.getComputedStyle)
    {
        var style = window.getComputedStyle(element, null);
        return (style ? style[propName] : null);
    }
    else
    {
        var value = element.currentStyle[propName];
        return value;
    }
}

ElementWrapper.prototype = 
{
    /// <summary>
    /// Determines if an element with the specified
    /// id is a child of this element.
    /// </summary>
    /// <param name="childID">The id of the child element to check for.</param>
    /// <returns>True if this element contains the specified child element, false otherwise.</returns>
    HasChild: function(childID)
    {
        if (childID == this.elementID)
            return false;

        var isChild = false;
        var curEl = document.getElementById(childID);
        while (curEl != null)
        {
            curEl = curEl.parentNode;
            if (curEl.id == this.elementID)
            {
                isChild = true;
                break;
            }
        }
        
        return isChild;
    },
    
    /// <summary>
    /// Determines if an element with the specified
    /// id is a parent of this element.
    /// </summary>
    /// <param name="parentID">The id of the parent element to check for.</param>
    /// <returns>True if this element is contained within specified paremt element, false otherwise.</returns>
    HasParent: function(parentID)
    {
        var hasParent = false;
        var curEl = this.element.parentNode;
        while (curEl != null)
        {
            if (curEl.id == parentID)
            {
                hasParent = true;
                break;
            }
            
            curEl = curEl.parentNode;
        }
        
        return hasParent;
    },
    
    FindContainingBlock: function()
    {
        var flag = false;
        var rootEl = this.element.parentNode;
        while (rootEl != null)
        {
            if (rootEl.tagName.toLowerCase() == "html")
            {
                flag = true;
            }
            else
            {
                var position = ElementWrapper.getComputedStyleValue(rootEl, "position");
                switch (position)
                {
                    case "absolute":
                    case "relative":
                    case "fixed":
                        flag = true;
                        break;
                }
            }
            
            if (flag)
                break;
                
            rootEl = rootEl.parentNode;
        }
                
        return new ElementWrapper(rootEl.id);
    },
    
    ComputePageLocation: function()
    {
        x = this.pixelX;
        y = this.pixelY;
        
        var cbEl = this.FindContainingBlock();
        while (cbEl != null)
        {
            x += cbEl.pixelX;
            y += cbEl.pixelY;
        }
        
        var size = new Size(x, y);
        return size;
    },
    
    /// <summary>
    /// Toggles the display value of the element.
    /// </summary>
    ToggleDisplay: function()
    {
        if (!this.isValid)
        {
            throw new ElementWrapperException("The underlying element is not valid.");
        }
        
        var curDisplay = this.element.style.display;
        
        if (curDisplay == "none")
        {
            switch (this.element.tagName)
            {
                case "tr":
                case "th":
                case "td":
                {
                    this.element.style.display = "";
                    break;
                }
                default:
                {
                    this.element.style.display = "block";
                    break;
                }
            }
        }
        else
        {
            this.element.style.display = "none";
        }
    },
    
    /// <summary>
    /// Shows the element.
    /// </summary>
    Show: function()
    {
        if (!this.isValid)
        {
            throw new ElementWrapperException("The underlying element is not valid.");
        }
        
        switch (this.element.tagName)
        {
            case "tr":
            case "th":
            case "td":
            {
                this.element.style.display = "";
                break;
            }
            default:
            {
                this.element.style.display = "block";
                break;
            }
        }
    },
    
    /// <summary>
    /// Hides the element.
    /// </summary>
    Hide: function()
    {
        if (!this.isValid)
        {
            throw new ElementWrapperException("The underlying element is not valid.");
        }
        
        this.element.style.display = "none";
    },
    
    /// <summary>
    /// Moves the element to the specified X and Y position.
    /// </summary>
    /// <param name="x">The x position to move the element to.</param>
    /// <param name="y">The y position to move the element to.</param>
    /// <remarks>The position coordinates may use any valid CSS unit type.</remarks>
    MoveTo: function(x, y)
    {
        if (!this.isValid)
        {
            throw new ElementWrapperException("The underlying element is not valid.");
        }
        
        this.element.style.left = x;
        this.element.style.top = y;
    },
    
    /// <summary>
    /// Moves the element to the specified X and Y pixel position,
    /// offset by the current offset values.
    /// </summary>
    /// <param name="x">The x pixel (excluding offset) to move the element to.</param>
    /// <param name="y">The y pixel (excluding offset) to move the element to.</param>
    /// <remarks>The position coordinates must represent pixels. The actual resulting 
    /// position of the element will be x+offsetX and y+offsetY, assuming an offset 
    /// is set.</remarks>
    MoveToPixels: function(x, y)
    {
        if (!this.isValid)
        {
            throw new ElementWrapperException("The underlying element is not valid.");
        }
        
        this.element.style.left = x + "px";
        this.element.style.top = y + "px";
    },
    
    /// <summary>
    /// Moves the element to the specified target element
    /// and adds the specified pixel offsets.
    /// </summary>
    MoveToElement: function(elID, offsetX, offsetY)
    {
        if (!this.isValid)
        {
            throw new ElementWrapperException("The underlying element is not valid.");
        } 
        
        var elTarget = new ElementWrapper(elID);
        if (!elTarget.isValid)
        {
            throw new ElementWrapperException("The target element is not valid.");
        }
        
        this.element.style.left = elTarget.pixelX + offsetX + "px";
        this.element.style.top = elTarget.pixelY + offsetY + "px";
    },
    
    /// <summary>
    /// Moves the element to the specified target element
    /// within page-relative scope, and adds the specivied
    /// pixel offsets.
    /// </summary>
    /// <remarks>
    /// This function will align the current elements containing
    /// block top and left coordinates to the top and left of 
    /// the target element.
    /// </remarks>
    MoveToPageRelativeElement: function(elID, offsetX, offsetY)
    {
        if (!this.isValid)
        {
            throw new ElementWrapperException("The underlying element is not valid.");
        }
        
        // Get the difference between this elements containing block,
        // and the target elements containing block
        
        var contBlockPos = this.FindContainingBlock().ComputePageLocation();
        var targetContBlockPos = new ElementWrapper(elID).FindContainingBlock().ComputePageLocation();
        
        var difX = targetContBlock.width - contBlock.width;
        var difY = targetContBlock.height - contBlock.height;
        
        alert(difX + ";" + difY);
    }
}
