/**
 * $Id: definitionpopup.js 64367 2009-02-20 01:56:36Z kchiu $
 * $Author: kchiu $
 * $Revision: 64367 $
 * $Name$
 * $Date: 2009-02-19 17:56:36 -0800 (Thu, 19 Feb 2009) $
 *
 * @jsRequire DomUtils
 * @jsRequire classes.BaseObject
 * @jsRequire classes.EventManager
 * @jsRequire interfaces.DropShadowInterface
 * @jsRequire interfaces.CalloutInterface
 * @jsRequire interfaces.DelayedPopupInterface
 * @jsRequire interfaces.AnchoredInterface
 * @jsRequire interfaces.RoundedCornersInterface
 *
 *
 *
 *
 * @version    $Revision: 64367 $
 * @author     Philip Snyder <philip@pricegrabber.com>
 * @copyright  Copyright &copy; 2006 2007, Philip Snyder, PriceGrabber.com
 * @see        classes.BaseObject
 * @see        interfaces.DropShadowInterface
 * @see        interfaces.CalloutInterface
 * @see        interfaces.DelayedPopupInterface
 * @see        interfaces.AnchoredInterface
 * @see        interfaces.RoundedCornersInterface
 */

/**
 * DefinitionPopup Constructor / Definition
 *
 * This is NOT intended to be instantiated directly. Instead, use the
 * singleton accessor methods DefinitionPopup.getInstance(),
 * DefinitionPopup.show(), DefinitionPopup.hide() and DefinitionPopup.toggle().
 *
 * @access public
 * @since  v1.1
 * @param  DOMElement       anchor
 * @return DefinitionPopup
 */
function DefinitionPopup(anchor) {
    this.elemId            = null;
    // Callout interface implementation
    this.calloutId         = null;
    this.calloutPadding    = 0;
    // Drop shadow interface implementation
    this.dropShadowId      = null;
    this.color             = null;
    this.xOffset           = null;
    this.yOffset           = null;
    this.blur              = { iRadius: null, iSigma: null };
    this.opacity           = null;
    this.xShrink           = null;
    this.yShrink           = null;
    this.shadowStyle       = null;
    this.images            = new Array;
    this.setBlur           = DropShadowInterface_SetBlur;
    // Delayed popup interface implementation
    this.timer             = null;
    this.visible           = false;
    this.delay             = null;
    this.linked            = new Array;
    this.cancelTimer       = DelayedPopupInterface_CancelTimer;
    this.hide              = DelayedPopupInterface_Hide;
    this.toggle            = PopupInterface_Toggle;
    // Anchored interface implementation
    this.anchorId          = anchor || null;
    this.disableScroll     = true;
    this.getAnchorX        = AnchoredInterface_GetAnchorX;
    this.getAnchorY        = AnchoredInterface_GetAnchorY;
    this.getAnchorZ        = AnchoredInterface_GetAnchorZ;
    this.getAnchorWidth    = AnchoredInterface_GetAnchorWidth;
    this.getAnchorHeight   = AnchoredInterface_GetAnchorHeight;
    this.getAnchorPosition = AnchoredInterface_GetAnchorPosition;
    this.getElemWidth      = AnchoredInterface_GetElemWidth;
    this.getElemHeight     = AnchoredInterface_GetElemHeight;
    this.setAnchor         = AnchoredInterface_SetAnchor;
    // Rounded corners interface implementation
    this.cornerStyle       = null;
    this.cornersDrawn      = false;
    // Drop shadow interface && Callout interface joint implementation
    this.erase             = DefinitionPopup_Erase;
    this.draw              = DefinitionPopup_Draw;
    this.init              = DefinitionPopup_Init;
    // Drop shadow interface && Delayed popup interface joint implementation
    this.show              = DefinitionPopup_Show;
    // Drop shadow interface && Anchored interface joint implementation
    this.alignElement      = DefinitionPopup_AlignElement;

    this.implement(DropShadowInterface);
    this.implement(CalloutInterface);
    this.implement(DelayedPopupInterface);
    this.implement(AnchoredInterface);
    this.implement(RoundedCornersInterface);
    
    this.setElement        = DefinitionPopup_SetElement;
    this.setDefinition     = DefinitionPopup_SetDefinition;
    this.setTerm           = DefinitionPopup_SetTerm;
    this.setTermColor      = DefinitionPopup_SetTermColor;

    this.id                = 'DefinitionPopup';
    this.style             = 'Default';
    this.delay             = 500;
    this.elemId            = this.id;
    this.defId             = this.elemId+'_def';
    this.termId            = this.elemId+'_term';
   
    this.init();
} // End DefinitionPopup

