// The global array of objects that have been instanciated
if (!Bs_Objects) {var Bs_Objects = [];};

/**
* A TabSet Component.
* 
* <b>Features:</b> 
* - IE6 and NS(Mozilla7) compliant.
*
* <b>How to use:</b>
* 1. Have a look at the example (see example link below)
* 2. Create a function in the HTML-header called init(). Place the javascript code 
*    that instanciates and inits this component into init().
* 3. Place an 'onLoad' in your body-tag: e.g. <body onLoad="init();">
* 4. In the HTML body: Place a div- or span-tag with an unique ID where you want the component to be.
*
* <b>How it works:</b>
* - [After instanciating and initializing the object]. Call the draw() method.
*   This will search the HTML code for a tag with the given id and insert HTML- and JS- code
*   dynamically (using DOM) to display the component and handle it.
* 
* @example example1.html
*
* @author     andrej-at-blueshoes-dot-org
* @package    javascript_components
* @subpackage tabset
* @copyright  blueshoes.org
*/
function Bs_TabSet(outerElmId) {

  // To support the old interface call with 2 arguments. (First argument used to be the object name). 
  var a = arguments;
  this._outerElmId = (a.length>1) ? a[1] :  a[0];  
	
  /**
	* ID is initialized in the constuctor. Represents the possition of 'this' in the global array 'Bs_Objects'
	* Use: This is the only way we can reference ourselfs in an evaluation string 
  *  E.g. str = "var me = Bs_Objects["+this._id+"];";
  *       str += "me.foo();" 
  *       eval(str); 
  *
  * @access private
	* @var  integer 
  */
  this._id;
  
  /**
	* Unique Object ID is initialized in the constuctor.
	* Bassed on this._id. Can be used in genarate JS-code as ID. Is set together 
  * from the  classname + this._id (see constructor code at the bottom).
  *
  * @access private
	* @var  string 
  */
  this._objectId;
	
  /**
  *
  */
  this.tabs = new Array;
	
  /**
  * default tab index, 0-n.
  * @access public
	* @var    integer defaultTab
  */
	this.defaultTab = 0;
	
  /**
  * Currently active Tab index
  * @access private
	* @var    integer _activeTabIdx
  */
  this._activeTabIdx = 0;
	
  /**
  * The event to call if set and tab is changed by click or by a clall to switchTo().
  * @access private
	* @var    integer _onTabSelectEvent
  */
  this._onTabSelectEvent
	
	/**
	* how the tabs should be drawn.
	* 
	*   'css' => using css only. default. see examples 1 and 2.
	*   'img' => using border images. more work, more fun. check example 3.
	* 
	* @access public
	* @var    string drawStyle
	* @since  bs-4.6
	*/
	this.drawStyle = 'css';
	
	/**
	* image path, used if drawStyle = 'img'.
	* @access public
	* @var    string imgPath
	*/
	this.imgPath;
	
	/**
	* image border size in pixels, used if drawStyle = 'img'.
	* @access public
	* @var    string imgBorderSize
	*/
	this.imgBorderSize;
	
	
	/**
	* the pseudo constructor.
	* @access private
	* @return void
	*/
	this._constructor = function() {
  	// Put this instance into the global object instance list
    this._id = Bs_Objects.length;
    Bs_Objects[this._id] = this; 
    this._objectId = "Bs_TabSet_"+this._id;
	}
	
	/**
	* @access public
	* @param  string  caption
	* @param  element container
	* @param  mixed   onTabSelect (callback like in this.onTabSelect() but only for this tab.)
	* @return void
	*/
	this.addTab = function(caption, container, onTabSelect) {
		if (typeof(caption) == 'object') {
			var o = caption;
		} else {
			var o = new Object;
			o.caption   = caption;
			if ((typeof(container) != 'undefined') && (container != null) && (container)) {
				if (typeof(container) == 'string') {
					o.container = document.getElementById(container);
					o.id        = container;
				} else {
					o.container = container;
					o.id        = container.id
				}
			}
			if (typeof(onTabSelect) != 'undefined') {
				o.onTabSelect = onTabSelect;
			}
		}
    o.tabIdx = this.tabs.length;
		this.tabs[o.tabIdx] = o;
	}
	
	
	/**
	* @access public (don't think you need that)
	* @return string
	* @see    this.draw()
	*/
	this.render = function() {
		
		var ret = new Array;
		//ret[ret.length] = '<div>';
		ret[ret.length] = '<div class="tabsetTabsDiv">';
		if (this.drawStyle == 'img') {
			var contentDiv = document.getElementById(this._outerElmId + '_content');
			if (contentDiv) {
				var preHtml = '';
				preHtml += '<table border="0" cellspacing="0" cellpadding="0" width="100%">';
				preHtml += '<tr>';
				preHtml += '<td width="' + this.imgBorderSize + '" background="' + this.imgPath + 'line_left.gif"><img src="' + this.imgPath + 'spacer.gif" width="' + this.imgBorderSize + '"></td>';
				preHtml += '<td>';
				
				var postHtml = '';
				postHtml += '</td>';
				postHtml += '<td width="' + this.imgBorderSize + '"  background="' + this.imgPath + 'line_right.gif"><img src="' + this.imgPath + 'spacer.gif" width="' + this.imgBorderSize + '"></td>';
				postHtml += '</tr>';
				postHtml += '<tr>';
				postHtml += '<td height="' + this.imgBorderSize + '" width="' + this.imgBorderSize + '"><img src="' + this.imgPath + 'line_cornerBottomLeft.gif"></td>';
				postHtml += '<td height="' + this.imgBorderSize + '" background="' + this.imgPath + 'line_bottom.gif"><img src="' + this.imgPath + 'spacer.gif" height="' + this.imgBorderSize + '"></td>';
				postHtml += '<td height="' + this.imgBorderSize + '" width="' + this.imgBorderSize + '"><img src="' + this.imgPath + 'line_cornerBottomRight.gif"></td>';
				postHtml += '</tr>';
				postHtml += '</table>';
				
				contentDiv.innerHTML = preHtml + contentDiv.innerHTML + postHtml;
				
				//have to re-set the elements:
				for (var i=0; i<this.tabs.length; i++) {
					this.tabs[i].container = document.getElementById(this.tabs[i].id);
				}
			}
			
			ret[ret.length] = '<table border="0" cellspacing="0" cellpadding="0" id="' + this._objectId + '_outerTable"><tr>';
			ret[ret.length] = '<td valign="bottom"><img src="' + this.imgPath + 'line_cornerTopLeft.gif"></td>';
			ret[ret.length] = '<td valign="bottom"><img src="' + this.imgPath + 'line_bottom.gif" width="5" height="' + this.imgBorderSize + '"></td>';
			for (var i=0; i<this.tabs.length; i++) {
				var actOrPasString = (i == this.defaultTab) ? 'open' : 'closed';
				if (i == this.defaultTab) {
					var cls = 'bsTabsetActive';
				} else {
					var cls = 'bsTabsetInactive';
					if (this.tabs[i].container) this.tabs[i].container.style.display = 'none';
				}
				
				ret[ret.length] = '<td>';
				ret[ret.length] = '<table border="0" cellspacing="0" cellpadding="0">';
				ret[ret.length] = '<tr>';
				if (i == 0) ret[ret.length] = '<td width="' + this.imgBorderSize + '" rowspan="100%"><img src="' + this.imgPath + 'left_' + actOrPasString + '.gif"></td>';
				ret[ret.length] = '<td height="' + this.imgBorderSize + '" background="' + this.imgPath + 'top.gif"><img src="' + this.imgPath + 'spacer.gif" width="1" height="' + this.imgBorderSize + '"></td>';
				if (i == (this.tabs.length -1)) {
					//last one:
					ret[ret.length] = '<td width="' + this.imgBorderSize + '" rowspan="100%"><img src="' + this.imgPath + 'right_' + actOrPasString + '.gif"></td>';
				} else {
					ret[ret.length] = '<td width="' + this.imgBorderSize + '" rowspan="100%"><img src="' + this.imgPath + 'middle.gif"></td>';
				}
				ret[ret.length] = '</tr>';
				ret[ret.length] = '<tr>';
				ret[ret.length] = '<td id="' + this._objectId + '_tdBg_' + i + '" background="' + this.imgPath + 'bg_' + actOrPasString + '.gif">';
				ret[ret.length] = '<div unselectable="On" id="' + this._objectId + '_tabCap_' + i + '" class="bsTabset ' + cls + '" style="display:inline;" onclick="Bs_Objects['+this._id+'].switchTo(' + i + ');">';
				ret[ret.length] = '<nobr>' + this.tabs[i].caption + '</nobr>';
				ret[ret.length] = '</div>';
				ret[ret.length] = '</td>';
				ret[ret.length] = '</tr>';
				ret[ret.length] = '<tr>';
				ret[ret.length] = '<td id="' + this._objectId + '_tdLineBottom_' + i + '" height="' + this.imgBorderSize + '" background="' + this.imgPath + 'bottom_' + actOrPasString + '.gif"><img src="' + this.imgPath + 'spacer.gif" width="1" height="' + this.imgBorderSize + '"></td>';
				ret[ret.length] = '</tr>';
				ret[ret.length] = '</table>';
				ret[ret.length] = '</td>';
			}
			ret[ret.length] = '<td id="' + this._objectId + '_tdLineBottom" valign="bottom" width="10"><img src="' + this.imgPath + 'line_bottom.gif" height="' + this.imgBorderSize + '" width="100%"></td>';
			ret[ret.length] = '<td valign="bottom"><img src="' + this.imgPath + 'line_cornerTopRight.gif" height="' + this.imgBorderSize + '" width="' + this.imgBorderSize + '"></td>';
			
			ret[ret.length] = '</tr></table>';
		} else { // 'css'
			ret[ret.length] = '<div style="width:2px; min-width:2px; display:inline;"></div>';
			for (var i=0; i<this.tabs.length; i++) {
				if (i == this.defaultTab) {
					var cls = 'bsTabsetActive';
				} else {
					var cls = 'bsTabsetInactive';
					if (this.tabs[i].container) this.tabs[i].container.style.display = 'none';
				}
				ret[ret.length] = '<div unselectable="On" id="' + this._objectId + '_tabCap_' + i + '" class="bsTabset ' + cls + '" style="display:inline;" onclick="Bs_Objects['+this._id+'].switchTo(' + i + ');">' + this.tabs[i].caption + '</div>';
			}
		}
		ret[ret.length] = '</div>';
		//ret[ret.length] = '</div>';
		return ret.join('');
	}
	
	/**
	* @access public
	* @return void
	*/
	this.draw = function() {
		var elem = document.getElementById(this._outerElmId + '_tabs');
		if (elem) elem.innerHTML = this.render();
		
		
		//after render stuff:
		if (this.drawStyle == 'img') {
			var tdLine     = document.getElementById(this._objectId + '_tdLineBottom');
			var outerTable = document.getElementById(this._objectId + '_outerTable');
			var tds = outerTable.firstChild.firstChild.childNodes;
			var allTdWidth = 0;
			for (var i=0; i<tds.length; i++) {
				if (tds[i] == tdLine) continue;
				allTdWidth += tds[i].offsetWidth;
			}
			var outerDiv  = document.getElementById(this._outerElmId);
			var lineWidth = outerDiv.offsetWidth - allTdWidth;
			tdLine.width  = lineWidth;
		}
	}
	
	
	/**
	* Switches to the register specified.
  * A paramter you may pass either the caption name of the Tab as string or the Tab index as intger (0-n).
	* @access public
	* @param  newReg mixed string or int 
	* @return void
	*/
	this.switchTo = function(theReg) {
    newRegIdx = -1;
    if (theReg == '') theReg = '0';
    if (isNaN(parseInt(theReg))) {
      for (var i=0; i<this.tabs.length; i++) {
        if (this.tabs[i].caption == theReg) (newRegIdx = i); 
      }
    } else {
      newRegIdx = theReg;
    }
  	
    if (newRegIdx < 0) return; // Unknown Register passed
    
		for (var i=0; i<this.tabs.length; i++) {
			var elem = document.getElementById(this._objectId + '_tabCap_' + i);
  		if (!elem) continue;
			if (newRegIdx == i) {
				this._activeTabIdx = i;
				elem.setAttribute('class','bsTabset bsTabsetActive');     //fox
				elem.setAttribute('className','bsTabset bsTabsetActive'); //ie
        //elem.className = 'bsTabset bsTabsetActive';             //ie
				if (typeof(this.tabs[i].container) != 'undefined') {
					this.tabs[i].container.style.display = 'block';
				}
				if (this.drawStyle == 'img') {
					var td = document.getElementById(this._objectId + '_tdLineBottom_' + i);
					//td.background = this.imgPath + 'bottom_open.gif';
					td.setAttribute('background', this.imgPath + 'bottom_open.gif');
					var td = document.getElementById(this._objectId + '_tdBg_' + i);
					//td.background = this.imgPath + 'bg_open.gif';
					td.setAttribute('background', this.imgPath + 'bg_open.gif');
				}
				if (typeof(this.tabs[i].onFocus) != 'undefined') {
					this._triggerFunction(this.tabs[i].onFocus);
				}
        this.fireOnTabSelect();
			} else {
				elem.setAttribute('class','bsTabset bsTabsetInactive');     //fox
				elem.setAttribute('className','bsTabset bsTabsetInactive'); //ie
				if (typeof(this.tabs[i].container) != 'undefined') {
					this.tabs[i].container.style.display = 'none';
				}
				if (this.drawStyle == 'img') {
					var td = document.getElementById(this._objectId + '_tdLineBottom_' + i);
					//td.background = this.imgPath + 'bottom_closed.gif';
					td.setAttribute('background', this.imgPath + 'bottom_closed.gif');
					var td = document.getElementById(this._objectId + '_tdBg_' + i);
					//td.background = this.imgPath + 'bg_closed.gif';
					td.setAttribute('background', this.imgPath + 'bg_closed.gif');
				}
				if (typeof(this.tabs[i].onBlur) != 'undefined') {
					this._triggerFunction(this.tabs[i].onBlur);
				}
			}
		}
	}
	
	
  /**
  * Get the currently active tab as object 
  * Note: This is just the one *currently visible* tab of the tabset.
	* @access public
	* @return object (with the vars .container, .id, .tabIdx and .caption)
  */
  this.getActiveTab = function() {
    return this.tabs[this._activeTabIdx];
  }
  
	/**
	* Returns the ID of the outer div element where this component is rendered into.
	* @access public
	* @return string
	*/
	this.getOuterDivID = function() {
		return this._outerElmId;
	}
	
  /**
  * attaches onTabSelect-event.
	* 
	* examples:
	*   myObj.onTabSelect(myFunction);
	*   then your function myFunction() receives one param, it is 
	*   a reference to this object (myObj).
	*   
	*   myObj.onTabSelect("if (true) return false;");
	*   this is an example with code attached that will be evaluated.
	* 
  * @access public
  * @param  mixed  yourEvent (string (of code) or function)
  * @return void
  * @see    var this._onTabSelectEvent
  */
  this.onTabSelect = function(yourEvent) {
    this._onTabSelectEvent = yourEvent;
  }
  
  /**
  * fires the onTabSelect for the trigger specified.
  * @access public (used internally but feel free to trigger events yourself...)
  * @param  string trigger
  * @see onTabSelect()
  * @return true
  */
  this.fireOnTabSelect = function() {
		//global registered stuff:
    if (this._onTabSelectEvent) {
      func = this._onTabSelectEvent;
      if (typeof(func) == 'string') {
        eval(func);
      } else {
        func(this);
      }
    }
		
		//registered stuff only for current tab:
		var tab = this.getActiveTab();
    if (tab.onTabSelect) {
      func = tab.onTabSelect;
      if (typeof(func) == 'string') {
        eval(func);
      } else {
        func(this);
      }
    }
		
		return true;
  }	
  
  
	/**
	* @access private
	* @param  mixed func (function or string)
	* @return void
	*/
	this._triggerFunction = function(func) {
		if (typeof(func) == 'function') {
			func();
		} else if (typeof(func) == 'string') {
			eval(func);
		}
	}
	

	this._constructor(); //call the constructor. needs to be at the end.	

}
