/*
 *+------------------------------------------------------------------------+
 *| Licensed Materials - Property of IBM
 *| IBM Cognos Products: Viewer
 *| (C) Copyright IBM Corp. 2014
 *|
 *| US Government Users Restricted Rights - Use, duplication or
 *| disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *|
 *+------------------------------------------------------------------------+
 */

function CognosTabControl(container, callback) {
	this._init();

	this._outsideContainer = container;		// Container provisded by the caller
	this._callback = callback;				// function to call when a tab is clicked
}

CognosTabControl.prototype._init = function() {
	this._tabs = null;
	this._tabControlNode = null;
	this._scrollButtonsVisible = false;
	this._scrollLeftButton = null;
	this._scrollRightButton = null;
	this._selectedTab = null;	
	this._wrapperDiv = null;
	this._topContainer = null;
	this._seperator = null;
	this._isSavedOutput = false;
	this._isHighContrast = false;
};

CognosTabControl.prototype.destroy = function() {
	if (this._wrapperDiv) {
		this._wrapperDiv.parentNode.removeChild(this._wrapperDiv);
		delete this._wrapperDiv;
		this._wrapperDiv = null;
	}
};

CognosTabControl.prototype.setHighContrast = function(isHighContrast) {
	this._isHighContrast = isHighContrast;
};

CognosTabControl.prototype.isHighContrast = function() {
	return this._isHighContrast;
};

/**
 * In CW we have to save enough room for the absolutly positions tab control
 */
CognosTabControl.prototype.setSpaceSaverContainer = function(node) {
	this._spaceSaverContainer = node;
};

/**
 * Used when we're in BUX so that the tab control is absolutly positioned inside the widget div
 */
CognosTabControl.prototype.useAbsolutePosition = function(value) {
	this._useAbsolutePosition = value;
};

CognosTabControl.prototype.setScrollAttachNode = function(node) {
	this._scrollAttachNode = node;
};

CognosTabControl.prototype.setIsSavedOutput = function(isSavedOutput) {
	this._isSavedOutput = isSavedOutput;
};

CognosTabControl.prototype.isSavedOutput = function() {
	return this._isSavedOutput;
};

CognosTabControl.prototype.getSelectedTabId = function() {
	if (this._selectedTab) {
		return this._selectedTab.getId();
	}
	
	return null;
};

CognosTabControl.prototype.getSelectedTab = function() {
	return this._selectedTab ? this._selectedTab : null; 
};

CognosTabControl.prototype.isTopAligned = function() {
	return this._isTopAligned;
};

CognosTabControl.prototype.getWrapperDiv = function() {
	return this._wrapperDiv;
};

CognosTabControl.prototype.getVisibleWidth = function() {
	var scrollButtonWidth = this._scrollRightButton ? this._scrollRightButton.getWidth() + 11 : 0;
	return this._wrapperDiv.clientWidth - scrollButtonWidth;
};


CognosTabControl.prototype.getMaxRightScroll = function() {
	var scrollButtonWidth = this._scrollRightButton ? this._scrollRightButton.getWidth() + 11 : 0;
	return this._totalWrapperWidth + scrollButtonWidth + 8 - this._wrapperDiv.clientWidth;
};

CognosTabControl.prototype.hide = function() {
	this._topContainer.style.display = "none";
};

/**
 * If we're using absolute positioning then this will reset the left, top and bottom values
 */
CognosTabControl.prototype.resetPosition = function() {
	if (this._useAbsolutePosition === true) {
		this._outsideContainer.srollLeft = "0px";
		this._outsideContainer.scrollTop = "0px";

		this._topContainer.style.top = "";
		this._topContainer.style.bottom = "";
		
		this._topContainer.style.left = "0px";
		if (this._isTopAligned) {
			this._topContainer.style.top = "0px";
		}
		else {
			this._topContainer.style.bottom = "0px";
		}
	}	
};

