//=============================================================================
// JavaScript WindowManager 
//=============================================================================
// Author: Jon Rista
// Date Created: 12/1/2007
// Date Modified: 6/19/2008
// Dependancies: MooTools v1.11
//=============================================================================

// WindowManager singleton
function WindowManager()
{
    var WINDOW_LEVEL = 10000; // 10,000 - 99,999
    //var m_windowLevelTopmost = 100000; // 100,000 - *
    
    var m_modalFormCount = 0;
    
    var m_formTypes = new Array();
    var m_activeForms = new Array();
    var m_visibleForms = new Array();
    
    var m_focusedForm = null;
    
    var m_modalPanelElement = null;
    
    var form_dialogResult = function(form, result)
    {
        
        switch (result)
        {
            case DialogResult.ok:
            {
                break;
            }
            case DialogResult.cancel:
            {
                break;
            }
            case DialogResult.yes:
            {
                break;
            }
            case DialogResult.no:
            {
                break;
            }
        }
    }
    
    var modalPanel_click = function(event)
    {
        if (m_focusedForm != null)
        {
            m_focusedForm.titleElement.removeClass("focused");
            m_focusedForm = null;
        }
    };
    
    this.HasModalPanel = function()
    {
        return (m_modalPanelElement != null);
    }
    
    this.SetModalPanel = function(panelEl)
    {
        if (m_modalPanelElement != null)
        {
            m_modalPanelElement.removeEvent("click", modalPanel_click);
        }
        
        if (panelEl == null)
        {
            m_modalPanelElement = null;
        }
        else
        {
            m_modalPanelElement = $(panelEl);
            m_modalPanelElement.addEvent("click", modalPanel_click);
        }
    }
    
    this.ShowModalPanel = function()
    {
        m_modalFormCount++;
        if (m_modalPanelElement != null)
        {
            m_modalPanelElement.setStyle("opacity", 0.4);
            m_modalPanelElement.setStyle("display", "block");
        }
    }
    
    this.HideModalPanel = function()
    {
        m_modalFormCount--;
        if (m_modalFormCount <= 0)
        {
            m_modalFormCount = 0;
            if (m_modalPanelElement != null)
            {
                m_modalPanelElement.setStyle("display", "none");
            }
        }
    }
    
    this.RegisterType = function(formInfo)
    {
        var curFormInfo = m_formTypes[formInfo.name];
        if (curFormInfo != null)
        {
            throw new WindowManagerException("Form type already defined.", formInfo)
        }
        
        m_formTypes[formInfo.name] = formInfo;
    }
    
    this.RegisterForm = function(form)
    {
        m_activeForms[form.formInfo.name] = form;
        
        //form.addEvent("onDialogResult", form_dialogResult);
    }
    
    this.RegisterVisible = function(form)
    {
        var newLevel = WINDOW_LEVEL;
        for (var i=0; i<m_visibleForms.length; i++)
        {
            var rform = m_visibleForms[i];
            var curLevel = rform.element.getStyle("zIndex").toInt();
            if (newLevel < curLevel)
            {
                newLevel = curLevel;
            }
        }
        
        newLevel++;
        
        form.element.setStyle("zIndex", newLevel);
        m_visibleForms.push(form);
    }
    
    this.UnregisterVisible = function(form)
    {
        for (var i=0; i<m_visibleForms.length; i++)
        {
            var rform = m_visibleForms[i];
            if (rform == form)
            {
                m_visibleForms.splice(i,1);
                break;
            }
        }
    }
    
    this.AdjustLayering = function(form)
    {
        var frmLayer = form.element.getStyle("zIndex").toInt();
        
        var maxLayer = WINDOW_LEVEL;
        var curLayer = 0;
        
        for (var i=0; i<m_visibleForms.length; i++)
        {
            var rform = m_visibleForms[i];
            
            curLayer = rform.element.getStyle("zIndex").toInt();
            
            if (curLayer > maxLayer)
            {
                maxLayer = curLayer;
            }
            
            if (curLayer > frmLayer)
            {
                rform.element.setStyle("zIndex", curLayer - 1);
            }
        }
        
        form.element.setStyle("zIndex", maxLayer);
        this.FocusForm(form);
    }
    
    this.Create = function(name)
    {
        var formInfo = m_formTypes[name];
        if (formInfo == null)
        {
            throw new WindowManagerException("Form type is not defined.", name);
        }
        
        var form = new Form(formInfo);
        return form;
    }
    
    this.GetForm = function(name)
    {
        var form = m_activeForms[name];
        return form;
    }
    
    this.FocusForm = function(form)
    {
        if (m_focusedForm != null)
        {
            m_focusedForm.titleElement.removeClass("focused");
        }
        
        m_focusedForm = form;
        
        if (form != null)
        {
            form.titleElement.addClass("focused");
        }
    }
    
    this.Dispose = function(form)
    {
        //form.removeEvent("onDialogResult", form_dialogResult);
        
        m_activeForms[form.name] = null;
    }
}

