window.dreamBoxes = new Object();

/** 
* DreamBox Contructor
*
* @param clientId, the ID of the DreamBox HTML element
*/
function DreamBox(clientId)
{
    this.popup = document.getElementById(clientId);
    this.initialContent = document.getElementById(clientId + "_content");
    this.content = this.initialContent;
    this.overlay = document.getElementById(clientId + "_overlay");
    this.loading = false;
    this.onLoad = null;
    this.cookieSet = false;
    this.processingTimeout = null;
    this.imagesLoaded = 0;
    this.isIE = navigator.userAgent.indexOf("MSIE") > -1;
    this.ieVersion = this.isIE ? parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE") + 5)) : 0;
    this.positionAbsolute = this.isIE && this.ieVersion > 6;
    this.iframe = null;
    this.visible = false;
    this.scrollX = 0;
    this.scrollY = 0;

    var box = this;
    this.navigateEvent = function(evt, link) { return box.FollowLink(evt, link); }
    this.hideEvent = function(evt, link) { box.Hide(evt, link); }
    if (this.overlay != null) { AddEvent(this.overlay, "click", function() { box.Hide(null, null); }); }
    AddEvent(document, "keydown", function(evt) { return box.KeyDown(evt); });

    this.Initialize(this.popup);
}

/**
* Show the DreamBox
*/
DreamBox.prototype.Show = function()
{
    if (!this.visible)
    {
        if (this.overlay != null)
        {
            if (this.isIE && this.ieVersion <= 6)
            {
                if (this.iframe == null)
                {
                    this.iframe = document.createElement("iframe");
                    this.iframe.id = "jsDreamBoxFrame";
                    this.iframe.name = "jsDreamBoxFrame";
                    this.iframe.setAttribute("frameBorder", "0");
                    this.overlay.appendChild(this.iframe);
                    frames["jsDreamBoxFrame"].document.write("<body style=\"background-color:" + this.overlay.currentStyle["backgroundColor"] + "\"></body>");
                }
                else { this.overlay.appendChild(this.iframe); }
                this.AddCssClass(document.documentElement, "dreambox-IE");
            }

            this.RemoveCssClass(this.overlay, "jsDreamBoxHidden");
        }

        this.RemoveCssClass(this.popup, "jsDreamBoxHidden");
        this.visible = true;
    }
}

/**
* Hide the DreamBox
*
* @param evt, mouse event (generated by browser)
* @param link, the clicked link
*/
DreamBox.prototype.Hide = function(evt, link)
{
    if (this.visible && !this.loading)
    {
        if (this.overlay != null)
        {
            this.AddCssClass(this.overlay, "jsDreamBoxHidden");
            if (this.isIE && this.ieVersion <= 6)
            {
                this.RemoveCssClass(document.documentElement, "dreambox-IE");
                if (this.iframe != null && this.iframe.parentNode != null) { this.iframe.parentNode.removeChild(this.iframe); }
            }
        }

        this.AddCssClass(this.popup, "jsDreamBoxHidden");

        if (this.content != this.initialContent)
        {
            this.content.parentNode.insertBefore(this.initialContent, this.content);
            this.content.parentNode.removeChild(this.content);
            this.content = this.initialContent;
        }

        this.popup.style.height = "";
        this.popup.style.marginLeft = "";
        this.popup.style.marginTop = "";
        this.popup.style.width = "";

        this.visible = false;
    }

    return PreventDefault(evt);
}

/**
* Set DreamBox width and height in pixels
*
* @param width, new width
* @param height, new height
*/
DreamBox.prototype.SetWidthHeight = function(width, height)
{
    this.popup.style.width = width + "px";
    this.popup.style.height = height + "px";
    this.Center(width, height);
}

/**
* Center DreamBox
*
* @param width, width to calcute left position, 0 uses current DreamBox width
* @param height, height to calcute top position, 0 uses current DreamBox height
*/
DreamBox.prototype.Center = function(width, height)
{
    width = width > 0 ? width : this.popup.offsetWidth;
    height = height > 0 ? height : this.popup.offsetHeight;
    this.popup.style.marginLeft = (0 - (parseInt(width / 2) - this.scrollX)) + "px";
    this.popup.style.marginTop = (0 - (parseInt(height / 2) - this.scrollY)) + "px";
}

/**
* Load a page into the DreamBox
*
* @param path, relative or absolute path of page to load
*/
DreamBox.prototype.LoadPage = function(path)
{
    if (!this.loading)
    {
        this.loading = true;
        this.imagesLoaded = 0;
        var box = this;
        this.processingTimeout = setTimeout(function()
        {
            box.AddCssClass(box.popup, "jsDreamBoxProcessing");
            box.processingTimeout = null;
        }, 1000);
        this.HTTPGet(path);
    }
}

