////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////

var __CFPOPUP_ERROR_HIDDEN = "popup is already hidden";
var __CFPOPUP_ERROR_ID = "invalid CFPopup id";
var __CFPOPUP_ERROR_VISIBLE = "popup is already visible";

var __CFPOPUP_WARNING_REFRESH = "windowed element hiding is disabled";

var __CFPOPUP_HIDE_TIME = 0;
var __CFPOPUP_SHOW_TIME = 0;

var __CFPOPUP_WINDOWED_TAGS = [];

////////////////////////////////////////////////////////////////////////////////
// Static Variables
////////////////////////////////////////////////////////////////////////////////

var __cfPopupHiddenElements = new Array();
var __cfPopupMap = {};

////////////////////////////////////////////////////////////////////////////////
// Classes
////////////////////////////////////////////////////////////////////////////////

function CFPopup(id)
{
    CFWidget.call(this, id);
    this.__bottomPosition = undefined;
    this.__hideTimer = undefined;
    this.__leftPosition = 0;
    this.__rightPosition = undefined;
    this.__showTimer = undefined;
    this.__topPosition = 0;
    this.__hideStyle();
    __cfPopupMap[id] = this;
    var f = cfEventHandlerCreate(this.__hide.bind(this));
    this.__hideEvent = f;
    f = cfEventHandlerCreate(this.__show.bind(this));
    this.__showEvent = f;
}

CFPopup.extendClasses(CFWidget);

CFPopup.prototype.__clearHideTimer = function()
{
    var timer = this.__hideTimer;
    if (timer) {
        window.clearTimeout(timer);
        this.__hideTimer = undefined;
    }
}

CFPopup.prototype.__clearShowTimer = function()
{
    var timer = this.__showTimer;
    if (timer) {
        window.clearTimeout(timer);
        this.__showTimer = undefined;
    }
}

CFPopup.prototype.__hide = function()
{
    this.__clearHideTimer();
    this.__hideStyle();
    this.refresh();
    this.__triggerEvent(CFWIDGET_EVENT_HIDE);
    __cfPopupRefreshHiddenElements();
}

CFPopup.prototype.__hideStyle = function()
{
    var style = this.getElement().style;
    style.display = "none";
    style.bottom = '';
    style.left = '';
    style.right = '';
    style.top = '';
    this.__visible = false;
}

CFPopup.prototype.__setPosition = function(bottom, left, right, top)
{
    this.__bottomPosition = bottom;
    this.__leftPosition = left;
    this.__rightPosition = right;
    this.__topPosition = top;
    if (this.isVisible()) {
        var style = this.getElement().style;
        style.bottom = (typeof(bottom) == "undefined") ? '' : bottom + "px";
        style.left = (typeof(left) == "undefined") ? '' : left + "px";
        style.right = (typeof(right) == "undefined") ? '' : right + "px";
        style.top = (typeof(top) == "undefined") ? '' : top + "px";
        __cfPopupRefreshHiddenElements();
    }
}

CFPopup.prototype.__show = function()
{
    this.__clearShowTimer();
    var style = this.getElement().style;
    var bottom = this.__bottomPosition;
    style.bottom = (typeof(bottom) == "undefined") ? '' : bottom + "px";
    var left = this.__leftPosition;
    style.left = (typeof(left) == "undefined") ? '' : left + "px";
    var right = this.__rightPosition;
    style.right = (typeof(right) == "undefined") ? '' : right + "px";
    var top = this.__topPosition;
    style.top = (typeof(top) == "undefined") ? '' : top + "px";
    style.display = "block";
    this.__visible = true;
    this.refresh();
    this.__triggerEvent(CFWIDGET_EVENT_SHOW);
    __cfPopupRefreshHiddenElements();
}

CFPopup.prototype.getHideTime = function()
{
    return __CFPOPUP_HIDE_TIME;
}

CFPopup.prototype.getShowTime = function()
{
    return __CFPOPUP_SHOW_TIME;
}

CFPopup.prototype.hide = function()
{
    this.__clearShowTimer();
    if (this.isVisible() && (typeof(this.__hideTimer) == "undefined")) {
        this.__hideTimer = window.setTimeout(this.__hideEvent,
                                             this.getHideTime());
    }
}

CFPopup.prototype.isVisible = function()
{
    return this.__visible;
}

CFPopup.prototype.setBottomLeftPosition = function(bottom, left)
{
    this.__setPosition(bottom, left, undefined, undefined);
}

CFPopup.prototype.setBottomRightPosition = function(bottom, right)
{
    this.__setPosition(bottom, undefined, right, undefined);
}

CFPopup.prototype.setTopLeftPosition = function(top, left)
{
    this.__setPosition(undefined, left, undefined, top);
}

CFPopup.prototype.setTopRightPosition = function(top, right)
{
    this.__setPosition(undefined, undefined, right, top);
}

