// http://www.wildbit.com/labs/cooltips/
// Tooltip Object
//
// Editor: Kravchuk Oleg, <kolegm.real@gmail.com>, 3.04.2009
//
// This class works with special classNames.
//
// The tooltip content could be in your HTML page as a title of the element, an hidden element or
// can be retreive by an AJAX call.
//
// To work, You just need to set the 'title' attribute into the element. This attribute will indicate where to take the content
// Also, you must indicate in the tooltip parameter (appointmentTitle) what 'title' attribute means.
//   Possible choises:
//     - appointmentTitle is empty - take the content from the 'title'
//     - appointmentTitle == 'id'  - take the content from the html object by id. In the title must be indicate the id of the html object
//     - appointmentTitle == 'url' - take the content from url by Ajax. In the title must be indicate the url.
//
// There are five types of tooltip which appointment by the className of element
// Possible choises for className:
//    - textTooltip
//    - htmlTooltip
//    - htmlClickTooltip
//    - ajaxTooltip
//    - ajaxClickTooltip
//
// For using text-tooltip in your HTML page could be next object:
//    <div title="some content" class="textTooltip" ></div>
//
// For using html-tooltip in your HTML page could be next object:
//    <div title="idOfElemet" class="htmlTooltip" ></div>
//    <div id="idOfElemet" style="display:none">
//      //your content
//    </div>
//
// For using html-click-tooltip in your HTML page could be next object:
//    <div title="idOfElemet" class="htmlClickTooltip" ></div>
//    <div id="idOfElemet" style="display:none">
//      //your content
//    </div>
//
// For using ajax-tooltip in your HTML page could be next object:
//    <div title="...some url must be here" class="ajaxTooltip" ></div>
//
// For using ajax-click-tooltip in your HTML page could be next object:
//    <div title="...some url must be here" class="ajaxClickTooltip" ></div>


// If you want to has title in the tooltip header,
// you must set the next tag <div style="display:none">...title for tooltip</div> inside the DOM object
// FOR EXAMPLE: for showed header title in the html-tooltip
//      <div title="idOfElemet" class="htmlTooltip" >
//        <div style="display:none">...title for tooltip</div>         <-- this
//      </div>
//      <div id="idOfElemet" style="display:none">
//       //your content
//      </div>


// For initialize tooltip you could call the next function: attachTooltips( tooltipParameter )
// attachTooltips.js
//    This function attach one type of tooltips or all together
//    Possible choises for tooltipParameter:
//    - not specified     - to attach all tooltip types
//    - 'textTooltip'       - to attach only the text type of tooltips
//    - 'htmlTooltip'       - to attach only the html type of tooltips
//    - 'htmlClickTooltip'  - to attach only the html type of tooltips whick would close by click on the cancel button
//    - 'htmlAjaxTooltip'   - to attach only the ajax type of tooltips
//    - 'htmlClickTooltip'  - to attach only the ajax type of tooltips whick would close by click on the cancel button