/**
	Renders all the tabs
**/
CognosTabControl.prototype.render = function(tabControlInfo) {
	this._updateTabInfo(tabControlInfo);
	if (!this._tabControlNode) {
	
		var tabControl = this;
		var scrollAttachNode = this._scrollAttachNode ? this._scrollAttachNode : this._outsideContainer;
		if (window.attachEvent)	{
			window.attachEvent("onresize", function() { tabControl.onResize(); });
			if (this._useAbsolutePosition === true) {
				scrollAttachNode.attachEvent("onscroll", function() { tabControl.onContainerScroll(); });
			}
		}
		else {
			window.addEventListener("resize", function() { tabControl.onResize(); }, false);
			if (this._useAbsolutePosition === true) {
				scrollAttachNode.addEventListener("scroll", function() { tabControl.onContainerScroll(); }, false);
			}			
		}

		this._outsideContainer.originalClassName = this._outsideContainer.className;
		this._outsideContainer.className = this._outsideContainer.className + (this._isTopAligned ? " ct_controlTop" : " ct_controlBottom");
		
		this._topContainer = document.createElement("div");
		this._topContainer.className = "ct_wrapperDiv";
		if (this._useAbsolutePosition === true) {
			this._topContainer.style.width = "100%";
			this._topContainer.style.position = "absolute";
			this._topContainer.style.left = "0px";
			if (this._isTopAligned) {
				this._topContainer.style.top = "0px";
			}
			else {
				this._topContainer.style.bottom = "0px";
			}
		}
		
		if (this._isTopAligned && this._outsideContainer.firstChild) {
			this._outsideContainer.insertBefore(this._topContainer, this._outsideContainer.firstChild);
		}
		else {
			this._outsideContainer.appendChild(this._topContainer);
		}
	
		this._wrapperDiv = document.createElement("div");
		this._wrapperDiv.setAttribute("role", "presentation");
		this._wrapperDiv.className = "ct_wrapperDiv";
		this._topContainer.appendChild(this._wrapperDiv);

	
		this._tabControlNode = document.createElement("div");
		this._tabControlNode.setAttribute("role", "tablist");
		this._tabControlNode.className = "ct_control";
		this._wrapperDiv.appendChild(this._tabControlNode);
	
		this._totalWrapperWidth = 0;

		for (var i=0; i < this._tabs.length; i++) {
			var tab = this._tabs[i];
			tab.render(this._tabControlNode);
			this._totalWrapperWidth += this._tabs[i].getWidth();
		}	
				
		var wrapperDivHeight = 0;
		if (this._tabs[0]) {
			wrapperDivHeight = this._tabs[0].getHeight();
		}
		this._wrapperDiv.style.height = wrapperDivHeight + 5 + "px";
		
		if (this._spaceSaverContainer) {
			this.spaceSaverDiv = document.createElement("div");
			this.spaceSaverDiv.style.height = wrapperDivHeight + 5 + "px";
			this.spaceSaverDiv.style.position = "relative";
			this.spaceSaverDiv.style.display = "block";
			
			this._spaceSaverContainer.appendChild(this.spaceSaverDiv);
		}
		
		this._createSeperator();
	}
	else {
		this.resetPosition();
	}


	this._topContainer.style.display = "";
	
	this.onResize();

	this.selectTab(tabControlInfo.currentTabId, false);	
	
	if (this._selectedTab) {
		this._selectedTab.scrollIntoView();
		this.updateScrollButtons();
	}
};

/**
 * In BUX when the use scroll the widget container we need to make sure the tab control gets moved horizontally 
 */
CognosTabControl.prototype.onContainerScroll = function() {
	var container = this._scrollAttachNode ? this._scrollAttachNode : this._topContainer;
	this._topContainer.style.left = container.scrollLeft + "px";
	if (this._isTopAligned) {
		this._topContainer.style.top = container.scrollTop + "px";
	}
	else {
		this._topContainer.style.bottom = (-container.scrollTop) + "px";
	}
};