CFPopup.prototype.show = function()
{
    this.__clearHideTimer();
    if ((! this.isVisible()) && (typeof(this.__showTimer) == "undefined")) {
        this.__showTimer = window.setTimeout(this.__showEvent,
                                             this.getShowTime());
    }
}

////////////////////////////////////////////////////////////////////////////////
// Private functions
////////////////////////////////////////////////////////////////////////////////

function __cfPopupRefreshHiddenElementsDisabled()
{
    // Nothing to do.
}

function __cfPopupRefreshHiddenElementsEnabled()
{
    var candidateElements = new Array();
    for (var i = 0; i < __CFPOPUP_WINDOWED_TAGS.length; i++) {
        var tag = __CFPOPUP_WINDOWED_TAGS[i];
        var tagElements = document.getElementsByTagName(tag);
        for (var j = 0; j < tagElements.length; j++) {
            candidateElements.push(tagElements[j]);
        }
    }
    var newHiddenElements = new Array();
    var oldHiddenElements = __cfPopupHiddenElements;
    for (var id in __cfPopupMap) {
        var win = __cfPopupMap[id];
        if (! win.isVisible()) {
            continue;
        }
        var windowElement = win.getElement();
        var elements = cfElementIntersectsElements(windowElement,
                                                   candidateElements);
        for (var i = 0; i < elements.length; i++) {
            var element = elements[i];
            if (cfElementHasDescendant(windowElement, element)) {
                continue;
            }
            if (! newHiddenElements.contains(element)) {
                newHiddenElements.push(element);
            }
        }
    }
    for (var i = 0; i < newHiddenElements.length; i++) {
        var element = newHiddenElements[i];
        if (! oldHiddenElements.contains(element)) {
            cfElementAddClass(element, CFELEMENT_INVISIBLE_CLASS);
        }
    }
    for (var i = 0; i < oldHiddenElements.length; i++) {
        var element = oldHiddenElements[i];
        if (! newHiddenElements.contains(element)) {
            cfElementRemoveClass(element, CFELEMENT_INVISIBLE_CLASS);
        }
    }
    __cfPopupHiddenElements = newHiddenElements;
}

////////////////////////////////////////////////////////////////////////////////
// Public API
////////////////////////////////////////////////////////////////////////////////

function cfPopupGet(id)
{
    var popup = __cfPopupMap[id];
    if (! popup) {
        return cfErrorTrigger("cfPopupGet: '" + id + "': " +
                              __CFPOPUP_ERROR_ID);
    }
    return popup;
}

////////////////////////////////////////////////////////////////////////////////
// Initialization
////////////////////////////////////////////////////////////////////////////////

// Windowed components are browser-dependent.  Here's a list of windowed
// components discovered thus far: applet, button (?), embed, iframe, input,
// isindex, object, select, textarea

var browserOS = cfBrowserGetOS();
var browserVersion = cfBrowserGetVersion();
switch (cfBrowserGetName()) {
case CFBROWSER_EXPLORER:
    if (browserVersion < 7) {
        __CFPOPUP_WINDOWED_TAGS.push("select");
        if (browserVersion < 5.5) {
            __CFPOPUP_WINDOWED_TAGS.push("iframe");
        }
    }
    break;
case CFBROWSER_NETSCAPE:
    if (browserVersion < 7) {
        __CFPOPUP_WINDOWED_TAGS.extend(["iframe", "select"]);
        if (browserVersion < 6) {
            __CFPOPUP_WINDOWED_TAGS.extend(["input", "isindex", "textarea"]);
        }
    }
    break;
case CFBROWSER_OPERA:
    // XX: The browser version is a guess.  Check this later.
    __CFPOPUP_WINDOWED_TAGS.push("iframe");
    if (browserVersion < 8.5) {
        __CFPOPUP_WINDOWED_TAGS.extend(["input", "isindex", "select",
                                        "textarea"]);
    }
    break;
// Webkit-based browsers
case CFBROWSER_OMNIWEB:
case CFBROWSER_SAFARI:
    break;
// Gecko-based browsers
case CFBROWSER_CAMINO:
case CFBROWSER_FIREFOX:
case CFBROWSER_MOZILLA:
case CFBROWSER_ICAB:
case CFBROWSER_KONQUEROR:
default:
    // Nothing to do.
}

var __cfPopupRefreshHiddenElements;
if (! __CFPOPUP_WINDOWED_TAGS.length) {
    __cfPopupRefreshHiddenElements = __cfPopupRefreshHiddenElementsDisabled;
} else if (document.getElementsByTagName) {
    __cfPopupRefreshHiddenElements = __cfPopupRefreshHiddenElementsEnabled;
} else {
    cfWarningTrigger("[popup]: " + __CFPOPUP_WARNING_REFRESH);
    __cfPopupRefreshHiddenElements = __cfPopupRefreshHiddenElementsDisabled;
}