// Setup DefinitionPopup prototype chain
DefinitionPopup.prototype             = new BaseObject;
DefinitionPopup.prototype.constructor = DefinitionPopup;
DefinitionPopup.superclass            = BaseObject.prototype;









/****** BEGIN EDIT SECTION ******/

/**
 * Style definitions for DefinitionPopup widget.
 *
 * These style settings can be overridden by a simple variable set call.
 * Note that if you set the backgroundColor to anything other than #ffffff
 * you will most likely want to create some rounded corner images and define
 * them too.
 * 
 * Example:
 *   <?php
 *   if (!$pricegrabber_site)
 *       echo "    DefinitionPopup.styles.Default.term.color = '".$color."';\n";
 *   ?>
 */
DefinitionPopup.styles = {
    Default: {
        term: {
            font: {
                family:  'Arial, Helvetica, sans-serif',
                size:    '13px',
                weight:  'bold'
            },
            color:       '#589c1c'
        },
        font: {
            family:      'Arial, Helvetica, sans-serif',
            size:        '13px',
            weight:      'normal'
        },
        backgroundColor: '#ffffff',
        color:           '#656565'
    }
} // End DefinitionPopup.styles

/****** END EDIT SECTION ******/


















/**
 * Sets the DOMElement that the DefinitionPopup works with.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_SetElement(elem) {
    //if (typeof(writeDebug) == 'function') writeDebug('DefinitionPopup_SetContent() called.');
    this.elemId = elem.id;
    //if (typeof(writeDebug) == 'function') writeDebug('DefinitionPopup_SetContent() finished.');
}

/**
 * Initializes the DefinitionPopup in preparation for drawing.
 *
 * Call this method before any draw methods as it handles initialization of
 * any implemented interfaces as well.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_Init() {
    //if (typeof(writeDebug) == 'function') writeDebug('DefinitionPopup_Init() called.');
    var elem = document.getElementById(this.elemId);
    if (!elem) {
        elem = document.createElement('div');
        document.getElementsByTagName('body')[0].appendChild(elem);
        elem.id = this.elemId;
    }

    var term = document.getElementById(this.termId);
    if (!term) {
        term = document.createElement('div');
        elem.appendChild(term);
        term.id = this.termId;
    }

    var def = document.getElementById(this.defId);
    if (!def) {
        def = document.createElement('div');
        elem.appendChild(def);
        def.id = this.defId;
    }

    elem.style.backgroundColor = DefinitionPopup.styles[this.style].backgroundColor;
    term.style.color           = DefinitionPopup.styles[this.style].term.color;
    term.style.paddingBottom   = '5px';
    term.style.fontFamily      = DefinitionPopup.styles[this.style].term.font.family;
    term.style.fontSize        = DefinitionPopup.styles[this.style].term.font.size;
    term.style.fontWeight      = DefinitionPopup.styles[this.style].term.font.weight;
    def.style.color            = DefinitionPopup.styles[this.style].color;
    def.style.fontFamily       = DefinitionPopup.styles[this.style].font.family;
    def.style.fontSize         = DefinitionPopup.styles[this.style].font.size;
    def.style.fontWeight       = DefinitionPopup.styles[this.style].font.weight;
    
    this.calloutPadding = 20;
    this.cornerStyle = 'Default';
    RoundedCornersInterface_Init.call(this);
    this.shadowStyle = 'Default';
    DropShadowInterface_Init.call(this);
    //if (typeof(writeDebug) == 'function') writeDebug('DefinitionPopup_Init() finished.');
} // End DefinitionPopup_Init

/**
 * Erases the definition popup by removing the dom elements created in DefinitionPopup_Draw.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_Erase() {
    CalloutInterface_Erase.call(this);
    DropShadowInterface_Erase.call(this);
    RoundedCornersInterface_Erase.call(this);
    this.linked = new Array;
} // End DefinitionPopup_Erase

/**
 * Draws the definition popup by creating the necessary dom elements and attaching them to the document accordingly.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_Draw() {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_Draw() called.', '#ffffff', '#0000ff');
    var elem = document.getElementById(this.elemId);
    if (!elem) throw new Error('Unable to find element: '+this.elemId);

    var term = document.getElementById(this.termId);
    if (!term) throw new Error('Unable to find element: '+this.termId);

    var def = document.getElementById(this.defId);
    if (!def) throw new Error('Unable to find element: '+this.defId);

    this.linked = new Array;
    bHeight = 2;
    elem.style.border = '1px solid '+DefinitionPopup.styles[this.style].backgroundColor;
    elem.style.backgroundColor = DefinitionPopup.styles[this.style].backgroundColor;
    elem.style.color = DefinitionPopup.styles[this.style].color;
    RoundedCornersInterface_Draw.call(this);
    CalloutInterface_Draw.call(this);
    DropShadowInterface_Draw.call(this);
    window.addEvent(elem, 'mouseover', this.cancelTimer, this, true);
    window.addEvent(elem, 'mouseout',  this.hide,        this, true);
    elem.style.border = 'none';
    elem.style.backgroundColor = 'transparent';

    this.linked.push(this.dropShadowId);
    this.linked.push(this.calloutId);
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup_Draw() finished.', '#ffffff', '#0000ff');
} // End DefinitionPopup_Draw

/**
 * Shows the definition popup on the screen.
 *
 * @access public
 * @since  v1.1
 * @return boolean
 */