CognosTabControl.prototype._resetTabControl = function() {
	if (this._outsideContainer.originalClassName) {
		this._outsideContainer.className = this._outsideContainer.originalClassName;
	}
	else {
		this._outsideContainer.className = "";
	}
	
	if (this._topContainer) {
		var node = this._outsideContainer.removeChild(this._topContainer);
		node = null;
	}
	
	this._init();
};

/**
	Creates or updates the tab objects
**/
CognosTabControl.prototype._updateTabInfo = function(tabControlInfo) {
	this._isTopAligned = tabControlInfo.position == "topLeft" ? true : false;

	var tabs = tabControlInfo.tabs;
	
	// We already have tabs, make sure nothing has changed
	if (this._tabs) {
		if (this._tabs.length != tabs.length) {
			this._resetTabControl();
		}
		else {
			for (var i=0; i < this._tabs.length; i++) {
				if (tabs[i].id != this._tabs[i].getId()) {
					this._resetTabControl();
					break;
				}
			}
		}		
	}
	
	if (!this._tabs) {
		this._tabs = [];
		if (!tabs) {
			return;
		}
		
		for (var ii=0; ii < tabs.length; ii++) {
			var tab = new CognosTab(tabs[ii], this, ii);
			this._tabs.push(tab);
		}
	}
};

CognosTabControl.prototype.getScrollPos = function() { 
	return this._wrapperDiv.scrollLeft;
};

CognosTabControl.prototype.scrollTo = function(scrollPos) {
	this._wrapperDiv.scrollLeft = scrollPos;
	this.updateScrollButtons();
};

/**
	Handles the window resize event to show/hide the scroll buttons
**/
CognosTabControl.prototype.onResize = function(evt) {
	if (this._wrapperDiv.offsetWidth < this._totalWrapperWidth) {
		this._showScrollButtons();
		this.updateScrollButtons();	
		if (this._selectedTab) {
			this._selectedTab.scrollIntoView();
		}
		
		if (this._scrollRightButton.isDisabled()) {
			this.scrollTo(this.getMaxRightScroll());
		}
	}
	else {
		this._hideScrollButtons();
		this.scrollTo(0);
	}
};

CognosTabControl.prototype._showScrollButtons = function() {
	if (this._scrollButtonsVisible) {
		return;
	}

	if (!this._scrollLeftButton) {
		var wrapperDivHeight = 0;
		if (this._tabs[0]) {
			wrapperDivHeight = this._tabs[0].getHeight();
		}
		
		this._scrollLeftButton = new CognosScrollButton("left", wrapperDivHeight, this);
		this._scrollLeftButton.render(this._topContainer);
		
		this._scrollRightButton = new CognosScrollButton("right", wrapperDivHeight, this);
		this._scrollRightButton.render(this._topContainer);		
	}
	
	this._scrollButtonsVisible = true;
	
	this._scrollLeftButton.show();
	this._scrollRightButton.show();
	
	this._tabControlNode.style.left = this._scrollLeftButton.getWidth() - 2 + "px";
};

CognosTabControl.prototype.updateScrollButtons = function() {
	if (this._scrollLeftButton) {
		this._scrollLeftButton.update();
	}
	
	if (this._scrollRightButton) {
		this._scrollRightButton.update();
	}
};

CognosTabControl.prototype._hideScrollButtons = function() {
	if (!this._scrollButtonsVisible) {
		return;
	}
	
	this._scrollButtonsVisible = false;
	
	this._tabControlNode.style.left = "0px";

	this._scrollLeftButton.hide();
	this._scrollRightButton.hide();	
};

