﻿////////////////////////////////////////////////////////////////////////////////////////////////////
// (c)2009 Noesis Innovation Inc. All rights reserved.
////////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////////////////////
// ElementManager
////////////////////////////////////////////////////////////////////////////////////////////////////
function ElementManager()
{
    var This = this;

    // Data members
    This.Elements = {};
    This.Classes =
    {
        Default: Element
    };
    This.Events =
    {
        'OnChange': { 'Name': 'OnChange', 'Bind': function(iElement, iHandler) { iElement.onchange = iHandler; } },
        'OnClick': { 'Name': 'OnClick', 'Bind': function(iElement, iHandler) { iElement.onclick = iHandler; } },
        'OnLoad': { 'Name': 'OnLoad', 'Bind': function(iElement, iHandler) { iElement.onload = iHandler; } },
        'OnMouseDown': { 'Name': 'OnMouseDown', 'Bind': function(iElement, iHandler) { iElement.onmousedown = iHandler; } },
        'OnMouseMove': { 'Name': 'OnMouseMove', 'Bind': function(iElement, iHandler) { iElement.onmousemove = iHandler; } },
        'OnMouseOut': { 'Name': 'OnMouseOut', 'Bind': function(iElement, iHandler) { iElement.onmouseout = iHandler; } },
        'OnMouseOver': { 'Name': 'OnMouseOver', 'Bind': function(iElement, iHandler) { iElement.onmouseover = iHandler; } },
        'OnMouseUp': { 'Name': 'OnMouseUp', 'Bind': function(iElement, iHandler) { iElement.onmouseup = iHandler; } },
        'OnScroll': { 'Name': 'OnScroll', 'Bind': function(iElement, iHandler) { iElement.onscroll = iHandler; } },
        'OnSubmit': { 'Name': 'OnSubmit', 'Bind': function(iElement, iHandler) { iElement.onsubmit = iHandler; } }
    };

    // Methods
    This.Create = function(iParentElement, iTagName, iId)
    {
        var documentElement = iParentElement.DocumentElement;
        var element = document.createElement(iTagName);

        element.id = iId;
        documentElement.appendChild(element);

        return This.Find(iId);
    }

    This.Get = function(iId)
    { return (This.Elements[iId]) ? This.Elements[iId] : This.Find(iId); }
        
    This.Find = function(iId)
    {
        var documentElement = document.getElementById(iId);

        if (documentElement)
        {
            var type = documentElement.tagName.toLowerCase();
            var ctor;
            var element;

            ctor = This.Classes[type];
            if (!ctor)
                ctor = This.Classes.Default;

            element = new ctor(documentElement);
            This.Elements[element.Id] = element;

            return element;
        }
        else
            return null;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Elements
////////////////////////////////////////////////////////////////////////////////////////////////////
var Elements = new ElementManager();

////////////////////////////////////////////////////////////////////////////////////////////////////
// ElementEventHandler
////////////////////////////////////////////////////////////////////////////////////////////////////
function ElementEventHandler(iElement, iEvent)
{
    var This = this;

    // Data members
    This.Element = iElement;
    This.Event = iEvent;
    
    // Methods
    This.Add = function(iHandler)
    {
        var _This = This;
        var eventHandler = new EventHandler();
        
        // bind to element event
        This.Element[This.Event.Name] = eventHandler;
        This.Event.Bind(This.Element.DocumentElement, eventHandler.Invoke);
        
        // add handler
        eventHandler.Add(iHandler);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// ElementClassManager
////////////////////////////////////////////////////////////////////////////////////////////////////
function ElementClassManager(iDocumentElement)
{
    var This = this;

    // Data members
    This.DocumentElement = iDocumentElement;
    This.Classes = [];

    // Methods
    This.Get = function()
    { return This.Classes; }

    This.Set = function(iClass)
    {
        if (typeof iClass == 'string')
            This.Classes = [iClass];
        else
            This.Classes = iClass;
        This.Update();
    }

    This.Add = function(iClass)
    {
        if (typeof iClass == 'string')
        {
            if (This.Has(iClass))
                return;
            This.Classes.push(iClass);
        }
        else
        {
            for (var i = 0; i < iClass.length; i++)
            {
                if (!This.Has(iClass))
                    This.Classes.push(iClass);
            }
        }
        This.Update();
    }

    This.Remove = function(iClass)
    {
        // TODO: implement with iClass as an array
        for (var i = 0; i < This.Classes.length; i++)
        {
            if (This.Classes[i] == iClass)
            {
                This.Classes.remove(i);
                This.Update();
                return;
            }
        }
    }

    This.Has = function(iClass)
    {
        for (var i = 0; i < This.Classes.length; i++)
        {
            if (This.Classes[i] == iClass)
                return true;
        }
        return false;
    }

    This.Clear = function()
    {
        This.Classes = [];
        This.Update();
    }

    This.Update = function(iFromDocument)
    {
        if (iFromDocument)
            This.Classes = This.DocumentElement.className.split(' ');
        else
        {
            var classes = '';
            for (var i = 0; i < This.Classes.length; i++)
                classes += ((i > 0) ? ' ' : '') + This.Classes[i];
            This.DocumentElement.className = classes;
        }
    }

    // Initialize
    {
        This.Update(true);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Element
////////////////////////////////////////////////////////////////////////////////////////////////////
function Element(iDocumentElement)
{
    var This = this;

    // Data members
    This.Id = null;
    This.DocumentElement = null;
    This.Class = new ElementClassManager(iDocumentElement);
    This.Style = iDocumentElement.style;

    // Events
    This.OnClick = new ElementEventHandler(This, Elements.Events.OnClick);
    This.OnMouseDown = new ElementEventHandler(This, Elements.Events.OnMouseDown);
    This.OnMouseMove = new ElementEventHandler(This, Elements.Events.OnMouseMove);
    This.OnMouseOut = new ElementEventHandler(This, Elements.Events.OnMouseOut);
    This.OnMouseOver = new ElementEventHandler(This, Elements.Events.OnMouseOver);
    This.OnMouseUp = new ElementEventHandler(This, Elements.Events.OnMouseUp);

    // Methods
    This.GetContent = function()
    { return This.DocumentElement.innerHTML; }

    This.SetContent = function(iContent)
    { This.DocumentElement.innerHTML = iContent; }

    This.GetParent = function()
    { throw "Not implemented"; }

    This.IsChildOf = function(iParent)
    {
        var parentElement = iParent.DocumentElement;
        var element = This.DocumentElement;

        for (;;)
        {
            if (element == parentElement)
                return true;
            if (element.parentNode)
                element = element.parentNode;
            else
                break;
        }

        return false;
    }

    This.IsPartOf = function(iSuperElement)
    { return (This.DocumentElement == iSuperElement.DocumentElement) || This.IsChildOf(iSuperElement); }
    
    This.GetPosition = function()
    { return { x: This.DocumentElement.offsetLeft, y: This.DocumentElement.offsetTop }; }
    
    // Initialize
    {
        This.Id = iDocumentElement.id;
        This.DocumentElement = iDocumentElement;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