function DefinitionPopup_Show() {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_Show() called.', '#ffffff', '#0000ff');
    this.cancelTimer();
    var wasVisible = this.visible;
    if (this.visible) {
        PopupInterface_Hide.call(this);
        this.erase();
    }
    this.draw();

    var anchor     = document.getElementById(this.anchorId);
    if (!anchor)     throw new Error('Unable to find anchor element: '+this.anchorId);

    var elem       = document.getElementById(this.elemId);
    if (!elem)       throw new Error('Unable to find element: '+this.elemId);

    var dropShadow = document.getElementById(this.dropShadowId);
    if (!elem)       throw new Error('Unable to find drop shadow element: '+this.dropShadowId);

    var callout    = document.getElementById(this.calloutId);
    if (!callout)    throw new Error('Unable to find callout element: '+this.calloutId);


    // Get the z-index of our anchor element
    var zIndex = parseInt(DomUtils.getZIndex(anchor));
    // If it doesn't have one make it 1000
    if (zIndex == 0) {
        zIndex = 1000;
        anchor.style.zIndex = zIndex;
    }
    dropShadow.style.zIndex = zIndex+1;
    callout.style.zIndex    = zIndex+2;
    elem.style.zIndex       = zIndex+3;
    //window.messageQueue.add( new Message('ItineraryPopup_Show', 'anchor zIndex: '+zIndex) );
    //window.messageQueue.add( new Message('ItineraryPopup_Show', 'drop shadow zIndex: '+dropShadow.style.zIndex) );
    //window.messageQueue.add( new Message('ItineraryPopup_Show', 'callout zIndex: '+callout.style.zIndex) );
    //window.messageQueue.add( new Message('ItineraryPopup_Show', 'elem zIndex: '+elem.style.zIndex) );
    //this.alignElement(this.getAnchorPosition());
    this.alignElement();
    if (wasVisible) PopupInterface_Show.call(this);
    else            DelayedPopupInterface_Show.call(this);
    return true;
} // End DefinitionPopup_Show