/**
	Creates the line seperator that's either above or below the tabs
**/
CognosTabControl.prototype._createSeperator = function() {
	this._seperator = document.createElement("div");
	this._seperator.setAttribute("role", "presendation");
	this._seperator.setAttribute("style", "");
	this._seperator.className = "ct_verticalLine";
	this._seperator.setAttribute("role", "presentation");
	this._tabControlNode.appendChild(this._seperator);
};

/**
	Selects one tab while making sure all the other tabs are unselected
**/
CognosTabControl.prototype.selectTab = function(tabId, userInvokved, evt) {	
	if (!evt) {
		evt = window.event;
	}
	
	for (var i=0; i < this._tabs.length; i++) {
		var tab = this._tabs[i];
		var isSelected = tab.getId() == tabId;
		
		tab.select(isSelected);
		
		if (isSelected) {
			this._selectedTab = tab;
			if (userInvokved && this._callback) {
				this._callback(tabId);
			}
		}

		if (userInvokved) {
			tab.focus(isSelected);
		}
	}
	
	if (evt && window.stopEventBubble) {
		window.stopEventBubble(evt);
	}
	
	return false;
};

CognosTabControl.prototype.handleKeyDown = function(evt, position) {
	if (!evt) {
		evt = window.event;
	}
	
	if (!evt) {
		return;
	}
	if (evt.keyCode == "39" || evt.keyCode == "37") {
		if (evt.keyCode == "39") { // left arrow
			position++;
			if (position >= this._tabs.length) {
				position = 0;
			}
		}
		else {
			position--;
			if (position < 0) {
				position = this._tabs.length-1;
			}		
		}
		
		this._tabs[position].focus();
		this._tabs[position].scrollIntoView();
	}
	else if (evt.keyCode == "32" || evt.keyCode == "13") { // space or enter
		var tabId = this._tabs[position].getId();
		this.selectTab(tabId, true);
	}
	
};

/** 
	Class that handles one tab in the tabControl
**/
function CognosTab(tabInfo, tabControl, position) {
	if (!tabInfo) {
		return;
	}
	this._id = tabInfo.id;
	this._label = tabInfo.label;
	this._position = position;
	this._contentClassName = tabInfo.className;
	this._imgURL = tabInfo.img;
	this._selected = false; 
	this._tabControl = tabControl;
	this._outerTabDiv = null;
	this._focusDiv = null;
}

CognosTab.prototype.getWidth = function() {
	return this._outerTabDiv.offsetWidth + 1;
};

CognosTab.prototype.getHeight = function() {
	return this._outerTabDiv.clientHeight;
};

CognosTab.prototype.getId = function() {
	return this._id;
};

/**
	Either selects or deselects the tab
**/
CognosTab.prototype.select = function(selected) {
	if (selected != this._selected) {
		this._selected = selected;
		if (selected) {			
			this.scrollIntoView();
		}
		if (this._outerTabDiv) {
			this._updateSelectedClass();
			this._updateAriaSelected();		
		}
	}
};

/**
	Scroll the tab into view if necessary
**/
CognosTab.prototype.scrollIntoView = function() {
	var tabRightCoord = this._outerTabDiv.offsetLeft + this._outerTabDiv.clientWidth;
	var scrollLength = this._tabControl.getVisibleWidth();
	var mainScrollPos = this._tabControl.getScrollPos();
	var tabOffsetLeft = this._outerTabDiv.offsetLeft;

	if (tabOffsetLeft === 0) {
		this._tabControl.scrollTo(0);
	}
	else if ( (tabOffsetLeft >= mainScrollPos) && (tabRightCoord <= (mainScrollPos + scrollLength))) {
		// If the tab is already visible don't move the scroll position
	}
	else if (tabOffsetLeft < mainScrollPos) {
		var scrollTo = tabOffsetLeft < 3 ? 0 : tabOffsetLeft - 3;
		this._tabControl.scrollTo(scrollTo);
	}
	else if (tabRightCoord - scrollLength > 0 || tabRightCoord < mainScrollPos) {
		this._tabControl.scrollTo(tabRightCoord - scrollLength + 10);
	}
};