var CurrentWindowManager = null;
WindowManager.Current = function()
{
    if (CurrentWindowManager == null)
    {
        CurrentWindowManager = new WindowManager();
    }
    
    return CurrentWindowManager;
}

WindowManager.FocusForm = function(form)
{
    WindowManager.Current().FocusForm(form);
}

WindowManager.RegisterActiveForm = function(form)
{
    WindowManager.Current().RegisterForm(form);
}

WindowManager.RegisterVisibleForm = function(form)
{
    WindowManager.Current().RegisterVisible(form);
}

WindowManager.UnregisterVisibleForm = function(form)
{
    WindowManager.Current().UnregisterVisible(form);
}

WindowManager.ReadjustLayering = function(form)
{
    WindowManager.Current().AdjustLayering(form);
}

// WindowManagerException exception class
var WindowManagerException = new Class({
    initialize: function(msg, data)
    {
        this.Message = msg;
        this.Data = data;
    }
});

// DialogResult enumeration
var DialogResult = new Class({
});

DialogResult.none = 0;
DialogResult.ok = 1;
DialogResult.cancel = 2;
DialogResult.yes = 3;
DialogResult.no = 4;

// FormInformation structure
var FormInformation = new Class({
    initialize: function(name, sizeable, draggable, rootEl, rootTitleEl, buttons)
    {
        this.name = name;
        this.sizeable = sizeable;                   // bool
        this.draggable = draggable;                 // bool
        this.rootElement = rootEl;                  // Html element 
        this.rootTitleElement = rootTitleEl;        // Html element of title bar
        this.buttons = buttons;                     // Array of buttons
    }
});

