// VIVO JavaScript Framework 1.1
// Copyright (c) 2005 Jeremy Raadt (jraadt@hotmail.com)
// Copyright (c) 2006 Andy Altepeter (aaltepet@altepeter.net)
//
// See vivo.js for full license.

/*-------------------------------------
  InPageTooltip Tool
  Options:
  id, tooltipElement (the id of the tooltip)
  offsetX, offsetY (not sure about this yet)
  display: (click|hover)
   - display tooltip onclick or onmousehover
  hoverDelay - how many milliseconds to delay before displaying
  hoverFollowMouse - tooltip follows mouse
  -------------------------------------**/
var InPageTooltip = Class.create();
InPageTooltip.prototype = {
  initialize: function(element, tooltipElement, options) {
    var self = this;
    this.element = $(element);
    this.toolElement = $(tooltipElement);
    this.active = 0;
    this.options = Object.extend({
      displayType: 'click',
	  alignX: 'left',
	  alignY: 'top',
	  offsetX: 5,
	  offsetY: 5,
	  hoverDelay: 500,
	  extraCallback: null
    }, options || {});
    this.options.offsetX = parseInt(this.options.offsetX);
    this.options.offsetY = parseInt(this.options.offsetY);

    this.displayOnClickListener = this.displayAction.bindAsEventListener(this);
    this.displayOnHoverListener = this.displayAction.bindAsEventListener(this);
    this.closeToolElementListener = this.closeToolElementAction.bindAsEventListener(this);
    if (this.options.displayType=='click') {
	Event.observe(this.element, 'click', this.displayOnClickListener);
        Event.observe(this.toolElement, 'click', this.closeToolElementListener);
    } else if (this.options.displayType=='hover') {
	Event.observe(this.element, 'mouseover', this.displayOnHoverListener);
        Event.observe(this.element, 'mouseout', this.closeToolElementListener);
        Event.observe(this.toolElement, 'mouseout', this.closeToolElementListener);
    } else {
	alert('unknown tooltip bind action');
    }
  },
  closeToolElementAction: function(event) {
      this.toolElement.style.display="none";
      this.active = 0;
  },
  displayAction: function(event) {
    if (this.options.extraCallback) {
      this.options.extraCallback();
    }
    if (!this.active) {
      body = document.getElementsByTagName('body')[0];
      this.toolElement.style.position="absolute";
      //this compute is where we add in the offsets
      var xalign = (event.pageX || (event.clientX + body.scrollLeft))
      if (this.options.alignX=='left') {
	this.toolElement.style.left = (xalign + this.options.offsetX) + 'px';
      } else {
	xalign = body.clientWidth - xalign - this.options.offsetX;
	this.toolElement.style.right = xalign + 'px';
      }
      
      var top = (event.pageY || (event.clientY + body.scrollTop))+this.options.offsetY;
      this.toolElement.style.top=top + 'px';
      
      this.toolElement.style.display = "block";
      this.active = 1;
    } else {
      /*XXX Note: toolElement needs to have an onclick to hide as well!*/
      this.toolElement.style.display="none";
      this.active = 0;
    }
  }
}

//-------------------------------------
// Collapsible Tool
//-------------------------------------
var Collapsible = Class.create();
Collapsible.prototype = {
  initialize: function(element, collapsibleElement, options) {
    var self = this;
    this.element = $(element);
    this.collapsibleElement = $(collapsibleElement);
    this.defaultCallback = function() {
      if (self.collapsibleElement.style.display == "none")
	self.collapsibleElement.style.display = 'block';
      else self.collapsibleElement.style.display = 'none';
    }
    this.options = Object.extend({
      action: "click",
	  callback: this.defaultCallback,
	  initialState: 'open'
    }, options || {});

    if (this.options.initialState == "close") {
      this.options.callback();
    }

    this.eventListener = this.collapsibleAction.bindAsEventListener(this);
    Event.observe(this.element, this.options.action, this.eventListener);
  },

  collapsibleAction: function(event) {
    this.options.callback();
    if (event) {
      Event.stop(event);
    }
    return false;
  }
}