/**	
	Renders a tab
**/
CognosTab.prototype.render = function(parentNode) {
	if (!this._outerTabDiv) {
		var tabId = this._id;
		var tabControl = this._tabControl;
		var tab = this;

		// Outer div
		this._outerTabDiv = document.createElement("div");
		this._outerTabDiv.onmousedown = function(event) { tabControl.selectTab(tabId, true, event); };
		this._outerTabDiv.onmouseover = function() { this.className = this.className + ' ct_highlight'; };
		this._outerTabDiv.onmouseout = function() { tab._updateSelectedClass(); };
		this._outerTabDiv.setAttribute("style", "");
		this._outerTabDiv.setAttribute("role", "presentation");
		this._updateSelectedClass();
		parentNode.appendChild(this._outerTabDiv);

		// This is the div that takes focus
		var textWrapperDiv = document.createElement("div");
		textWrapperDiv.className = "ct_content";
		textWrapperDiv.setAttribute("role", "presentation");
		this._outerTabDiv.appendChild(textWrapperDiv);
		
		// Tab text
		this._focusDiv = document.createElement("span");	
		this._focusDiv.innerHTML = this._label ? this._label : "&nbsp;";
		this._focusDiv.className = "ct_text";
		this._focusDiv.setAttribute("tabIndex", this._position === 0 ? "0" : "-1");
		this._focusDiv.setAttribute("role", "tab");
		
		this._focusDiv.onkeydown = function(event) {tabControl.handleKeyDown(event, tab._position);};
		this._updateAriaSelected();
		
		textWrapperDiv.appendChild(this._focusDiv);
		
		// Only needed in IE quirks mode since min-width doesn't work
		if (this.isIE() && this.getWidth() < 75) {
			this._outerTabDiv.style.width = "75px";
		}
		
	}
	else {
		this._updateSelectedClass();
		this._updateAriaSelected();
	}
};


CognosTab.prototype.isIE = function() {
	return (navigator.userAgent.indexOf('MSIE') != -1 || navigator.userAgent.indexOf('Trident') != -1);
};

CognosTab.prototype.getFocusableDiv = function() {
	return this._focusDiv;
};

CognosTab.prototype.focus = function(selected) {
	if (typeof selected === "undefined") {
		selected = true;
	}
	this._focusDiv.setAttribute("tabIndex", selected ? "0" : "-1");	
	if (selected && this._focusDiv.focus) {
		this._focusDiv.focus();
	}	
};

/**
	Update the css class attribute depending on if the tab is selected
**/
CognosTab.prototype._updateSelectedClass = function() {
	this._outerTabDiv.className = this._selected ? "ct_outerDiv ct_highlight ct_selected" : "ct_outerDiv";
};

/**
	Updated the aria-selected attribute
**/
CognosTab.prototype._updateAriaSelected = function() {
	this._focusDiv.setAttribute("aria-selected", this._selected ? "true" : "false");
};

function CognosScrollButton(direction, height, tabControl) {
	this._direction = direction;
	this._height = height;
	this._tabControl = tabControl;
	this._disabled = true;
	this._scrolling = false;
}

CognosScrollButton.prototype.getWidth = function() {
	return this._scrollButtonDiv.offsetWidth + 1;
};

CognosScrollButton.prototype.show = function() {
	this._wrapperDiv.style.display = "block";
};

CognosScrollButton.prototype.hide = function() {
	this._wrapperDiv.style.display = "none";
};

CognosScrollButton.prototype.update = function() {
	var wrapperDiv = this._tabControl.getWrapperDiv();
	var disableButton = false;
	if (this._direction == 'left') {
		if (wrapperDiv.scrollLeft === 0) {
			disableButton = true;
		}
	}
	else {
		if (wrapperDiv.scrollLeft >= (this._tabControl.getMaxRightScroll() - 2)) {
			disableButton = true;
		}
	}

	if (disableButton) {
		this._disable();
	}
	else {
		this._enable();
	}
};