/**
* Empty the DreamBox
*/
DreamBox.prototype.EmptyContent = function()
{
    var emptyContent = this.content.cloneNode(false);
    emptyContent.style.width = "";
    this.content.parentNode.insertBefore(emptyContent, this.content);
    var oldContent = this.content.parentNode.removeChild(this.content);
    this.content = emptyContent;
    oldContent = null;
}

DreamBox.prototype.Initialize = function(el)
{
    this.InitNavigation(el, "jsDreamBoxNav", "a", this.navigateEvent);
    this.InitNavigation(el, "jsDreamBoxClose", null, this.hideEvent);
    this.InitForm(el);

    this.ShowControlsOnce();

    if (this.onLoad != null && this.onLoad instanceof Function)
    {
        this.onLoad(el);
    }
}

DreamBox.prototype.InitNavigation = function(el, className, tagName, func)
{
    var nodes = this.GetElementsByClassName(el, className, tagName);
    if (nodes.length > 0) { for (var i = 0; i < nodes.length; i++) { this.AddClickEvent(nodes[i], func); } }
}

DreamBox.prototype.InitForm = function(el)
{
    var forms = this.GetElementsByClassName(el, "jsDreamBoxForm", "form");
    for (var i = 0; i < forms.length; i++) { this.AddFormEvent(forms[i]); }
}

/**
* Show DreamBox controls once when cookie doesn't exist
*/
DreamBox.prototype.ShowControlsOnce = function()
{
    if (this.CookieExists())
    {
        this.SetCookie();
    }
    else
    {
        var nodes = this.GetElementsByClassName(this.popup, "jsDreamBoxOnce", null);

        if (nodes.length > 0)
        {
            var box = this;

            var showFunc = function(show)
            {
                for (var i = 0; i < nodes.length; i++)
                {
                    if (show) { box.RemoveCssClass(nodes[i], "jsDreamBoxOnce"); }
                    else { box.AddCssClass(nodes[i], "jsDreamBoxOnce"); }
                }
            }

            showFunc(true);
            setTimeout(function() { showFunc(false); }, 5000);
            this.SetCookie();
        }
    }
}

/**
* Check if DreamBox cookie exists
*/
DreamBox.prototype.CookieExists = function()
{
    return document.cookie.length > 0 && document.cookie.indexOf("dreambox_tempcontrols=1") > -1;
}

/**
* Set DreamBox cookie
*/
DreamBox.prototype.SetCookie = function()
{
    if (!this.cookieSet)
    {
        var expireDate = new Date();
        expireDate.setDate(expireDate.getDate() + 10);
        document.cookie = "dreambox_tempcontrols=1;expires=" + expireDate.toGMTString();
        this.cookieSet = true;
    }
}

DreamBox.prototype.ClearProcessingTimeout = function()
{
    if (this.processingTimeout != null)
    {
        clearTimeout(this.processingTimeout);
        this.processingTimeout = null;
    }
    else { this.RemoveCssClass(this.popup, "jsDreamBoxProcessing"); }
}

DreamBox.prototype.StoreScrollPosition = function(clear)
{
    this.scrollX = clear ? 0 : document.documentElement.scrollLeft;
    this.scrollY = clear ? 0 : document.documentElement.scrollTop;
}

DreamBox.prototype.FollowLink = function(evt, link)
{
    this.LoadPage(link.getAttribute("href"));
    return PreventDefault(evt); ;
}

DreamBox.prototype.GetMatchCount = function(html, substring)
{
    var regExp = new RegExp(substring, "gim");
    var matches = html.match(regExp);
    return matches == null ? 0 : matches.length;
}

DreamBox.prototype.ExtractElementHTMLById = function(html, id)
{
    var elementHTML = "";
    var match = new RegExp("<([^>]*) id=\"" + id + "\"[^>]*>", "i").exec(html);

    if (match != null && match.index > -1)
    {
        var startIndex = match.Index;
        var tagName = match[1];
        html = html.substring(match.index);

        var endTagExpression = "</" + tagName + ">";
        var endTagIndex = html.search(endTagExpression, "i");

        if (endTagIndex > -1)
        {
            endTagIndex += tagName.length + 3;
            var i = 0;
            elementHTML = html.substring(0, endTagIndex);
            html = html.substring(endTagIndex);

            while (this.GetMatchCount(elementHTML, "<" + tagName + "[^>]*?>") > this.GetMatchCount(elementHTML, endTagExpression) && i < 5000)
            {
                endTagIndex = html.search(endTagExpression, "i");

                if (endTagIndex > -1)
                {
                    endTagIndex += tagName.length + 3;
                    elementHTML += html.substring(0, endTagIndex);
                    html = html.substring(endTagIndex);
                }

                i++;
            }
        }
    }

    return elementHTML;
}