/**
 * Aligns the definition popup by calling implemented interfaces' AlignElement functions.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_AlignElement() {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_AlignElement() called.', '#ffffff', '#0000ff');
    AnchoredInterface_AlignElement.call(this)
    CalloutInterface_AlignElement.call(this);
    DropShadowInterface_AlignElement.call(this);
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup_AlignElement() finished.', '#ffffff', '#0000ff');
} // End DefinitionPopup_AlignElement

/**
 * Sets the definition in the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_SetDefinition(definition) {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_SetDefinition() called.', '#ff0000', '#ffffff');
    var defElem = document.getElementById(this.defId);
    if (!defElem) throw new Error('Unable to find definition element: '+this.defId);
    while (defElem.hasChildNodes()) DomUtils.removeElement(defElem.firstChild);
    var txtDef = document.createTextNode(definition);
    defElem.appendChild(txtDef);
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup_SetDefinition() finished.', '#ff0000', '#ffffff');
}

/**
 * Sets the term in the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_SetTerm(term) {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_SetTerm() called.', '#ff0000', '#ffffff');
    var termElem = document.getElementById(this.termId);
    if (!termElem) throw new Error('Unable to find term element: '+this.termId);
    while (termElem.hasChildNodes()) DomUtils.removeElement(termElem.firstChild);
    var txtTerm = document.createTextNode(term);
    termElem.appendChild(txtTerm);
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup_SetTerm() finished.', '#ff0000', '#ffffff');
}

/**
 * Sets the term color of the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_SetTermColor(color) {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_SetTermColor() called.', '#ff0000', '#ffffff');
    var term = document.getElementById(this.termId);
    if (!term) throw new Error('Unable to find term element: '+this.termId);
    term.style.color = color;
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup_SetTermColor() finished.', '#ff0000', '#ffffff');
}








/****** SINGLETON ACCESSORS SECTION ******/

/**
 * Singleton instance variable.
 *
 * @access public
 * @since  v1.1
 * @var    instance   DefinitionPopup
 */
DefinitionPopup.instance = null;

/**
 * Singleton accessor for retrieving the definition popup instance.
 *
 * @access public
 * @since  v1.1
 * @return DefinitionPopup
 */
DefinitionPopup.getInstance = function() {
    if (!DefinitionPopup.instance) DefinitionPopup.instance = new DefinitionPopup();
    return DefinitionPopup.instance;
} // End DefinitionPopup.getInstance

/**
 * Singleton accessor for initializing the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
//DefinitionPopup.initInstance = function() {
//    if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup.init() called.', '#ff0000', '#ffff00');
//    DefinitionPopup.instance = new DefinitionPopup();
//    if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup.init() finished.', '#ff0000', '#ffff00');
//} // End DefinitionPopup.init

/**
 * Singleton accessor for showing the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
DefinitionPopup.show = function(anchor, term, def) {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup.show() called.', '#ff0000', '#ffff00');
    DefinitionPopup.getInstance().setAnchor(anchor);
    DefinitionPopup.getInstance().setDefinition(def);
    DefinitionPopup.getInstance().setTerm(term);
    DefinitionPopup_Show.call(DefinitionPopup.getInstance());
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup.show() finished.', '#ff0000', '#ffff00');
} // End DefinitionPopup.show

/**
 * Singleton accessor for hiding the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
DefinitionPopup.hide = function() {
    DelayedPopupInterface_Hide.call(DefinitionPopup.getInstance());
} // End DefinitionPopup.hide

/**
 * Singleton accessor for toggling the definition popup.
 *
 * @access public
 * @since  v1.1
 * @param  DOMElement  anchor
 * @param  string      def
 * @return void
 */
DefinitionPopup.toggle = function(anchor, term, def) {
    if (DefinitionPopup.getInstance().visible) DefinitionPopup.hide();
    else                                       DefinitionPopup.show(anchor, term, def);
}