CognosScrollButton.prototype.isDisabled = function() {
	return this._disabled;
};

CognosScrollButton.prototype._disable = function() {
	this._disabled = true;
	this._outerDiv.className = "ct_outerDiv ct_scrollDisabled";
};

CognosScrollButton.prototype._enable = function() {
	this._disabled = false;
	this._outerDiv.className = "ct_outerDiv ct_scrollEnabled";
};

CognosScrollButton.prototype.scroll = function() {
	if (!this._scrolling) {
		this._scrolling = true;
		var scrollLength = this._tabControl.getWrapperDiv().clientWidth;
		this._doAnimateScroll(scrollLength, this._tabControl.getMaxRightScroll());
	}
};

CognosScrollButton.prototype._doAnimateScroll = function(scrollLength, maxRightScroll) {
	if (scrollLength > 0) {
		var scrollOffset = 10;
		
		var wrapperDiv = this._tabControl.getWrapperDiv();
		if (this._direction == 'left') {
			if (wrapperDiv.scrollLeft > scrollOffset) {
				this._tabControl.scrollTo(wrapperDiv.scrollLeft - scrollOffset);
			}
			else {
				this._tabControl.scrollTo(0);
				this._scrolling = false;
				return;
			}
		}
		else {
			if (wrapperDiv.scrollLeft + scrollOffset < maxRightScroll) {
				this._tabControl.scrollTo(wrapperDiv.scrollLeft + scrollOffset);
			}
			else {
				this._scrolling = false;
				this._tabControl.scrollTo(maxRightScroll);
				this._tabControl.updateScrollButtons();
				return;
			}
		}
		scrollLength -= scrollOffset;
		
		var scrollButton = this;
		setTimeout(function() { scrollButton._doAnimateScroll(scrollLength, maxRightScroll);}, 3);
	}
	else {
		this._scrolling = false;
		this._tabControl.updateScrollButtons();
	}
};


CognosScrollButton.prototype.isIE = function() {
	return (navigator.userAgent.indexOf('MSIE') != -1 || navigator.userAgent.indexOf('Trident') != -1);
};

CognosScrollButton.prototype.render = function(parentNode) {
	this._scrollButtonDiv = document.createElement("div");
	this._scrollButtonDiv.className = "ct_scrollButton";
	var offset = -1;
	if (this.isIE() && document.compatMode != 'CSS1Compat') {
		// Only needed until we support standards mode. Once we do this work-around for
		// proper alignment can be removed
		offset = 1;
	}
	this._scrollButtonDiv.style.height = this._height + offset + "px";
	
	if (this._tabControl.isHighContrast()) {
		this._scrollButtonDiv.innerHTML = this._direction == "left" ? "&laquo;" : "&raquo;";
	}
	
	this._outerDiv = document.createElement("div");
	
	this._outerDiv.className = "ct_scrollDisabled";
	this._outerDiv.appendChild(this._scrollButtonDiv);
	this._outerDiv.style.height = this._height + "px";
	var scrollButton = this;
	this._outerDiv.onclick = function() {scrollButton.scroll();};

	this._wrapperDiv = document.createElement("div");
	this._wrapperDiv.style.height = this._height + "px";
	this._wrapperDiv.className = "ct_scroll " + (this._direction == "left" ? "ct_left" : "ct_right") + (this._tabControl.isHighContrast() ? " a11y" : "");
	this._wrapperDiv.appendChild(this._outerDiv);

	if (this._direction == "left") {
		parentNode.insertBefore(this._wrapperDiv, parentNode.firstChild);
		this._wrapperDiv.style.left = "0px";
	}
	else {
		parentNode.appendChild(this._wrapperDiv);		
		this._wrapperDiv.style.right = "0px";
	}
};