/**
 * Generic popups for CWIS that have external dependencies, namely jQuery and
 * CSS classes.
 *
 * Part of the Collection Workflow Integration System (CWIS)
 * Copyright 2012 Internet Scout Project
 * http://scout.wisc.edu
 */

cw.provide("CW-Popup", function(){

var Helpers = cw.require("CW-Helpers");

if (typeof jQuery == "undefined") {
    cw.error("jQuery is required for the Popup module");
}

function DefaultPopup(node, pointer, clobber) {
    DefaultPopup.base.call(this, node);

    this.Pointer = pointer;
    this.Clobber = clobber;

    // make sure the node isn't shackled to an element
    this.Node.remove();
    this.Node.appendTo("body");

    // make sure when it's off the screen and invisible
    DefaultPopup.base.prototype.hide.call(this);
    this.Node.css({"opacity": 0});

    var popup = this;

    // keep the popup shown when the mouse hovers over it
    this.Node.bind("mouseenter", function(){
        popup.Clobber(function(){}, {"delay": 0});
    });

    // allow the popup to be hidden when the mouse moves from it
    this.Node.bind("mouseleave", function(){
        popup.Clobber(function(){ popup.hide(); }, {"delay": 30});
    });
} cw.extend(DefaultPopup, Helpers.AnchoredPopup);

DefaultPopup.prototype.show = function() {
    DefaultPopup.base.prototype.show.call(this);

    this.Node.animate({"opacity": "1"});
};

DefaultPopup.prototype.hide = function() {
    var popup = this,
        node = this.Node;

    node.animate({"opacity": "0"}, function(){
        DefaultPopup.base.prototype.hide.call(popup);
    });
};

DefaultPopup.prototype.Pointer = null;
DefaultPopup.prototype.Clobber = null;

/**
 * Construct a popup for tooltips.
 * @param node:reference jQuery object reference
 */
function Tooltip(node) {
    var tooltip = this;

    Helpers.AnchoredPopup.base.call(this, node);

    // hide the tooltip the instant the mouse button is touched
    this.Node.mousedown(function(){
        tooltip.hide(true);
    });
} cw.extend(Tooltip, Helpers.AnchoredPopup);

/**
 * Anchor the tooltip to the given element, but not until shown. Options are:
 * anchorSide: which side of the anchor the popup should be displayed
 * anchorHandle: where, in pixels or percent, should the anchor handle be
 * popupHandle: where, in pixels or perecent, should the popup handle be
 * distance: how many pixels away the popup should be from the anchor
 * showOnClick: true to show the tooltip when the anchor is clicked
 * showOnHover: true to show the tooltip when the anchor is hovered over
 * @param anchor:reference jQuery object reference
 * @param options:object options to specify the position and length of the tether
 */
Tooltip.prototype.anchor = function(anchor, options) {
    var tooltip = this;

    options = $.extend({
        "anchorSide": "right",
        "anchorHandle": "100%",
        "popupHandle": "0%",
        "showOnClick": true,
        "showOnHover": true}, options);

    if (options.showOnClick) {
        anchor.click(function(){
            clearTimeout(tooltip.Timeout);
            tooltip.anchorAux($(this), options);
        });
    } else {
        anchor.click(function(){
            clearTimeout(tooltip.Timeout);
            tooltip.hide(true);
        });
    }

    if (options.showOnHover) {
        anchor.mouseover(function(){
            var $this = $(this),
                delay = tooltip.isVisible() ? 375 : 1500;

            clearTimeout(tooltip.Timeout);

            // remove the title attribute to disable browser-based tooltips
            tooltip.removeTitle($this);

            tooltip.Timeout = setTimeout(function(){
                tooltip.anchorAux($this, options);
            }, delay);
        });

        anchor.mouseout(function(){
            clearTimeout(tooltip.Timeout);

            // restore the title attribute to the element
            tooltip.restoreTitle($(this));

            tooltip.Timeout = setTimeout(function(){
                tooltip.hide();
            }, 200);
        });
    }
};

/**
 * Show the tooltip.
 */
Tooltip.prototype.show = function() {
    // stop any animations that might interfere
    this.Node.stop();

    // show the tooltip
    this.Node.css({"opacity": "1"});
    Tooltip.base.prototype.show.call(this);
};

/**
 * Hide the tooltip.
 */
Tooltip.prototype.hide = function(immediate) {
    var tooltip = this;

    // stop any animations that might interfere
    this.Node.stop();

    if (immediate) {
        // hide immediately
        this.Node.css({"opacity": "0"});
        Tooltip.base.prototype.hide.call(tooltip);
    } else {
        // hide with an animation
        this.Node.animate({"opacity": "0"}, 650, function(){
            Tooltip.base.prototype.hide.call(tooltip);
        });
    }
};

/**
 * @protected
 * Since the anchor function sets two event handlers that need to accomplish
 * essentially the same thing, use this auxiliary function to perform that "same
 * thing". Options are:
 * anchorSide: which side of the anchor the popup should be displayed
 * anchorHandle: where, in pixels or percent, should the anchor handle be
 * popupHandle: where, in pixels or perecent, should the popup handle be
 * distance: how many pixels away the popup should be from the anchor
 * @param anchor:reference jQuery object reference
 * @param options:object options to specify the position and length of the tether
 */
Tooltip.prototype.anchorAux = function(anchor, options) {
    var text = anchor.data("tooltip") || anchor.attr("tooltip");

    // convert new lines to breaks, per the HTML5 spec
    text = text.replace(/\u000a/g, "<br />");

    // update the tooltip text
    this.Node.html(text);

    // anchor the tooltip to the anchor
    Tooltip.base.prototype.anchor.call(this, anchor, options);

    // show the tooltip
    this.show();
};

/**
 * Remove the title attribute from the anchor and cache it.
 * @param anchor:reference jQuery object reference
 */
Tooltip.prototype.removeTitle = function(anchor) {
    this.TitleCache = anchor.attr("title");
    anchor.removeAttr("title");
};

/**
 * Restore the title attribute of the anchor and clear the cache.
 * @param anchor:reference jQuery object reference
 */
Tooltip.prototype.restoreTitle = function(anchor) {
    anchor.attr("title", this.TitleCache);
    this.TitleCache = null;
};

/**
 * @protected Timeout:reference holds object returned by setTimeout
 * @protected TitleCache:string caches the title attribute of the anchor
 */
Tooltip.prototype.Timeout = null;
Tooltip.prototype.TitleCache = null;

this.DefaultPopup = DefaultPopup;
this.Tooltip = Tooltip;

});