DreamBox.prototype.ParseHTML = function(html)
{
    var popupHTML = this.ExtractElementHTMLById(html, this.popup.id + "_content");
    var newContent = null;

    if (popupHTML != null && popupHTML != "")
    {
        var tempDiv = document.createElement("div");
        tempDiv.innerHTML = popupHTML;
        newContent = tempDiv.removeChild(tempDiv.firstChild);
        tempDiv = null;
    }

    this.ClearProcessingTimeout();

    if (newContent == null) { this.Hide(null, null); }
    else { this.InitNewPopup(newContent); }
}

DreamBox.prototype.InitNewPopup = function(newContent)
{
    var newPopup = this.popup.cloneNode(false);
    newPopup.style.cssText = "";
    newPopup.style.left = "0";
    newPopup.style.top = "0";
    newPopup.style.visibility = "hidden";
    newPopup.appendChild(newContent);

    this.imagesLoaded = 0;

    var box = this;
    var swapFunc = function() { box.SwapBoxes(newPopup, newContent); }

    var images = newPopup.getElementsByTagName("img");
    var length = images.length;
    var swapNow = length == 0;

    if (!swapNow)
    {
        for (var i = 0; i < length; i++)
        {
            if (images[i].complete) { this.imagesLoaded++; }
            else { this.AddImageLoadEvent(images[i], length, swapFunc); }
        }

        swapNow = this.imagesLoaded == length;
    }

    this.popup.parentNode.insertBefore(newPopup, this.popup);
    if (swapNow) { swapFunc(); }
}

DreamBox.prototype.AddImageLoadEvent = function(img, total, swapFunc)
{
    var box = this;
    AddEvent(img, "load", function() { box.ImageLoaded(img, total, swapFunc); });
    AddEvent(img, "error", function() { box.ImageLoaded(img, total, swapFunc); });
}

DreamBox.prototype.ImageLoaded = function(img, total, swapFunc)
{
    this.imagesLoaded++;
    if (this.imagesLoaded == total) { swapFunc(); }
}

DreamBox.prototype.SwapBoxes = function(newPopup, newContent)
{
    var currentWidth = this.popup.offsetWidth;
    var currentHeight = this.popup.offsetHeight;
    var targetWidth = newPopup.offsetWidth;
    var targetHeight = newPopup.offsetHeight;

    newPopup.parentNode.removeChild(newPopup);

    if (currentWidth == targetWidth && currentHeight == targetHeight)
    {
        this.ChangeContent(newContent);
        this.loading = false;
    }
    else
    {
        var widthDiff = targetWidth - currentWidth;
        var heightDiff = targetHeight - currentHeight;
        var widthValue = widthDiff > 0 ? widthDiff : 0 - widthDiff;
        var heightValue = heightDiff > 0 ? heightDiff : 0 - heightDiff;
        var widthAddValue = heightValue > 0 && heightValue > widthValue ? (widthValue / heightValue) * 50 : 50;
        var heightAddValue = widthValue > 0 && widthValue > heightValue ? (heightValue / widthValue) * 50 : 50;
        this.AnimateSwap(newContent, currentWidth, currentHeight, targetWidth, targetHeight, widthDiff, heightDiff, widthAddValue, heightAddValue);
    }
}

DreamBox.prototype.ChangeContent = function(newContent)
{
    var oldContent = this.content;
    this.content.parentNode.insertBefore(newContent, oldContent);
    this.content.parentNode.removeChild(oldContent);
    this.content = newContent;
    this.Initialize(newContent);
}

