var cloupIt = {
    delay: 250,
    noDelay: 1,
    frames: [],
    frameWidth: 440 + 20,
    frameHeight: 250 + 20,
    urlRegEx: /cloupit.com\/(\w{6}$)/i,
    baseUrl: "http://cloupit.com/",
    satelliteUrl: "satellite/",
    satelliteReverseUrl: "satellite/url/",

    //determines if the ready method is already called
    readyCalled: false,

    //gets the ie browser version (999 for other browers)
    browser: {
        version: function() {
            if (navigator.appVersion.indexOf("MSIE") != -1)
                return parseFloat(navigator.appVersion.split("MSIE")[1]);
            return 999;
        }
    },

    //helper object for delayed calls
    delayHelper: new function() {
        var m_iTimerID = -1;
        var m_oMethod = null;
        var m_oArgs = null;

        var m_oSender = this;

        function clear() {
            if (m_iTimerID > 0) {
                clearInterval(m_iTimerID);
                m_iTimerID = -1;
                m_oMethod = null;
                m_oArgs = null;
            }
        }

        function call(method, delay, args) {

            if (m_oMethod == method) {
                if (m_oArgs.length == args.length) {
                    var tmp_bSameParams = true;
                    for (var i = 0; i < m_oArgs.length && !tmp_bSameParams; i++) {
                        if (m_oArgs[i] != args[i])
                            tmp_bSameParams = false;
                    }

                    if (tmp_bSameParams)
                        return;
                }
            }

            if (!delay) delay = 1;
            if (m_iTimerID > 0) clearInterval(m_iTimerID);
            m_iTimerID = setTimeout(function() { method.apply(m_oSender, args); }, delay);
            m_oMethod = method;
            m_oArgs = args;
        }

        //public interface
        return {
            call: function(method, delay) { call(method, delay, Array.prototype.slice.call(arguments, 2)); },
            clear: function() { clear(); }
        }
    },

    //preloads the images
    preloadImages: function() {
        var tmp_oImages = ["pic_cloupit_satellite_vshade.png", "pic_cloupit_satellite_hshade.png", "pic_cloupit_satellite_header.png",
            "pic_cloupit_satellite_cshade.png", "pic_clouping_16.png", "pic_cloupit_satellite_loading.gif", "pic_cloupit_satellite_scroll.png"];
        for (var i = 0; i < tmp_oImages.length; i++) {
            var tmp_oImage = new Image();
            tmp_oImage.src = cloupIt.baseUrl + "qios.silvergrid.webfeatures/gfx/" + tmp_oImages[i];
        }
    },

    //gets called when the DOM or the window is ready
    ready: function() {
        if (cloupIt.readyCalled) return;
        cloupIt.readyCalled = true;
        cloupIt.initialize();
    },

    //determines of the offset of an element
    offset: function(element) {
        var curleft = curtop = 0;
        if (element.offsetParent) {
            do {
                curleft += element.offsetLeft;
                curtop += element.offsetTop;
            } while (element = element.offsetParent);
        }
        return [curleft, curtop];
    },

    //gets the iframe for an anchor, creating one if it doesn't exist yet
    secureFrame: function(anchor) {
        //get the frame number
        var tmp_iIndex = parseInt(anchor.getAttribute("cloupItFrame"));

        //create the frame if it deosn't exist
        if (isNaN(tmp_iIndex)) {
            var tmp_oFrame = document.createElement("iframe");
            tmp_oFrame.setAttribute("frameBorder", "0");
            tmp_oFrame.setAttribute("scrolling", "no");
            tmp_oFrame.setAttribute("allowTransparency", "true");
            var tmp_sStyle = "display:none;position:absolute;z-index:5000;width:" + cloupIt.frameWidth + "px;height:" + cloupIt.frameHeight + "px;";
            //ff, webkit, opera
            tmp_oFrame.setAttribute("style", tmp_sStyle);
            //ie
            tmp_oFrame.style.cssText = tmp_sStyle;
            document.body.insertBefore(tmp_oFrame, document.body.firstChild);

            var tmp_oFrameWindow = (tmp_oFrame.contentWindow) ? tmp_oFrame.contentWindow : (tmp_oFrame.contentDocument.document) ? tmp_oFrame.contentDocument.document : tmp_oFrame.contentDocument;
            try {
                tmp_oFrameWindow.document.open();
                tmp_oFrameWindow.document.write("<div style='background-color:white;position:absolute;top:0px;left:0px;width:100%;height:100%;text-align:center;'><img style='position:relative;top:40%;' src='" + cloupIt.baseUrl + "qios.silvergrid.webfeatures/gfx/pic_cloupit_satellite_loading.gif'></div>");
                tmp_oFrameWindow.document.close();
            }
            catch (ex) { }

            tmp_iIndex = cloupIt.frames.length;
            cloupIt.frames[tmp_iIndex] = tmp_oFrame;
            anchor.setAttribute("cloupItFrame", tmp_iIndex);
        }

        //return the frame
        return cloupIt.frames[tmp_iIndex];
    },

    applyOverrides: function(overrides) {
        for (var tmp_sKey in overrides) {
            cloupIt[tmp_sKey] = overrides[tmp_sKey];
        }
    },

    //initializes the cloupIt anchors
    initialize: function() {

        if (typeof cloupItOverrides != "undefined")
            cloupIt.applyOverrides(cloupItOverrides);

        if (cloupIt.browser.version() < 7) return;

        cloupIt.addEventHandler(document, "mouseover", cloupIt.documentMouseOver);

        //initialize all anchors
        var tmp_oAnchors = document.getElementsByTagName("A");
        for (var i = 0; i < tmp_oAnchors.length; i++)
            cloupIt.initializeAnchor(tmp_oAnchors[i]);

        //preload images
        cloupIt.preloadImages();
    },

    //adds an event handler
    addEventHandler: function(element, event, handler) {
        if (document.addEventListener) {
            element.addEventListener(event, handler, false);
        }
        else if (document.attachEvent) {
            element.attachEvent("on" + event, function(e) {
                handler.apply(element, arguments);
            }, false);
        }
    },

    //initializes a specific cloupIt anchor
    initializeAnchor: function(anchor) {
        if (cloupIt.isAnchor(anchor)) {
            cloupIt.addEventHandler(anchor, "mouseover", cloupIt.anchorMouseOver);
            cloupIt.addEventHandler(anchor, "mouseout", cloupIt.anchorMouseOut);
        }
    },

    //determines if the child is within the parent
    isWithinElement: function(child, parent) {
        while (child && child != parent) {
            child = child.parentNode;
        }
        return (child == parent)
    },

    //handles the mouseover event of the document
    documentMouseOver: function(e) {
        var tmp_oFromElement = e.relatedTarget || e.fromElement;
        var tmp_oToElement = e.srcElement || e.target;
        if (cloupIt.isAnchorFrame(tmp_oFromElement)) {
            if (!cloupIt.isAnchor(tmp_oToElement))
                cloupIt.delayHelper.call(cloupIt.hideAnchorFrame, cloupIt.delay, null, tmp_oFromElement);
        } else if (cloupIt.isAnchorFrame(tmp_oToElement)) {
            cloupIt.delayHelper.clear();
        }
    },

    //handle the mouseover event of an anchor
    anchorMouseOver: function(e, b) {
        cloupIt.delayHelper.call(cloupIt.showAnchorFrame, cloupIt.noDelay, this);
    },

    //handle the mouseout event of an anchor
    anchorMouseOut: function(e) {
        var tmp_oNewElement = e.relatedTarget || e.toElement;
        if (cloupIt.isWithinElement(tmp_oNewElement, this) || cloupIt.isAnchorFrame(tmp_oNewElement))
            return;
        cloupIt.delayHelper.call(cloupIt.hideAnchorFrame, cloupIt.delay, this);
    },

    //determines if the element is (part of) an cloupIt anchor
    isAnchor: function(element) {
        while (element && element.tagName != "A") {
            element = element.parentNode;
        }
        if (element == null) return false;
        if (!cloupIt.urlRegEx) return false;

        //It might be suppressed.
        var tmp_oSuppress = element.getAttribute("suppresscloupitsatellite");
        if (tmp_oSuppress && tmp_oSuppress.toLowerCase() == "true") return false;

        //It might be a default cloupit URL.
        if (cloupIt.urlRegEx.test(element.getAttribute("href"))) return true;

        //It might contain a cloupitID
        var tmp_sWsr = element.getAttribute("cloupitid");
        if (tmp_sWsr && tmp_sWsr.length >= 4 && tmp_sWsr.length <= 8) return true;

        //It might contain a cloupitAnchor class
        if (element.className && (element.className.toLowerCase().indexOf("cloupitanchor") >= 0)) return true;

        return false;
    },

    //determines is the given element is an cloupIt iframe
    isAnchorFrame: function(frame) {
        if (!frame || frame.tagName != "IFRAME") return false;
        for (var i = 0; i < cloupIt.frames.length; i++)
            if (cloupIt.frames[i] == frame)
            return true;
        return false;
    },

    //gets the size of the visible part of the page
    getClientSize: function() {
        //IE in Quarksmode doesn't have documentElement filled, so we use the max of documentElement and body.
        return [
            Math.max(document.documentElement.clientWidth, document.body.clientWidth),
            Math.max(document.documentElement.clientHeight, document.body.clientHeight)
            ];
    },

    //gets the scrolll offset of the page
    getClientScrollOffset: function() {
        return [
            document.documentElement.scrollLeft || document.body.scrollLeft,
            document.documentElement.scrollTop || document.body.scrollTop
            ];
    },

    //positions the frame
    positionAnchorFrame: function(anchor, frame) {

        //Add some space on the left, so that you can hover to links above or below it.
        var tmp_iExtraLeftSpace = 30;

        if (anchor.getBoundingClientRect) {

            //get the client bounds of the link
            var tmp_oAnchorRect = anchor.getBoundingClientRect();

            //get the client window size
            var tmp_oClientSize = cloupIt.getClientSize();

            //get the client window scroll offset
            var tmp_oScrollOffset = cloupIt.getClientScrollOffset();

            //convert to a structure we can alter
            //Make the Anchor 2 pixels smaller. in IE 7.0 (Not 8.0) there is a gap between the Anchor and the Frame
            tmp_oAnchorRect = { top: tmp_oAnchorRect.top + 2, bottom: tmp_oAnchorRect.bottom - 2, left: tmp_oAnchorRect.left + 2, right: tmp_oAnchorRect.right - 2 };

            //Add some space on the left, so that you can hover to links above or below it.
            tmp_oAnchorRect.left += tmp_iExtraLeftSpace;

            //add page scrolling, element scrolling is taken care of the in the getBoundingClientRect
            tmp_oAnchorRect.left += tmp_oScrollOffset[0];
            tmp_oAnchorRect.right += tmp_oScrollOffset[0];
            tmp_oAnchorRect.bottom += tmp_oScrollOffset[1];
            tmp_oAnchorRect.top += tmp_oScrollOffset[1];

            //determine the horizontal overflow (negative value) and move the anchor rect left
            var tmp_oOverflowX = Math.min(0, tmp_oClientSize[0] - (tmp_oAnchorRect.left + cloupIt.frameWidth));
            tmp_oAnchorRect.left += tmp_oOverflowX;
            tmp_oAnchorRect.right += tmp_oOverflowX;

            //determine the vertical overflow as well
            var tmp_oOverflowY = Math.min(0, (tmp_oAnchorRect.top - cloupIt.frameHeight) - tmp_oScrollOffset[1]);

            //set location
            frame.style.left = tmp_oAnchorRect.left + "px";
            frame.style.top = (tmp_oAnchorRect.top - cloupIt.frameHeight) + "px";
            if (tmp_oOverflowY == 0) (tmp_oAnchorRect.top - cloupIt.frameHeight) + "px";
            else frame.style.top = tmp_oAnchorRect.bottom + "px";
        } else {
            var tmp_oPosition = cloupIt.offset(anchor);
            frame.style.left = tmp_oPosition[0] + tmp_iExtraLeftSpace + "px";
            frame.style.top = tmp_oPosition[1] + anchor.offsetHeight + "px";
        }
    },

    //shows an anchor frame
    showAnchorFrame: function(anchor) {

        var tmp_sReference = cloupIt.getWebsiteReference(anchor);
        var tmp_sReverseUrl = cloupIt.getWebsiteReverseUrl(anchor);

        if (tmp_sReference || tmp_sReverseUrl) {

            var tmp_oFrame = cloupIt.secureFrame(anchor);

            cloupIt.positionAnchorFrame(anchor, tmp_oFrame);

            //hide other frames and show this one
            for (var i = 0; i < cloupIt.frames.length; i++) {
                cloupIt.frames[i].style.display = cloupIt.frames[i] == tmp_oFrame ? "block" : "none";
            }

            if ("" + tmp_oFrame.src == "") {
                var tmp_sTarget = anchor.getAttribute("target");
                if (!tmp_sTarget) tmp_sTarget = "_self";


                var tmp_sTargetParameter = (cloupIt.satelliteUrl.indexOf("qios.silvergrid") > -1 ? "&target=" + tmp_sTarget : "/" + tmp_sTarget)

                if (tmp_sReference && tmp_sReference.length > 0) {
                    tmp_oFrame.src = cloupIt.baseUrl + cloupIt.satelliteUrl + tmp_sReference + tmp_sTargetParameter;
                }
                else if (tmp_sReverseUrl && (tmp_sReverseUrl.length > 0)) {
                    tmp_oFrame.src = cloupIt.baseUrl + cloupIt.satelliteReverseUrl + tmp_sReverseUrl + tmp_sTargetParameter;
                }
            }
        }
    },

    //gets the websitereference by url
    getWebsiteReference: function(anchor) {
        var tmp_oRegexResult = cloupIt.urlRegEx.exec(anchor.href);
        if (tmp_oRegexResult) {
            return tmp_oRegexResult[1];
        }
        else {
            return anchor.getAttribute("cloupitid");
        }

        return (tmp_oRegexResult) ? tmp_oRegexResult[1] : null;
    },

    //gets a potential url that is used for reversed lookup
    getWebsiteReverseUrl: function(anchor) {

        if (anchor.className && (anchor.className.toLowerCase().indexOf("cloupitanchor") >= 0)) {
            return encodeURIComponent(anchor.href);
        }
        else {
            return null;
        }
    },

    //hides an anchorframe by anchor or frame
    hideAnchorFrame: function(anchor, frame) {
        var tmp_oFrame = frame || cloupIt.secureFrame(anchor);
        if (tmp_oFrame != null)
            tmp_oFrame.style.display = "none";
    },

    //gets called when the dom is ready
    domLoaded: function() {
        if (document.addEventListener) {
            document.removeEventListener("DOMContentLoaded", cloupIt.domLoaded, false);
            cloupIt.ready();
        } else if (document.attachEvent) {
            if (document.readyState === "complete") {
                document.detachEvent("onreadystatechange", cloupIt.domLoaded);
                cloupIt.ready();
            }
        }
    }
};

//perhaps the document is already complete
if (document.readyState === "complete" ) {
    cloupIt.ready();
//add eventhandlers for FF, Webkit and opera
} else if ( document.addEventListener ) {
	document.addEventListener( "DOMContentLoaded", cloupIt.domLoaded, false );
	window.addEventListener( "load", cloupIt.ready, false );
//add eventhandlers for IE
} else if ( document.attachEvent ) {
	document.attachEvent("onreadystatechange", cloupIt.domLoaded);
	window.attachEvent("onload", cloupIt.ready);
}
