/*
Product Name: dhtmlxSuite 
Version: 4.0.3 
Edition: Professional 
License: content of this file is covered by DHTMLX Commercial or Enterprise license. Usage without proper license is prohibited. To obtain it contact sales@dhtmlx.com
Copyright UAB Dinamenta http://www.dhtmlx.com
*/
function dhtmlXTabBar(conf, mode) { // skin? data?
	
	// console.log("context menu for tabs?");
	// console.log("first tab open event?");
	
	var that = this;
	
	this.conf = {
		skin: (window.dhx4.skin||(typeof(dhtmlx)!="undefined"?dhtmlx.skin:null)||window.dhx4.skinDetect("dhxtabbar")||"dhx_skyblue"),
		fullScreen: false,
		fullScreenResize: false, // autoresize not inited
		lastActive: null,
		closeButton: false,
		align: "left", // tabs aligned to right side, inversed, default "right" align
		tabsMode: (mode=="bottom"?"bottom":"top"), // top/bottom
		contZone: true,
		transSpeed: "0.15s",
		baseOfs: {w:2,h:2}, // offset for base in fullscreen mode
		tabsOfs: 1, // dhx_skyblue and dhx_terrace have margin-left:-1px for tabs, should be included
		tabsTop: 0, // tabs top position, used in attachObject to hide border
		autoload: {}
	};
	
	var base;
	
	// check if api init
	if (conf != null && typeof(conf) == "object" && typeof(conf.tagName) == "undefined") {
		base = conf.parent;
		if (typeof(conf.skin) != "undefined") this.conf.skin = conf.skin;
		if (typeof(conf.mode) != "undefined") this.conf.tabsMode = (conf.mode=="bottom"?"bottom":"top");
		if (typeof(conf.align) != "undefined") this.conf.align = (conf.align=="right"?"right":"left");
		if (typeof(conf.close_button) != "undefined") this.conf.closeButton = window.dhx4.s2b(conf.close_button);
		if (typeof(conf.content_zone) != "undefined") this.conf.contZone = window.dhx4.s2b(conf.content_zone);
		if (typeof(conf.xml) != "undefined") this.conf.autoload.xml = conf.xml;
		if (typeof(conf.json) != "undefined") this.conf.autoload.xml = conf.json; // new in 4.0
		if (typeof(conf.tabs) != "undefined") this.conf.autoload.tabs = conf.tabs;
		if (typeof(conf.onload) != "undefined") this.conf.autoload.tabs = conf.tabs; // new in 4.0
		// deprecated from 4.0
		// conf { height, offset, margin, image_path, href_mode, scroll, forced, size_by_content, auto_size }
	} else {
		base = conf;
	}
	
	if (base == document.body) {
		
		document.documentElement.className += " dhxtabbar_fullscreen";
		document.body.className += " dhxtabbar_fullscreen";
		this.conf.fullScreen = true;
		
		this.base = document.createElement("DIV");
		this.base.className = "dhxtabbar_base_"+this.conf.skin;
		this.base.style.position = "absolute";
		this.base.style.left = this.conf.baseOfs.w+"px";
		this.base.style.top = this.conf.baseOfs.h+"px";
		document.body.appendChild(this.base);
		
	} else {
		
		this.base = (typeof(base) == "string" ? document.getElementById(base) : base);
		base = null;
		
		this.base.className += " dhxtabbar_base_"+this.conf.skin;
		
	}
	
	// tabsTop override
	if (this.base._ofs != null && this.base._ofs.t != null) this.conf.tabsTop = this.base._ofs.t;
	
	this.tabsMode = document.createElement("DIV");
	this.tabsMode.className = "dhxtabbar_tabs_"+this.conf.tabsMode;
	this.base.appendChild(this.tabsMode);
	
	this.tabsArea = document.createElement("DIV");
	this.tabsArea.className = "dhxtabbar_tabs dhxtabbar_tabs_"+this.conf.tabsMode;
	this.tabsArea.innerHTML = "
"+
					""+
					"";
	
	if (this.conf.tabsMode == "top") {
		this.tabsArea.style.top = this.conf.tabsTop+"px";
	}
	this.tabsMode.appendChild(this.tabsArea);
	
	// area to move tabs
	this.tabsArea.childNodes[1].childNodes[0].style[this.conf.align] = "0px";
	
	this.tabsArea.childNodes[0].onclick = function() {
		if (that.conf.align == "left") {
			that._moveTabs(1);
		} else {
			that._moveTabs(-1);
		}
	}
	this.tabsArea.childNodes[2].onclick = function() {
		if (that.conf.align == "left") {
			that._moveTabs(-1);
		} else {
			that._moveTabs(1);
		}
	}
	
	this._onTabsAreaClick = function(id) {
		return this._callMainEvent("onTabClose",[id]);
	}
	
	this.tabsArea.onclick = function(e) {
		e = e||event;
		var t = (e.target||e.srcElement);
		while (t != null) {
			if (typeof(t._tabCloseId) != "undefined") {
				if (that._onTabsAreaClick(t._tabCloseId) !== true) return;
				that.t[t._tabCloseId].conf.remove = true;
				that._hideTab(t._tabCloseId);
				t = null;
			} else if (typeof(t._tabId) != "undefined") {
				that._doOnClick(t._tabId);
				t = null;
			}
			if (t != null) {
				t = t.parentNode;
				if (t == this) t = null;
			}
		}
	}
	
	this.tabsArea.onselectstart = function(e) {
		e = e||event;
		if (e.preventDefault) e.preventDefault(); else e.returnValue = false;
	}
	
	this._doOnClick = function(id) {
		// onBeforeEvent here
		this.callEvent("onTabClick", [id, this.conf.lastActive]);
		if (this.t[id].conf.enabled) this._setTabActive(id);
	}
	
	this.t = {};
	
	this.addTab = function(id, text, width, position, active, close) {
		
		// close = show close button, false by default
		// true - show_closeButton
		// false - do not show (ignoring enableTabCloseButton)
		// not set - depending on enableTabCloseButton
		if (typeof(close) != "boolean") close = (this.conf.closeButton==true);
		active = window.dhx4.s2b(active);
		
		var tab = document.createElement("DIV");
		tab.className = "dhxtabbar_tab";
		tab.innerHTML = ""+text+"
"+
				(close?"":"");
		
		tab._tabId = id;
		if (close) tab.childNodes[1]._tabCloseId = id; // close button
		
		var p = this.tabsArea.childNodes[1].firstChild;
		
		if (position != null && position+1 > 0 && position+1 < p.childNodes.length) { // 1st item - line
			p.insertBefore(tab, p.childNodes[position+1]);
		} else {
			p.appendChild(tab);
		}
		
		
		// width
		var autowidth = false;
		if (typeof(width) == "undefined" || width == null || width == "*") {
			width = this._getLabelWidth(text, close);
			autowidth = true;
		} else {
			width = parseInt(width);
		}
		
		tab.style.width = width+"px";
		
		var cell = new dhtmlXTabBarCell(id, this);
		this.tabsMode.appendChild(cell.cell);
		
		this.t[id] = {
			tab: tab,
			cell: cell,
			conf: {
				text: text,
				visible: true,
				active: false,
				enabled: true,
				close: close,
				width: width,
				autowidth: autowidth
			}
		};
		
		p = cell = null;
		
		if (active) {
			this._setTabActive(id);
		} else {
			this._adjustCell(id);
		}
		
	}
	
	this.setSizes = function() {
		
		if (this.conf.fullScreen) {
			this.base.style.width = document.body.offsetWidth-this.conf.baseOfs.w*2+"px";
			this.base.style.height = document.body.offsetHeight-this.conf.baseOfs.h*2+"px";
		}
		
		if (this.conf.tabsAreaOfs == null) {
			this.tabsArea.style.width = this.base.offsetWidth+"px";
			this.conf.tabsAreaOfs = parseInt(this.tabsArea.style.width)-this.tabsArea.offsetWidth;
		}
		this.tabsArea.style.width = this.base.offsetWidth+this.conf.tabsAreaOfs+"px";
		
		this.tabsArea.childNodes[1].style.left = this.tabsArea.childNodes[0].offsetWidth-1+"px";
		this.tabsArea.childNodes[1].style.width = Math.max(0, this.tabsArea.offsetWidth-this.tabsArea.childNodes[0].offsetWidth-this.tabsArea.childNodes[2].offsetWidth)+1+"px"; // minus 2 arrows
		
		this._adjustCell(this.conf.lastActive);
		this._adjustTabs();
		
	}
	
	this._adjustCell = function(id) {
		
		// adjust specified cell or active
		
		if (!this.conf.contZone || id == null) return;
		
		var y = (this.conf.tabsMode=="top"?this.tabsArea.offsetHeight:0)+this.conf.tabsTop;
		var h = this.base.offsetHeight-this.tabsArea.offsetHeight-this.conf.tabsTop;
		
		// if layout attached - move a bit
		var t = this.t[id].cell.dataType;
		if (this.conf.skin == "dhx_skyblue" && (t == "layout" || t == "tabbar" || t == "acc")) {
			if (this.conf.tabsMode == "top") y = y - 1; // only for top
			h = h + 1; // always
		}
		
		if (id != this.conf.lastActive) {
			y = -5000;
			this.t[id].cell.cell.style.visibility = "hidden";
			this.t[id].cell.cell.style.zIndex = 0;
		}
		this.t[id].cell._setSize(0, y, this.base.offsetWidth, h);
	}
	
	this.setTabsMode = function(mode) {
		
		// new
		this.conf.tabsMode = (mode=="bottom"?"bottom":"top");
		this.tabsMode.className = "dhxtabbar_tabs_"+this.conf.tabsMode;
		this.setSizes();
		
	}
	
	// generate tab css depending on actv/en state
	this._tabCss = function(id, hidden) {
		var a = this.t[id].conf.active;
		var d = !this.t[id].conf.enabled;
		var h = !this.t[id].conf.visible;
		return "dhxtabbar_tab"+(h?" dhxtabbar_tab_hidden":(a||d?" dhxtabbar_tab"+(a?"_actv":"")+(d?"_dis":""):""));
	}
	
	// calculate tab width depending on text and close button
	this._getLabelWidth = function(text, close) {
		
		if (!this.tabsTextTest) {
			this.tabsTextTest = document.createElement("SPAN");
			this.tabsTextTest.className = "dhxtabbar_tabs_text_test_"+this.conf.skin;
		}
		
		document.body.appendChild(this.tabsTextTest);
		this.tabsTextTest.innerHTML = text;
		var w = this.tabsTextTest.offsetWidth;
		// move to conf?
		w += (this.conf.skin == "dhx_terrace" ? 44:35);
		w += (close ? (this.conf.skin == "dhx_terrace" ? 14:9) : 0);
		//
		document.body.removeChild(this.tabsTextTest);
		return w;
	}
	
	// if tabs overflow left/right side, adjust active tab position
	this._adjustTabs = function() {
		
		var p = this.tabsArea.childNodes[1];
		if (p.offsetWidth < 5) {
			p = null;
			return;
		}
		
		var x = parseInt(p.childNodes[0].style[this.conf.align]);
		
		var k = null;
		for (var q=0; q p.offsetWidth) {
						k = {d:-1, id: id}; // overflow on right
					}
				}
				x += w;
			}
		}
		
		if (k != null) {
			// move selected tab to visible space
			this._moveTabs(k.d, k.id);
		} else if (p.offsetWidth > x+1) {
			// check space on right side
			p.childNodes[0].style[this.conf.align] = Math.min(0, parseInt(p.childNodes[0].style[this.conf.align])+(p.offsetWidth-x))+"px";
		}
		
		p = k = null;
		
	}
	
	// tabs scrolling
	this._moveTabs = function(d, tabId) {
		
		// get all visible tabs
		var p = this.tabsArea.childNodes[1].childNodes[0];
		var i = 0;
		var tabs = [];
		var tabInd = null; // index of tabId
		for (var q=0; q= 0 && x+tabs[q].w > 0) f = tabs[q];
			if (x < totalSpace && x+tabs[q].w <= totalSpace) l = tabs[q];
			x += tabs[q].w;
		}
		
		if (tabInd != null) {
			
			var t = tabs[tabInd];
			
		} else {
			
			var t = null;
			if (d > 0) {
				// left arrow clicked
				// find prev tab (for 1st visible) or last (if 1st is null)
				if (f == null) {
					if (tabs.length > 0) t = tabs[tabs.length-1];
				} else {
					if (f.ind > 0 && tabs.length >= f.ind) t = tabs[f.ind-1];
				}
				
			} else {
				// right arrow clicked
				// find next tab (for last visible) or first (if last-visible is null)
				if (l == null) {
					if (tabs.length > 0) t = tabs[0];
				} else {
					if (tabs.length > l.ind) t = tabs[l.ind+1];
				}
				
			}
		}
		
		// move prev/last tab to 1st position
		if (t != null) {
			if (d > 0) {
				if (x < totalSpace) {
					// some tabs are on left and some space left on right
					p.style[this.conf.align] = Math.min(0, parseInt(p.style[this.conf.align])+(totalSpace-x))+"px";
				} else {
					// show tab on left
					p.style[this.conf.align] = parseInt(p.style[this.conf.align])-t.x+"px";
				}
			} else {
				p.style[this.conf.align] = parseInt(p.style[this.conf.align])-t.x+totalSpace-t.w+"px";
			}
		}
		
		p = t = tabs = null;
		
	}
	
	// return next visible related to tab-id
	this._getNextVisible = function(id, getFirst) {
		return this._getNearVisible(id, getFirst, "next");
	}
	
	// return prev visible related to tab-id
	this._getPrevVisible = function(id, getFirst) {
		return this._getNearVisible(id, getFirst, "previous");
	}
	
	// get first visible
	this._getFirstVisible = function() {
		return this._getNearVisible(null, false, "first");
	}
	
	this._getNearVisible = function(id, getFirst, mode) {
		
		if (mode == "first") {
			var node = this.tabsArea.childNodes[1].childNodes[0].childNodes[1]; // firstChild is line
			mode = "next";
		} else {
			if (id == null || this.t[id] == null) return (getFirst?this._getFirstVisible():null);
			var node = this.t[id].tab[mode+"Sibling"];
		}
		
		var tabId = null;
		
		while (node != null && tabId == null) {
			var k = node._tabId;
			if (k != null && tabId == null && this.t[k].conf.visible) {
				tabId = k;
			} else {
				node = node[mode+"Sibling"];
			}
		}
		
		node = null;
		
		return tabId;
	}
	
	
	
	this._showTab = function(id, activate) { // activate true/false
		
		if (!this.t[id] || this.t[id].conf.visible || this.t[id].conf.transActv) return;
		
		// get next tab
		// move
		// show prev+set marg to -1
		// get next/prev tabs
		
		if (this.conf.transProp !== false) {
			
			// slide effect
			this.t[id].conf.transActv = true;
			this.t[id].conf.transMode = "show";
			this.t[id].conf.transProp = this.conf.transProp;
			this.t[id].conf.transActvId = (activate?id:null);
			
			if (!this.t[id].conf.transEv) {
				this.t[id].tab.addEventListener(this.conf.transEv, this._doOnTrEnd);
				this.t[id].conf.transEv = true;
			}
			
			this.t[id].conf.visible = true;
			this.t[id].tab.className = this._tabCss(id);
			
			this.t[id].tab.style[this.conf.transProp] = this.conf.transValueWidth;
			this.t[id].tab.style.width = this.t[id].conf.width+"px";
			
			
		} else {
			this.t[id].conf.visible = true;
			this.t[id].tab.style.display = "";
			
			if (activate) {
				this._setTabActive(id);
			} else {
				this._adjustTabs();
			}
		}
	}
	
	this._hideTab = function(id, activateId) { // activateId - tab to activate
		
		// activateId
		// if set to true, selection jump from current tab to nearest one (old logic)
		// activateId can also be id of any other tab (new logic)
		
		if (!this.t[id] || !this.t[id].conf.visible || this.t[id].conf.transActv) return;
		
		// if tab was active clear flags/css
		var lastActive = false;
		if (this.conf.lastActive == id) {
			this.conf.lastActive = null;
			this.t[id].conf.active = false;
			this.t[id].tab.className = this._tabCss(id);
			lastActive = true;
		}
		
		// get next/prev tabs
		var prev = this._getPrevVisible(id);
		var next = this._getNextVisible(id);
		
		var actvId = (lastActive && activateId !== false ? (activateId==true?null:activateId)||next||prev : null);
		
		// hide and move next tab to left if any
		if (this.conf.transProp !== false) {
			
			this.t[id].conf.transActv = true;
			this.t[id].conf.transMode = "hide";
			this.t[id].conf.transProp = this.conf.transProp;
			this.t[id].conf.transActvId = actvId;
			this.t[id].conf.visible = false;
			
			if (!this.t[id].conf.transEv) {
				this.t[id].tab.addEventListener(this.conf.transEv, this._doOnTrEnd);
				this.t[id].conf.transEv = true;
			}
			
			this.t[id].tab.style.visibility = "hidden";
			this.t[id].tab.className = that._tabCss(id);
			this.t[id].tab.style[this.conf.transProp] = this.conf.transValueWidth;
			this.t[id].tab.style.width = "0px";
			
		} else {
			
			this.t[id].tab.style.display = "none";
			this.t[id].conf.visible = false;
			if (this.conf.contZone) {
				this.t[id].cell.cell.style.visibility = "hidden";
				this.t[id].cell.cell.style.top = "-5000px"; // "vis:hid" > "vis:vis" http://www.w3.org/TR/CSS2/visufx.html#visibility
			}
			
			if (actvId != null) this._setTabActive(actvId);
			this._adjustTabs();
			
			if (this.t[id].conf.remove) this._removeTab(id);
		}
		
	}
	
	this._isTabVisible = function(id) {
		return (this.t[id].conf.visible==true);
	}
	
	this._doOnTrEnd = function() {
		
		var id = this._tabId; // this points to tab
		
		if (that.t[id] == null) return;
		
		var t = that.t[id];
		var actvId = t.conf.transActvId;
		
		if (t.conf.transMode == "hide") {
			
			// remove if any
			if (t.conf.remove) {
				that._removeTab(id);
			} else {
				
				t.tab.style[t.conf.transProp] = "";
				
				if (that.conf.contZone) {
					t.cell.cell.style.visibility = "hidden";
					t.cell.cell.style.top = "-5000px";
				}
				
				t.conf.transActv = false;
				
			}
			
		} else if (t.conf.transMode == "show") {
			
			t.tab.style[t.conf.transProp] = "";
			t.tab.style.visibility = "visible";
			
			t.conf.transMode = null;
			t.conf.transActv = false;
			
		}
		
		if (actvId != null) {
			that._setTabActive(actvId);
		} else {
			that._adjustTabs();
		}
		
		t = null;
		
	}
	
	
	this.enableTabCloseButton = function(mode) {
		this.conf.closeButton = window.dhx4.s2b(mode);
	}
	
	this.unload = function() {
		
		this.clearAll(); // remove all tabs
		this.t = null;
		
		// fullscreen resize events
		if (this.conf.fullScreen) {
			if (window.addEventListener) {
				window.removeEventListener("resize", this._doOnResizeStart, false);
			} else {
				window.detachEvent("onresize", this._doOnResizeStart);
			}
			this._doOnResizeStart = null;
			this._doOnResizeEnd = null;
		}
		
		if (this.tabsTextTest != null) {
			if (this.tabsTextTest.parentNode) this.tabsTextTest.parentNode.removeChild(this.tabsTextTest);
			this.tabsTextTest = null;
		}
		
		// clear evernt
		window.dhx4._eventable(this, "clear");
		window.dhx4._enableDataLoading(this, null, null, null, "clear");
		
		this.tabsArea.childNodes[0].onclick = null;
		this.tabsArea.childNodes[2].onclick = null;
		this.tabsArea.onclick = null;
		this.tabsArea.onselectstart = null;
		this.tabsArea.parentNode.removeChild(this.tabsArea);
		this.tabsArea = null;
		
		this.tabsMode.parentNode.removeChild(this.tabsMode);
		this.tabsMode = null;
		
		if (this.conf.fullScreen) {
			this.base.parentNode.removeChild(this.base);
			document.documentElement.className = document.documentElement.className.replace("dhxtabbar_fullscreen","");
			document.body.className = document.body.className.replace("dhxtabbar_fullscreen","");
		} else {
			this.base.className = this.base.className.replace("dhxtabbar_base_"+this.conf.skin,"");
		}
		this.base = null;
		for (var a in this) this[a] = null;
		that = null;
	}
	
	this.enableContentZone = function(mode) {
		// enables/disables the content zone (enabled by default)
		// call before tabs adding
		this.conf.contZone = (mode==true);
	}
	
	this.setSkin = function(skin) {
		
		// sets style used for tabbar
		
		this.base.className = this.base.className.replace(new RegExp("dhxtabbar_base_"+this.conf.skin),"dhxtabbar_base_"+skin);
		this.conf.skin = skin;
		
		if (this.tabsTextTest != null) this.tabsTextTest.className = "dhxtabbar_tabs_text_test_"+this.conf.skin;
		
		for (var a in this.t) {
			
			// reset autosaved data for padding/border
			this.t[a].cell._resetSizeState();
			
			// tab width
			if (this.t[a].conf.autowidth == true) {
				this.t[a].conf.width = this._getLabelWidth(this.t[a].conf.text, this.t[a].conf.close);
				if (this.t[a].conf.visible) this.t[a].tab.style.width = this.t[a].conf.width+"px";
			}
			
		}
		
		this.conf.tabsAreaOfs = null;
		this._fixTabsOfs();
		
		this.setSizes();
	}
	
	this.setAlign = function(align) {
		
		align = (align=="left"?"left":"right");
		if (align == this.conf.align) {
			this.tabsArea.childNodes[1].childNodes[0].style[this.conf.align] = "0px";
			return;
		}
			
		if (this.conf.transProp !== false) {
			this.tabsArea.childNodes[1].childNodes[0].style[this.conf.transProp] = "";
		}
		this.tabsArea.childNodes[1].childNodes[0].style[this.conf.align] = "";
		
		this.conf.align = align;
		this.tabsArea.childNodes[1].childNodes[0].className = "dhxtabbar_tabs_cont_"+this.conf.align;
		this.tabsArea.childNodes[1].childNodes[0].style[this.conf.align] = "0px";
		
		if (this.conf.transProp !== false) {
			this.conf.transValuePos = this.conf.align+" "+this.conf.transSpeed;
			this.tabsArea.childNodes[1].childNodes[0].style[this.conf.transProp] = this.conf.transValuePos;
		}
	}
	
	this._initObj = function(data) {
		
		this.clearAll();
		
		var viaAjax = false;
		
		// settings
		if (data.settings != null) {
			if (data.settings.skin != null) this.setSkin(data.settings.skin);
			if (data.settings.closeButton != null) this.enableTabCloseButton(window.dhx4.s2b(data.settings.closeButton));
			if (data.settings.align != null) this.setAlign(data.settings.align);
			if (data.settings.hrefmode == "ajax" || data.settings.hrefmode == "ajax-html") viaAjax = true; // ajax-html is deprecated
		}
		// tabs
		if (data.tabs != null) {
			for (var q=0; q= p.childNodes.length) {
			p.appendChild(this.t[id].tab);
		} else {
			p.insertBefore(this.t[id].tab, p.childNodes[index]);
		}
	}
	p = null;
};
dhtmlXTabBar.prototype._getIndex = function(id) {
	var i = -1;
	var p = this.tabsArea.childNodes[1].firstChild;
	for (var q=1; q