// Form class
var Form = new Class({
    Implements: [new Options, new Events],

    options: {
        onDialogResult: Class.empty,
        onShow: Class.empty,
        onHide: Class.empty
    },
    
    /// <summary>
    /// Initializes the Form class.
    /// </summary>
    initialize: function(formInfo, options)
    {
        this.setOptions(options);
        
        var el = formInfo.rootElement;
        var elTitle = formInfo.rootTitleElement;
        
        var form = this;
        
        this.visible = false;
        this.dialogResult = DialogResult.none;
        
        this.formInfo = formInfo;
        this.element = $(el);
        this.titleElement = $(elTitle);
        
        var form_click = function(event)
        {
            WindowManager.ReadjustLayering(form);
        };
        
        this.titleElement.addEvent("mousedown", form_click);
        this.element.addEvent("mousedown", form_click);
        
        // Configure draggability
        if (formInfo.draggable)
        {
            this.element.makeDraggable({'handle': this.titleElement});
        }
        
        // Configure sizeability
        if (formInfo.sizeable)
        {
        }
        
        // Register this form with the window manager
        WindowManager.RegisterActiveForm(this);
        
        // Internal handler for button clicks for registered buttons
        var button_click = function(event)
        {
            event = new Event(event);
            
            if (formInfo.buttons != null)
            {
                for (var i=0; i<formInfo.buttons.length; i++)
                {
                    var buttonInfo = formInfo.buttons[i];
                    if ($(buttonInfo.el).id == $(event.target).id)
                    {
                        form.dialogResult = buttonInfo.result;
                        form.fireEvent("onDialogResult", [form, buttonInfo.result]);
                        break;
                    }
                }
            }
        };
        
        // Attach handler to registered buttons
        if (formInfo.buttons != null)
        {
            for (var i=0; i<formInfo.buttons.length; i++)
            {
                var buttonInfo = formInfo.buttons[i];
                $(buttonInfo.el).addEvent("click", button_click);
            }
        }
    },
    
    center: function(centerParent)
    {
        this.centerVertically(centerParent);
        this.centerHorizontally(centerParent);
    },
    
    centerVertically: function(centerParent)
    {
        try
        {
            var parentSize = $(centerParent).getCoordinates();
    
            var elHeight = this.element.getStyle("height").toInt();
            
            var left = this.element.getStyle("left").toInt();
            var top = parentSize.height/2 - elHeight/2;
            top = top.toInt();
        
            this.moveTo(left, top);
        }
        catch (e)
        {
        }
    },
    
    /// <summary>
    /// Centers the form in the specified element.
    /// </summary>
    /// <param name="centerParent">The element to center within.</param>
    centerHorizontally: function(centerParent)
    {
        try
        {
            var parentSize = $(centerParent).getCoordinates();
    
            var elWidth = 0;
            if (this.element.currentStyle)
            {
                elWidth = this.element.currentStyle["width"].toInt();
            }
            else
            {
                elWidth = this.element.getStyle("width").toInt();
            }
            
            var top = this.element.getStyle("top").toInt();
            var left = parentSize.width/2 - elWidth/2;
            left = parentSize.left + left.toInt();

            this.moveTo(left, top);
        }
        catch (e)
        {
        }
    },
    
    /// <summary>
    /// Moves the form to the specified coordinates.
    /// </summary>
    /// <param name="x">The x coordinate to move to.</param>
    /// <param name="y">The y coordinate to move to.</param>
    moveTo: function(x, y)
    {
        if (x == '@')
            x = this.element.getStyle("left").toInt();
            
        if (y == '@')
            y = this.element.getStyle("top").toInt();
            
        this.element.setStyle("left", x);
        this.element.setStyle("top", y);
    },
    
    /// <summary>
    /// Moves the form to the specified viewport coordinates.
    /// </summary>
    /// <param name="x">The x coordinate in viewport scope to move to.</param>
    /// <param name="y">The y coordinate in viewport scope to move to.</param>
    moveToViewport: function(x, y)
    {
        var cx = this.element.getStyle("left").toInt();
        var cy = this.element.getStyle("top").toInt();
        
        var px = this.element.getLeft().toInt();
        var py = this.element.getTop().toInt();
        
        var dx = px - x;
        var dy = py - y;
        
        if (x == '@')
            dx = 0;
            
        if (y == '@')
            dy = 0;
        
        cx = cx + dx;
        cy = cy + dy;
        
        this.moveTo(cx, cy);
    },
    
    /// <summary>
    /// Moves the form to the specified coordinates using a sliding animation.
    /// </summary>
    /// <param name="x">The x coordinate to move to.</param>
    /// <param name="y">The y coordinate to move to.</param>
    slideTo: function(x, y)
    {
        if (x == '@')
            x = this.element.getStyle("left").toInt();
            
        if (y == '@')
            y = this.element.getStyle("top").toInt();
            
        this.element.set("morph", {duration: 500, transition: Fx.Transitions.Quad.easeInOut});
        this.element.morph({"top": y, "left": x});
    },
    
    /// <summary>
    /// Moves the form to the specified viewport coordinates using a sliding animation.
    /// </summary>
    /// <param name="x">The x coordinate in viewport scope to move to.</param>
    /// <param name="y">The y coordinate in viewport scope to move to.</param>
    slideToViewport: function(x, y)
    {
        var cx = this.element.getStyle("left").toInt();
        var cy = this.element.getStyle("top").toInt();
        
        var px = this.element.getLeft().toInt();
        var py = this.element.getTop().toInt();
        
        var dx = px - x;
        var dy = py - y;
        
        if (x == '@')
            dx = 0;
            
        if (y == '@')
            dy = 0;
        
        cx = cx + dx;
        cy = cy + dy;
        
        this.slideTo(cx, cy);
    },
    
    /// <summary>
    /// Show the window in non-modally.
    /// </summary>
    show: function()
    {
        if (!this.visible)
        {
            var form = this;
            
            this.fireEvent("onShow", form, 0);
            
            var showChain = new Chain();
            
            var registerVisibleForm = function()
            {
                WindowManager.RegisterVisibleForm(form);
                
                showChain.callChain();
            }
            
            var showNonModalDialog = function()
            {
                var showFx = new Fx.Tween(form.element, {
                    duration: 300,
                    transition: Fx.Transitions.Quart.easeInOut
                    }
                );
                
                var dlgShowChain = new Chain();
                
                var setStyles = function()
                {
                    form.element.setOpacity(0.0);
                    dlgShowChain.callChain();
                }
                
                var fixDisplay = function()
                {
                    form.element.setStyle("display", "block");
                    dlgShowChain.callChain();
                }
                
                var fadeDialog = function()
                {
                    showFx.start("opacity", 1);
                    form.visible = true;
                }
                
                dlgShowChain.chain(setStyles);
                dlgShowChain.chain(fixDisplay);
                dlgShowChain.chain(fadeDialog);
                dlgShowChain.callChain();
            }
            
            showChain.chain(registerVisibleForm);
            showChain.chain(showNonModalDialog);
            showChain.callChain();
        }
    },
    
    /// <summary>
    /// Show the window modally.
    /// </summary>
    showDialog: function()
    {
        if (!this.visible)
        {
            var form = this;
            
            this.fireEvent("onShow", form, 0);
            
            var showChain = new Chain();
            
            var showModalPanel = function()
            {
                WindowManager.Current().ShowModalPanel();
                
                showChain.callChain.delay(100, showChain);
            }
            
            var registerVisibleForm = function()
            {
                WindowManager.RegisterVisibleForm(form);
                
                showChain.callChain();
            }
            
            var showModalDialog = function()
            {
                var showFx = new Fx.Tween(form.element, {
                    duration: 400,
                    transition: Fx.Transitions.Quart.easeInOut
                    }
                );
                
                var dlgShowChain = new Chain();
                
                var setStyles = function()
                {
                    form.element.setOpacity(0.0);
                    dlgShowChain.callChain();
                }
                
                var fixDisplay = function()
                {
                    form.element.setStyle("display", "block");
                    dlgShowChain.callChain();
                }
                
                var fadeDialog = function()
                {
                    showFx.start("opacity", 1);
                    form.visible = true;
                }
                
                dlgShowChain.chain(setStyles);
                dlgShowChain.chain(fixDisplay);
                dlgShowChain.chain(fadeDialog);
                dlgShowChain.callChain();
            }
            
            showChain.chain(showModalPanel);
            showChain.chain(registerVisibleForm);
            showChain.chain(showModalDialog);
            showChain.callChain();
        }
    },
    
    /// <summary>
    /// Hide the window
    /// </summary>
    hide: function()
    {
        if (this.visible)
        {
            var form = this;           
            
            var hideChain = new Chain();
            
            var hideModalDialog = function()
            {
                var showFx = new Fx.Tween(form.element, {
                    duration: 400,
                    transition: Fx.Transitions.Quart.easeInOut
                    }
                );
                
                var dlgHideChain = new Chain();
                
                var setStyles = function()
                {
                    form.element.setOpacity(1.0);
                    dlgHideChain.callChain();
                }
                
                var fixDisplay = function()
                {
                    form.element.setStyle("display", "none");
                    form.visible = false;
                    //dlgHideChain.callChain();
                }
                
                var fadeDialog = function()
                {
                    showFx.start("opacity", 0);
                    dlgHideChain.callChain();
                }
                
                dlgHideChain.chain(setStyles);
                dlgHideChain.chain(fadeDialog);
                dlgHideChain.chain(fixDisplay);
                dlgHideChain.callChain();
                
                hideChain.callChain();
            }
            
            var unregisterVisibleForm = function()
            {
                WindowManager.UnregisterVisibleForm(form);
                
                hideChain.callChain();
            }
            
            var hideModalPanel = function()
            {
                WindowManager.Current().HideModalPanel();
                
                form.fireEvent("onHide", form);
            }
            
            hideChain.chain(hideModalDialog);
            hideChain.chain(unregisterVisibleForm);
            hideChain.chain(hideModalPanel);
            hideChain.callChain();
        }
    }
});

//Form.implement(new Options, new Events);