//-------------------------------------
// Tab Tool
// TODO: Make tab enabling/disabling more generic then just removing class and adding "active" class
// TODO: Allow user to configure AJAX options (check out Ajax.InPlaceEditor)
//-------------------------------------
var Tab = Class.create();
Tab.prototype = {
  initialize: function(element, contentElement, tabGroupElement, url, options) {
    var self = this;
    this.fragment = document.createElement("div");
    this.element = $(element);
    this.contentElement = $(contentElement);
    this.tabGroupElement = $(tabGroupElement);
    this.url = url;
    this.options = Object.extend({
      action: "click",
      initialState: "close",
      reload: "yes",
      loadingText: "Loading...",
      onComplete: function(content) {
        if ($("vivo-loading-tab") != null) {
          self.contentElement.removeChild($("vivo-loading-tab"));
        }

        if (content != null && content.length > 0) {
          self.fragment.innerHTML = content;
        }
        self.fragment.style.display = "block";

        var tabs = self.tabGroupElement.getElementsByTagName("li");
        for (var i = 0; i < tabs.length; i++) {
          if (tabs[i].nodeType == 1 && tabs[i].className.length > 0) {
            tabs[i].className = "";
          }
        }
        self.element.className = "active";
      },
      onLoading: function() {
        var loadingDiv = document.createElement("div");
        loadingDiv.id = "vivo-loading-tab";
        loadingDiv.innerHTML = self.options.loadingText;
        self.contentElement.appendChild(loadingDiv);
      }
    }, options || {});

    this.contentElement.appendChild(this.fragment);

    if (this.options.initialState == "open") {
      this.tabAction();
    }

    this.eventListener = this.tabAction.bindAsEventListener(this);
    Event.observe(this.element, this.options.action, this.eventListener);
  },

  tabAction: function(event) {
    var self = this;

    for (var a = 0; a < self.contentElement.childNodes.length; a++) {
      if (self.contentElement.childNodes[a].nodeType == 1) {
        self.contentElement.childNodes[a].style.display = "none";
      }
    }

    if (this.options.reload == "yes" || this.fragment.innerHTML.length < 1) {
      var ajaxComplete = function(xmlhttp) {
        if (xmlhttp.status == 200) {
          self.options.onComplete(xmlhttp.responseText);
        }
        else {
          self.options.onComplete("An error occured while getting the content.");
        }
      }
      new Ajax.Request(this.url, {method: "get", onLoading: self.options.onLoading, onComplete: ajaxComplete});
    }
    else {
      this.options.onLoading();
      this.options.onComplete();
    }

    if (event) {
      Event.stop(event);
    }

    return false;
  }
}


//-------------------------------------
// BatchLink Tool
// Like a tab tool.  This tool is attached to a link, with a target container id.
// when link is clicked, div will be retrieved from url and content placed in the container
// idea is to place the batch links inside the container url
//-------------------------------------
var BatchLink = Class.create();
BatchLink.prototype = {
  initialize: function(element, contentElement, options) {
    var self = this;
    this.element = $(element);
    this.contentElement = $(contentElement);
    this.url = this.element.getAttribute('href');
    /*    if (element.hasAttribute('href')) {
      element.removeAttribute('href');
      alert(element.href);
      }*/
    this.transEffect = null;
    this.options = Object.extend({
      action: "click",
	  loadingText: "Loading...",
	  onComplete: function(content) {
	    if ($("vivo-loading-batch") != null) {
	      self.contentElement.removeChild($("vivo-loading-batch"));
	    }
	    function finishLoading() {
	      if (content != null && content.length > 0) {
		self.contentElement.innerHTML = content;
		Vivo.apply(self.contentElement);
		if (self.options.afterComplete) {
		  self.options.afterComplete();
		};
	      };
	    };
	    finishLoading();
	    /*turn off opacity as it doesn't work well in firefox
	      function doOpacity() {
	      new Effect.Opacity(self.contentElement.id,
				 { duration: 0.0,
				     transition: Effect.Transitions.linear,
				     from: 0.5,
				     to: 1.0,
				     beforeStart: function(obj){finishLoading()},
				     queue: 'end'}
				 );
	    };
	    var d = (new Date()).valueOf();
	    if (d < self.transEffect.finishOn){
	      window.setTimeout(doOpacity,self.transEffect.finishOn - d);
	    } else {
	      doOpacity();
	      };*/
	},
	  onLoading: function() {
	    var loadingDiv = document.createElement("div");
	  /*self.contentElement.innerHTML = '';*/
	    loadingDiv.id = "vivo-loading-batch";
	    loadingDiv.innerHTML = self.options.loadingText;
	    loadingDiv.style.display = 'block';
	    self.contentElement.insertBefore(loadingDiv,self.contentElement.childNodes[0]);
	    /*self.transEffect = new Effect.Opacity(self.contentElement.id, 
				   { duration: 0.0, 
				       transition: Effect.Transitions.linear, 
				       from: 1.0, 
				       to: 0.5,
				       queue: 'end'
				    }
				    );*/
	}
      }, options || {});
    //afterComplete is a function, so parse it into a function
    if (self.options.afterComplete) {
      //in IE, eval returns undefined, so set the option within the eval
      eval('self.options.afterComplete = ' + self.options.afterComplete);
    }

    this.eventListener = this.batchAction.bindAsEventListener(this);
    /* XXX is this.options.action defined if not supplied? */
    Event.observe(this.element, this.options.action, this.eventListener);
  },

  batchAction: function(event) {
    var self = this;
    var ajaxComplete = function(xmlhttp) {
      if (xmlhttp.status == 200 || xmlhttp.status == 0) {
	self.options.onComplete(xmlhttp.responseText);
      }
      else {
	self.options.onComplete("An error occured while getting the content." +
				xmlhttp.responseText + xmlhttp.status);
      }
    }
    /*var onError = function(xmlhttp) {
      alert('an error occured');
      }*/
    new Ajax.Request(this.options.url || this.url, {method: "get", onLoading: self.options.onLoading, 
			 onComplete: ajaxComplete });
    
    if (event) {
      Event.stop(event);
    }
    return false;
  } }