DreamBox.prototype.AnimateSwap = function(newContent, currentWidth, currentHeight, targetWidth, targetHeight, widthDiff, heightDiff, widthAddValue, heightAddValue)
{
    var widthSet = currentWidth == targetWidth;
    var heightSet = currentHeight == targetHeight;
    var setAbsolute = true;
    var box = this;

    this.EmptyContent();

    var animateInterval = setInterval(function()
    {
        if (!widthSet)
        {
            if (widthDiff > 0)
            {
                currentWidth += widthAddValue;
                if (currentWidth > targetWidth) { currentWidth = targetWidth; }
            }
            else
            {
                currentWidth -= widthAddValue;
                if (currentWidth < targetWidth) { currentWidth = targetWidth; }
            }

            widthSet = currentWidth == targetWidth;
        }

        if (!heightSet)
        {
            if (heightDiff > 0)
            {
                currentHeight += heightAddValue;
                if (currentHeight > targetHeight) { currentHeight = targetHeight; }
            }
            else
            {
                currentHeight -= heightAddValue;
                if (currentHeight < targetHeight) { currentHeight = targetHeight; }
            }

            heightSet = currentHeight == targetHeight;
        }

        box.loading = !(widthSet && heightSet);

        if (box.positionAbsolute)
        {
            if (box.loading)
            {
                if (setAbsolute)
                {
                    box.StoreScrollPosition(false);
                    box.popup.style.position = "absolute";
                    setAbsolute = false;
                }
            }
            else
            {
                box.StoreScrollPosition(true);
                box.popup.style.position = "";
            }
        }

        box.SetWidthHeight(currentWidth, currentHeight);

        if (!box.loading)
        {
            clearInterval(animateInterval);
            box.ChangeContent(newContent);
        }
    }, 15);
}

DreamBox.prototype.GetElementsByClassName = function(el, className, tagName)
{
    var nodes = new Array();
    var classRegExp = new RegExp("\\b" + className + "\\b");
    var childNodes = el.getElementsByTagName(tagName == null ? "*" : tagName);
    for (var i = 0; i < childNodes.length; i++)
    {
        var classes = childNodes[i].className;
        if (classRegExp.test(classes)) { nodes.push(childNodes[i]); }
    }
    return nodes;
}

DreamBox.prototype.AddCssClass = function(el, className)
{
    if (el.className == "") { el.className = className; }
    else
    {
        var classes = el.className.split(" ");
        var found = false;
        var i = 0;

        while (!found && i < classes.length)
        {
            found = classes[i] == className;
            i++;
        }

        if (!found) { el.className += " " + className; }
    }
}

DreamBox.prototype.RemoveCssClass = function(el, className)
{
    if (el.className != "")
    {
        var oldClasses = el.className.split(" ");
        var newClasses = "";
        for (var i = 0; i < oldClasses.length; i++)
        {
            if (newClasses != "") { newClasses += " "; }
            if (oldClasses[i] != className) { newClasses += oldClasses[i]; }
        }

        el.className = newClasses;
    }
}

DreamBox.prototype.AddClickEvent = function(el, func)
{
    AddEvent(el, "click", function(evt) { return func(evt, el); });
}

DreamBox.prototype.AddFormEvent = function(form)
{
    var box = this;
    AddEvent(form, "submit", function(evt) { return box.HTTPPost(evt, form); });
}

DreamBox.prototype.ImportNode = function(srcNode)
{
    var tempDiv = document.createElement("div");
    tempDiv.innerHTML = srcNode.outerHTML;
    var importNode = tempDiv.removeChild(tempDiv.firstChild);
    tempDiv = null;
    return importNode;
}

DreamBox.prototype.InitHTTPRequest = function(path, method)
{
    if (path != null && path != "")
    {
        var data = null;

        if (window.XMLHttpRequest) { data = new XMLHttpRequest(); }
        else if (window.ActiveXObject)
        {
            var IE_XMLHTTPVER = ["MSXML4.XMLHTTP",
								 "MSXML3.XMLHTTP",
								 "MSXML2.XMLHTTP",
								 "MSXML.XMLHTTP",
								 "Microsoft.XMLHTTP"]
            var i = 0;

            while (data == null && i < IE_XMLHTTPVER.length)
            {
                try { data = new ActiveXObject(IE_XMLHTTPVER[i]); }
                catch (ex) { }
                i++;
            }
        }

        if (data != null)
        {
            if (data.overrideMimeType) { data.overrideMimeType("text/html"); }
            data.open(method, path, true);

            var box = this;
            data.onreadystatechange = function()
            {
                if (data.readyState == 4)
                {
                    if (data.status == 200) { box.ParseHTML(data.responseText); }
                    else
                    {
                        box.ClearProcessingTimeout();
                        box.Hide(null, null);
                    }
                    data = null;
                }
            }
        }
    }

    return data;
}

DreamBox.prototype.HTTPGet = function(path)
{
    var data = this.InitHTTPRequest(path, "GET");
    if (data != null) { data.send(null); }
}

DreamBox.prototype.HTTPPost = function(evt, form)
{
    var data = this.InitHTTPRequest(form.getAttribute("action"), "POST");

    if (data != null)
    {
        var values = this.GetFormValues(form);
        data.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        data.send(values);
    }

    return PreventDefault(evt);
}