var Tooltip = Class.create();
Tooltip.prototype = {
  initialize: function(el, options) {
    this.el = $(el);
    this.initialized = false;
    this.setOptions(options);

    ///////////////////////////////////////////////////////////////////
    // initilize events handler
    ///////////////////////////////////////////////////////////////////

    //show event
    this.showEvent = this.show.bindAsEventListener(this);

    //ajax calling
    this.ajaxCalling = this.ajaxLoadingData.bindAsEventListener(this);

    //hide event
    this.hideEvent = this.hide.bindAsEventListener(this);

    //update event
    this.updateEvent = this.update.bindAsEventListener(this);



    //////////////////////////////////////////////////////////////////
    // observe events
    //////////////////////////////////////////////////////////////////
    if (this.options.handlerShow == 'click') {
      if (this.options.appointmentTitle == 'url')
        Event.observe(this.el, "click", this.ajaxCalling );
      else Event.observe(this.el, "click", this.showEvent );
    }
    else {
      if (this.options.appointmentTitle == 'url')
        Event.observe(this.el, "mouseover", this.ajaxCalling );
      else Event.observe(this.el, "mouseover", this.showEvent );
    }

    if (this.options.handlerHide != 'clickCancel')
      Event.observe(this.el, "mouseout", this.hideEvent );


    //////////////////////////////////////////////////////////////////
    //define content for tooltip
    //////////////////////////////////////////////////////////////////
    if (this.options.appointmentTitle == 'id') {
      if ($(this.el.title)) this.content = $(this.el.title);
    }
    else if (this.options.appointmentTitle == 'url') {
      //do nothing
    }
    else { //default
      this.content = this.el.title;
    }

    //if DOM element has a children than get header title
    if (this.el.down()) this.options.titleHeader = this.el.down();

    // Removing 'title' attribute from DOM element to avoid showing it
    this.el.removeAttribute('title');

    // If descendant elements has 'alt' attribute defined, clear it
    var elDescends = Element.descendants(this.el);
    if (undefined != elDescends)
    {
      elDescends.each(function(el){
        if(Element.readAttribute(el, 'alt'))  el.alt = "";
      });
    }
  },
  setOptions: function(options) {
    this.options = {
      backgroundColor: '#d0e3fc', // Default background color
      borderColor: '#98c0f4', // Default border color
      textColor: '', // Default text color (use CSS value)
      textShadowColor: '', // Default text shadow color (use CSS value)
      maxWidth: 600,  // Default tooltip width
      align: "left", // Default align
      delay: 50, // Default delay before tooltip appears in ms
      mouseFollow: false, // Tooltips follows the mouse moving
      opacity: 1.0, // Default tooltips opacity
      appearDuration: 0.1, // Default appear duration in sec
      hideDuration: 0, // Default disappear duration in sec

      draggable: false, // Should tooltip be draggable or not

      showHeader: false, //show header tooltip
      titleHeader: '', //tooltip title
      appointmentTitle: '', //what title means. Possible choices: 'url', 'id' or empty string. Empty string is default and it means: take content from title. Id - get content from html-object. Url - get content from url by Ajax
      handlerShow: '', //type of show handler. Possible choices: 'click' or empty string. Empty string is default and it means 'mouseover' handler.
      handlerHide: '', //type of hide handler. Possible choices: 'clickCancel' or empty string. Empty string is default and it means 'mouseout' handler.
      url: '' //define location for ajax loading data. Used when option appointmentTitle == 'url'.
    };
    Object.extend(this.options, options || {});
  },
  ajaxLoadingData: function(e){
    if (this.options.appointmentTitle == 'url' && this.options.url != '') {
      this.xCord = Event.pointerX(e);
      this.yCord = Event.pointerY(e);

      new Ajax.Request(this.options.url, {
        method: 'GET',
        onSuccess: this.processAjaxResponse.bind(this),
        evalScripts: true
      });
    }
    else alert('Url was not set');
  },
  processAjaxResponse: function (response) {
    this.ajaxContent = response.responseText;
    this.timeout = window.setTimeout(this.appear.bind(this), this.options.delay);
  },
  show: function(e) {
    this.xCord = Event.pointerX(e);
    this.yCord = Event.pointerY(e);

    //if(!this.initialized)
    this.timeout = window.setTimeout(this.appear.bind(this), this.options.delay);
  },
  hide: function(e) {
    if(this.initialized) {
      this.appearingFX.cancel();
      if (Prototype.Browser.IE)
        this.appearingMaskIframe.cancel();
      if(this.options.mouseFollow)
        Event.stopObserving(this.el, "mousemove", this.updateEvent);
      this.destroy();
    }
    this._clearTimeout(this.timeout);

    this.initialized = false;
  },
  update: function(e){
    this.xCord = Event.pointerX(e);
    this.yCord = Event.pointerY(e);
    this.setup();
  },
  destroy: function(){
    new Effect.Fade(this.tooltip, {duration: this.options.hideDuration, afterFinish: function() {
      Element.remove(this.tooltip);
      this.removeIFrameUnderTooltip();
    }.bind(this) });
  },
  appear: function() {
    // Building tooltip container
    if(Object.isElement(this.options.titleHeader))
      this.options.titleHeader.show();

    // Hide all tooltips first
    $$(".tooltip-iframe").each( function(item) { item.hide(); });
    $$(".tooltip").each( function(item){ item.hide(); });

    if (this.options.appointmentTitle == 'id') this.content.show();

    // create content for tooltip
    this.tooltip = Builder.node("div", { className: "tooltip", style: "display: none; border: 1px solid " + this.options.borderColor + ";" }, [
      Builder.node("div", {
          className: "tooltip-content", style: "border: none; background-color:" + this.options.backgroundColor + ";"  +
          ((this.options.textColor != '') ? "; color:" + this.options.textColor : "") +
          ((this.options.textShadowColor != '') ? "; text-shadow:2px 2px 0" + this.options.textShadowColor + ";" : "")
        },
        this.content
      )
    ]);

    $(document.body).insert({top: this.tooltip}); //insert tooltip to template

    if (this.ajaxContent !== undefined)
    {
      $(this.tooltip).down('div').update(this.ajaxContent);
    }
    
    Element.extend(this.tooltip); // IE needs element to be manually extended

    this.options.width = this.tooltip.getWidth();
    this.tooltip.style.width = this.options.width + 'px'; // IE7 needs width to be defined

    if (this.options.showHeader) { //add header to tooltip
      var btnClose,
        titleTooltip,
        tooltipHeader,
        intWidthTooltipHeader,
        intWidthTooltip;

      if (this.options.handlerHide && this.options.handlerHide == 'clickCancel') {
        // create btn 'close' for closing tooltip
        btnClose = Builder.node('div', { className : 'tooltip-btn-close' });
        //add Hide event to btn
        Event.observe(btnClose, "click", this.hideEvent );
      }

      if (this.options.titleHeader && Object.isElement(this.options.titleHeader)) {
        // create title for tooltip
        titleTooltip = Builder.node('div', {className: 'tooltip-title'}, this.options.titleHeader);
      }

      if (Object.isElement(btnClose) || Object.isElement(titleTooltip)){
        //create header for tooltip
        tooltipHeader = Builder.node('div', {
            className: 'tooltip-header',
            style: 'width: 180px'
          },
          [ titleTooltip, btnClose, Builder.node('div', {style: 'clear:both;'}) ]
        );

        //must be here, cause header influence onto the tooltip body width in IE.
        $(this.tooltip).insert({top: tooltipHeader});

        intWidthTooltipHeader = parseInt(this.tooltip.down('.tooltip-header').style.width);
        intWidthTooltip = parseInt(this.tooltip.style.width);

        if ( intWidthTooltipHeader > intWidthTooltip )
        {
          this.tooltip.style.width = intWidthTooltipHeader + 'px';
          this.options.width = intWidthTooltipHeader;
        }
        else if ( intWidthTooltipHeader < intWidthTooltip )
        {
          this.tooltip.down('.tooltip-header').style.width = '100%';
        }

        // if tooltip header exists than the draggable is possible
        // [2009-12-18, RoDush]:
        // This is not correct! Sometimes we need to copy some information from tooltip
        // and can not, because it is dragging with mouse! :(
        if (true == this.options.draggable)
        {
          new Draggable($(this.tooltip), {
            onStart: function(){
              if (this.maskIframe != null) {
                $(this.maskIframe).hide();
              }
            }.bind(this),
            onEnd: function(){
              this.dragIframe();
            }.bind(this)
          });
        }
        else
        {
          tooltipHeader.setStyle('cursor:default');
        }
      }
    }

    this.setup();

    if(this.options.mouseFollow) Event.observe(this.el, "mousemove", this.updateEvent);

    this.initialized = true;
    this.appearingFX = new Effect.Appear(this.tooltip, {duration: this.options.appearDuration, to: this.options.opacity });

    if (Prototype.Browser.IE) {
      this.showIFrameUnderTooltip();
      this.appearingMaskIframe = new Effect.Appear(this.maskIframe, {duration: (this.options.appearDuration + 0.2), to: this.options.opacity });
    }

  },
  setup: function(){
    // If content width is more then allowed max width, set width to max
    if(this.options.width > this.options.maxWidth) {
      this.options.width = this.options.maxWidth;
      this.tooltip.style.width = this.options.width + 'px';
    }

    // Tooltip doesn't fit the current document dimensions
    if(this.xCord + this.options.width >= Element.getWidth(document.body)) {
      this.options.align = "right";
      this.xCord = this.xCord - this.options.width + 20;
    }

    this.tooltip.style.left = this.xCord - 7 + "px";
    this.tooltip.style.top = this.yCord + 12 + "px";
  },
  showIFrameUnderTooltip: function() { // for ie (important for ie6), its need for hidding selectboxes which under tooltip
    var styleIframe;

    styleIframe  = "display: none;";
    styleIframe += "position: absolute;";
    styleIframe += "width: " + this.tooltip.getWidth() + "px;";
    styleIframe += "height: " + this.tooltip.getHeight() + "px;";
    styleIframe += "left: " + this.tooltip.style.left + ";";
    styleIframe += "top: " + this.tooltip.style.top + ";";
    styleIframe += "z-index: " + (this.tooltip.getStyle('z-index') - 1) + ";";

    this.maskIframe = Builder.node('iframe', {
  	  style: styleIframe,
  	  className: 'tooltip-iframe',
  	  frameborder: 1,
  	  scrolling: "no"
  	});

  	$(this.tooltip).insert({before: this.maskIframe});
  },
  removeIFrameUnderTooltip: function() { // for ie (important for ie6)
    if (this.maskIframe != null) {
  	  Element.remove(this.maskIframe);
  	  this.maskIframe = null;
  	}
	},
	dragIframe: function() { //if iframe exists than follow on tooltip
	  if (this.maskIframe != null) {
	    this.maskIframe.style.left = this.tooltip.style.left;
	    this.maskIframe.style.top = this.tooltip.style.top;
	    $(this.maskIframe).show();
	  }
	},
  _clearTimeout: function(timer) {
    clearTimeout(timer);
    clearInterval(timer);
    return null;
  }
};
/*
 * vim:ts=2:sw=2:expandtab
 */