DreamBox.prototype.GetFormValues = function(form)
{
    var values = "";
    var length = form.elements.length;

    for (var i = 0; i < length; i++)
    {
        var field = form.elements[i];
        var add = true;

        if (field.tagName.toLowerCase() == "input")
        {
            var fieldType = field.type.toLowerCase();

            switch (fieldType)
            {
                case "button":
                    add = false;
                    break;

                case "checkbox":
                    add = field.checked;
                    break;

                case "file":
                    add = false;
                    break;

                case "radio":
                    add = field.checked;
                    break;

                case "reset":
                    add = false;
                    break;
            }
        }

        if (add) { values = this.AddFormValue(values, field); }
    }

    return values;
}

DreamBox.prototype.AddFormValue = function(values, field)
{
    if (field.name != "")
    {
        if (values != "") { values += "&"; }
        values += field.name + "=" + encodeURIComponent(field.value);
    }

    return values;
}

DreamBox.prototype.NavigateByFirstLink = function(className)
{
    var navigate = false;
    var node = this.GetElementsByClassName(this.content, className, "a")[0];
    if (node != null)
    {
        var hRef = node.getAttribute("href");
        if (hRef != null && hRef != "")
        {
            this.LoadPage(hRef);
            navigate = true;
        }
    }
    return navigate;
}

DreamBox.prototype.KeyDown = function(evt)
{
    var defaultEvt = !this.visible;

    if (!defaultEvt)
    {
        switch (evt.which ? evt.which : evt.keyCode)
        {
            case 27: // ESC
                this.Hide(null, null);
                break;
            case 37: // Arrow left
                defaultEvt = !this.NavigateByFirstLink("jsDreamBoxNavPrev");
                break;
            case 39: // Arrow right
                defaultEvt = !this.NavigateByFirstLink("jsDreamBoxNavNext");
                break;
            default:
                defaultEvt = true;
                break;
        }
    }

    return defaultEvt ? true : PreventDefault(evt);
}

/**
Generic functions
*/

function AddEvent(el, evt, func)
{
    if (el.attachEvent) { el.attachEvent("on" + evt, func); } // IE
    else if (el.addEventListener) { el.addEventListener(evt, func, true); } // Gecko / W3C
    else { el["on" + evt] = func; }
}

function GetTargetEl(evt)
{
    if (evt.srcElement) { return evt.srcElement; }
    else { return evt.target; }
}

function PreventDefault(evt)
{
    if (evt != null && evt.preventDefault) { evt.preventDefault(); }
    return false;
}

/**
Functions to initialize DreamBox on page
*/


/**
* Check for existing DreamBox and create when null
*/
function GetDreamBox(clientId)
{
    var dreamBox = window.dreamBoxes[clientId];

    if (dreamBox == null)
    {
        dreamBox = new DreamBox(clientId);
        window.dreamBoxes[clientId] = dreamBox;
    }
    
    return dreamBox;
}

/**
* Open URL in DreamBox
*/
function LoadHRefInDreamBox(href)
{
    var dreamBox = GetDreamBox("dreambox");
    if (!dreamBox.visible) { dreamBox.Show(); }
    dreamBox.LoadPage(href);
}

/**
* Submit form to DreamBox
*/
function SubmitFormToDreamBox(evt, form)
{
    var dreamBox = GetDreamBox("dreambox");
    if (!dreamBox.visible) { dreamBox.Show(); }
    return dreamBox.HTTPPost(evt, form);
}

/**
* Open URL in DreamBox on element click
*
* @param link, a HTML anchor
*/
function AddDreamBoxOpenEvent(link)
{
    if (link.className.indexOf("jsDreamBoxOpen") > -1)
    {
        var href = link.getAttribute("href");

        if (href != null && href != "" && href.toLowerCase().indexOf("javascript:") == -1)
        {
            AddEvent(link, "click", function(evt)
            {
                LoadHRefInDreamBox(href);
                return PreventDefault(evt);
            });
        }
    }
}

/**
* Post form to DreamBox on submit
*
* @param form, a HTML form
*/
function AddDreamBoxSubmitEvent(form)
{
    if (form.className.indexOf("jsDreamBoxForm") > -1)
    {
        AddEvent(form, "submit", function(evt)
        {
            return SubmitFormToDreamBox(evt, form);
        });
    }
}

/**
* Initialize all links in an element to open in DreamBox
*/
AddEvent(window, "load", function()
{
    var links = document.body.getElementsByTagName("a");
    for (var i = 0; i < links.length; i++) { AddDreamBoxOpenEvent(links[i]); }
    var forms = document.body.getElementsByTagName("form");
    for (var i = 0; i < forms.length; i++) { AddDreamBoxSubmitEvent(forms[i]); }
});
