function CountSystem() {
	//set timeout
	this.pageControllers = {};
	this.activePage = '';
	this.initGUI();
	this.locked = false;
	this._buttonLock = false;
	this.mainActionURL = '/CS.do';
	this._errorHandlerStack = new Array(); 
}


/**
 * 
 * This one handles all DWR errors
 * 
 */
function _errh(msg){
	CountSystem.clearCursor();
	try{
		var handlerObj = CountSystem.getInstance().getRegisteredErrorHandlerObject();
		if(handlerObj){handlerObj.handleError(msg);}
	}catch(e){
		alert(msg);	
	}
}

CountSystem.getInstance = function() {
	if (!CountSystem.instance) {
		CountSystem.instance = new CountSystem();
	}
	return CountSystem.instance;
}

CountSystem.prototype.initGUI = function() {
	
	DWREngine.setErrorHandler(_errh);
	DWREngine.setTimeout(10000);

}

CountSystem.prototype.getRegisteredErrorHandlerObject = function() {
	return this._errorHandlerStack.last();
}

CountSystem.prototype.setRegisteredErrorHandlerObject = function(obj) {
	if(obj){
		this._errorHandlerStack.push(obj);
	}
}

CountSystem.prototype.releaseRegisteredErrorHandlerObject = function() {
	this._errorHandlerStack.pop();
}

CountSystem.prototype.clearRegisteredErrorHandlerObjects = function() {
	this._errorHandlerStack.clear();
}


CountSystem.prototype.getClientsOptions = {
	callback:function(data) {
			if (data){
				CountSystem.getInstance().createAtiraMenu(data)
			}
		},
	errorHandler:function(message) {  }
}

CountSystem.prototype.createAtiraFloatingLoader = function(data){
	
	var atiraLoader = new Atira.FloatingLoader('tile_body', 'load_indicator', false);
	return atiraLoader;

}

CountSystem.prototype.createDevelopmentToolbar = function(){
	var toolbar = new Atira.DevelopmentToolbar('toolbar_placeholder');
	return toolbar;
}

CountSystem.prototype.changeClient = function(id) {
	if(id){
		new Ajax.Request(this.mainActionURL, {asynchronous:true, method:'post', onComplete:this.postClientChange, postBody:'method=changeClient&id='+id});
	}
}

CountSystem.prototype.postClientChange = function() {
	
	CountSystem.getInstance().preAwake();
}

CountSystem.prototype.changeTab = function(id) {
	this.tabLoaderStart(id);
}

CountSystem.prototype.setBodyMode = function(mode) {
	var body = document.getElementById('tile_body');
	
	if(body){
		if(!mode){
			document.getElementById('body_topspace').style.display = 'none';
			document.body.style.minWidth = '930px';
			body.className = 'body_container';
		}else if(mode == 'wide'){
			document.getElementById('body_topspace').style.display = 'block';
			document.body.style.minWidth = '930px';
			body.className = 'body_container_wide_and_topspace';
		}else if(mode == 'topspace'){
			document.getElementById('body_topspace').style.display = 'block';
			document.body.style.minWidth = '930px';
			body.className =  'body_container_topspace';
		}
	}
}


CountSystem.prototype.doChangeTab = function(id) {
	
	if(!this.locked){
		this.locked = true;
		
		var action = this.mainActionURL;
		
		// protect against multi-changes
		if (this.activeChange == null) {
			this.activeChange = id; 
			var options = {
				asynchronous:true,
				method:'post',
				evalScripts:true,
				postBody:'method=changeTab&id='+id,
				onComplete:function() {
					CountSystem.getInstance().postChangePage();
				},
				onLoading:function() {
					//noop
				}
				
			};	
			
			// FIXME: ?
			this.toggler.setSelected(id);
			new Ajax.Updater('tile_body', action, options);
			
		} else {
			this.activeChange = id; 
		}
	
	}
}


CountSystem.prototype.changePage = function(url) {
	
	if(!this.locked){
		this.locked = true;
		this.pageLoaderStart();
	
		var options = {
			asynchronous:true,
			method:'post',
			evalScripts:true,
			onComplete:function() {
				CountSystem.getInstance().postChangePage();
			},
			onLoading:function() {
					//noop
			}
			
		};	
		new Ajax.Updater('tile_body', url, options);
		
	}
}

CountSystem.prototype.postChangePage = function() {
	
	this.updateActivePageName();
	this.preAwake();
}


CountSystem.prototype.preAwake = function() {	
	this.loader.show();
	
	this.clearRegisteredErrorHandlerObjects();
	this.setRegisteredErrorHandlerObject(this.getPageController());
	this.getPageController().clearError();
	
	this._currentAwakeCallback = 0;
	this._awakeCallbacks = this.getPageController().getNumberOfCallbacks();
	this.getPageController().awake();
}

CountSystem.prototype.awakeCallback = function(clearAll) {	
	this._currentAwakeCallback ++;
	
	//done loading?
	if(clearAll || this._awakeCallbacks >= this._currentAwakeCallback){
		
		this.getPageController().drawCurvy();
		this.activeChange = null;
		this.loader.hide();
		this.locked = false;
		this._buttonLock = false;
	}

}

CountSystem.lb = function() {
	CountSystem.getInstance()._buttonLock = true;
	document.body.style.cursor = "wait";
	try{
		setTimeout("CountSystem.lboff()", 100);
	}catch(e){
		//noop
	}
}

CountSystem.clearCursor = function() {
	document.body.style.cursor = "auto";
}

CountSystem.lboff = function() {
	CountSystem.getInstance()._buttonLock = false;
}	
	
CountSystem.isLocked = function() {
	return CountSystem.getInstance()._buttonLock;
}

CountSystem.prototype.tabLoaderStart = function(id) {
	this.loader.show(id);
}

CountSystem.prototype.pageLoaderStart = function(id) {
	this.loader.show();
}

CountSystem.prototype.getPageController = function() {
	var c = this.pageControllers;
	if (!c[this.activePage]) {
		c[this.activePage] = Page.createController(this.activePage);
	}
	return this.pageControllers[this.activePage];
}

CountSystem.prototype.updateActivePageName = function(p) {
	if(p){
		this.activePage = p;
	}else{
		alert("active page is not defined");
	}
}

//INSERTER UTIL
CountSystem.insert = function(elmId, value){
	if(elmId){ 
		if(value){
			var elm = document.getElementById(elmId);
			if(elm){
				elm.innerHTML = value;
			}		
		}else{
			var elm = document.getElementById(elmId);
			if(elm){
				elm.innerHTML = "";
			}
		}
	}
};

//CLEAR UTIL
CountSystem.clearInnerHTML = function(elmId){
	if(elmId){
		var elm = document.getElementById(elmId);
		if(elm)elm.innerHTML = '';
	}
};

//EXTRACTER UTIL
CountSystem.extract = function(elmId){
	if(elmId){
		var elm = document.getElementById(elmId);
		if(elm)return elm.value;
	}
	return null;
};

//INPUT UTIL
CountSystem.input = function(elmId, value, disabl){
	if(elmId && value){
		var elm = document.getElementById(elmId);
		if(elm){
			elm.value = value;
			if(disabl){
				elm.readOnly = true;
			}else{
				elm.readOnly = false;
			}
		}
	}
};

//CLEAR INPUT UTIL
CountSystem.clearInput = function(elmId){
	if(elmId){
		var elm = document.getElementById(elmId);
		if(elm.value){
			elm.value = null;
		}
	}
};

//VISIBILITY TOGGLER UTIL
CountSystem.toggleHTML = function(elmId){
	if(elmId){
		var elm = document.getElementById(elmId);
		if(elm){
			if(!elm.style.display || elm.style.display == 'none'){
			 	elm.style.display = 'block';
			}else{
			 	elm.style.display = 'none';
			}
		}
	}
};

//VISIBILITY TOGGLER UTIL
CountSystem.showHTML = function(elmId){
	if(elmId){
		var elm = document.getElementById(elmId);
		if(elm){
			elm.style.display = 'block';
		}
	}
};

//VISIBILITY TOGGLER UTIL
CountSystem.hideHTML = function(elmId){
	if(elmId){
		var elm = document.getElementById(elmId);
		if(elm){
			elm.style.display = 'none';
		}
	}
};

//CALCULATOR UTIL
CountSystem.multiply = function(id1, id2){
	if(id1 && id2){
		var value1 = CountSystem.extract(id1); 
		var value2 = CountSystem.extract(id2);
		
		if(!(typeof(value1) == 'number')){
			value1 = CountSystem.removeCommas(value1);		
		}
		
		if(!(typeof(value2) == 'number')){
			value2 = CountSystem.removeCommas(value2);		
		}
		
		if(!isNaN(value1) && !isNaN(value2)){
			var result = value1 * value2;
			return result;
		}
		return 'n/a';
	}
	return 'n/a';
}

CountSystem.renderPointAndFigureReSTLink = function(data, onDate, showPnfIcon) {
		var html = '';
		if(data){
			var shareName = data;
			html+= '<div class="link"><a onclick="Atira.DevelopmentToolbar.pu(\'/faces/admin/candlestick/'+shareName+'\', 930, 620, false);">'+shareName+'</a></div>';
			//html+= '<div class="link"><a onclick="Atira.DevelopmentToolbar.pu(\'/faces/admin/pnf/'+shareName+'\', 885, 705, true);">'+shareName+'</a></div>';
			if(showPnfIcon){
				html+= '<div class="icon_pnf_chart" onclick="Atira.DevelopmentToolbar.pu(\'/faces/admin/pnf/'+shareName+'\', 885, 705, true);"></div>';
			}else{
				html+= '<div class="icon_no_pnf_chart" ></div>';
			}
		}
		return html;
}

CountSystem.renderPointAndFigureIcon = function(data, displayedText) {
	var html = '';
	if(data){
		var shareName = data;
		html+= '<div class="icon_pnf_chart" onclick="Atira.DevelopmentToolbar.pu(\'/faces/admin/pnf/'+shareName+'\', 885, 705, true);"></div>';
		html+= '<a style="vertical-align: top;font-weight:bold; margin-left:6px;" onclick="Atira.DevelopmentToolbar.pu(\'/faces/admin/pnf/'+shareName+'\', 885, 705, true);">'+displayedText+'</a>';
	}
	return html;
}

CountSystem.renderUserReSTLink = function(data) {
		var html = '';
		if(data){
			var userid = data[0];
			var fullname = data[1];
			html+= '<a href="/faces/admin/user/'+userid+'">'+fullname+'</a>';
		}
		return html;
}

/**
* this function creates a popup window
*/
function pu(url, width, height, usescroll, callback) {		
      
      var scroll = 'no';
      if(usescroll){
      	scroll= 'yes';
      }
      
      var name = "Popup";

      var callerFrame = window;

      var style = "toolbar=no,location=no,directories=no,statusbar=no,menubar=no,scrollbars="+ scroll + ",resizable=yes,width=" + width + ",height=" + height;

      var x = (screen.width - width) / 2;
      var y = (screen.height - height) / 2;

      var notSeenX = screen.availWidth - (x + width);
      var notSeenY = screen.availHeight - (y + height);

      if (notSeenX < 0) x += (notSeenX - 20); if (x < 0) x = 0;
      if (notSeenY < 0) y += (notSeenY - 30); if (y < 0) y = 0;

      style += ",left=" + x + ",top=" + y;

      var openWin = callerFrame.open (url, "popup", style);

	  openWin.onCallback = callback; 

      openWin.focus();
    
      return;
}

//debug util
function printObject(object) {
	obj = eval(object);
	var temp = "";
	for (x in obj)
        temp += x + ": " + obj[x] + "\n";
	if(temp == "") alert(obj);
	else alert (temp);	
}

function printVars(object) {
	obj = eval(object);
	var temp = "";
	var dims = 0;
	for (x in obj)
        if(dims > 5) {
        	temp += x + "\n"; 
        	dims = 0;
        }else{
        	temp += x + ", "; 
        	dims ++;
        }
	alert (temp);	
}

function printFunctions(object, matchStr) {
	obj = eval(object);
	var temp = "";
	
	if(matchStr){
		for (x in obj)
        if(typeof(obj[x]) == 'function') {
        	
            if(x.match(matchStr)){
        		temp += x +  ": <function> \n"; 
        	}
        }
    }else{
    	for (x in obj)
        if(typeof(obj[x]) == 'function') {
        	temp += x +  ": <function> \n"; 
        }
    }
	alert (temp);	
}


//////////////////////////////////////// Generic page controller /////////////////////////////////

function Page() {
}

Page.createController = function(unique) {
	var className = unique.substr(0,1).toUpperCase()+unique.substr(1)+'Controller';
	try {
		return eval('new '+className+'()');
	} catch (e) {
		return new Page();
	}
}

Page.prototype.awake = function() {
	window.status = this;
	
}

Page.prototype.getNumberOfCallbacks = function() {
	return 0;
}

Page.prototype.toString = function() {
	return 'Generic controller';
	
}

Page.prototype.handleError = function(msg) {
	
	if(typeof(msg) == 'object'){
		//NOOP, perhaps we should handle this some other way
		//was put here to handle missing ids in the page. If you change page while a component is loading the async will try to render in a non-existing id
	}else{
		CountSystem.insert('body_error_container', msg);
	}
	CountSystem.getInstance().awakeCallback(true);
}

Page.prototype.clearError = function() {
	CountSystem.clearInnerHTML('body_error_container');
}

Page.renderLoader = function(){
	return '<div class="loading"></div>';
}

Page.renderWhiteLoader = function(){
	return '<div class="whiteloading"></div>';
}

//////////////////////////////////////// extra /////////////////////////////////


function attachAllEvents(div){

	div.onactivate = function() {alert('onactivate')};	
	div.onafterupdate = function() {alert('onafterupdate')};
	div.onbeforeactivate = function() {alert('onbeforeactivate')};
	div.onbeforecopy = function() {alert('onbeforecopy')};
	div.onbeforecut = function() {alert('onbeforecut')};
	div.onbeforedeactivate = function() {alert('onbeforedeactivate')};
	div.onbeforeeditfocus = function() {alert('onbeforeeditfocus')};
	div.onbeforepaste = function() {alert('onbeforepaste')};
	div.onbeforeupdate = function() {alert('onbeforeupdate')};
	div.onblur = function() {alert('onblur')};
	div.onclick = function() {alert('onclick')};
	div.oncontextmenu = function() {alert('oncontextmenu')};
	div.oncontrolselect = function() {alert('oncontrolselect')};
	div.oncopy = function() {alert('oncopy')};
	div.oncut = function() {alert('oncut')};
	div.ondblclick = function() {alert('ondblclick')};
	div.ondeactivate = function() {alert('ondeactivate')};
	div.ondrag = function() {alert('ondrag')};
	div.ondragend = function() {alert('ondragend')};
	div.ondragenter = function() {alert('ondragenter')};
	div.ondragleave = function() {alert('ondragleave')};
	div.ondragover = function() {alert('ondragover')};
	div.ondragstart = function() {alert('ondragstart')};
	div.ondrop = function() {alert('ondrop')};
	
	div.onerrorupdate = function() {alert('onerrorupdate')};
	div.onfilterchange = function() {alert('onfilterchange')};
	div.onfocus = function() {alert('onfocus')};
	div.onfocusin = function() {alert('onfocusin')};
	div.onfocusout = function() {alert('onfocusout')};
	div.onhelp = function() {alert('onhelp')};
	div.onkeydown = function() {alert('onkeydown')};
	div.onkeypress = function() {alert('onkeypress')};
	div.onkeyup = function() {alert('onkeyup')};
	div.onlayoutcomplete = function() {alert('onlayoutcomplete')};
	div.onlosecapture = function() {alert('onlosecapture')};
	
	/*
	div.onmousedown = function() {alert('onactivate')};
	div.onmouseenter = function() {alert('onactivate')};
	div.onmouseleave = function() {alert('onactivate')};
	div.onmousemove = function() {alert('onactivate')};
	div.onmouseout = function() {alert('onactivate')};
	div.onmouseover = function() {alert('onactivate')};
	div.onmouseup = function() {alert('onactivate')};
	div.onmousewheel = function() {alert('onactivate')};
	*/
	
	
	div.onmove = function() {alert('onmove')};
	div.onmoveend = function() {alert('onmoveend')};
	div.onmovestart = function() {alert('onmovestart')};
	div.onpaste = function() {alert('onpaste')};
	div.onpropertychange = function() {alert('onpropertychange')};
	div.onreadystatechange = function() {alert('onreadystatechange')};
	div.onresize = function() {alert('onresize')};
	div.onresizeend = function() {alert('onresizeend')};
	div.onresizestart = function() {alert('onresizestart')};
	div.onscroll = function() {alert('onscroll')};
	div.onselectstart = function() {alert('onselectstart')};
	div.ontimeerror = function() {alert('ontimeerror')};

}


CountSystem.parseDate = function(nStr){
	
	nStr += '';
	var x = nStr.split('-');
	var day = x[0];
	var month = CountSystem.monthToInt[x[1]];
	var year = x[2];
		
	var date = new Date();
	date.setDate(day);
	date.setMonth(month);
	date.setYear(year);
	date.setHours(0);
	date.setMinutes(0);
	date.setSeconds(0);
	date.setMilliseconds(0);

	return date;
}

CountSystem.createDateFromDayOfYear = function(year, dayOfYear) {
	if(dayOfYear){
		var date = new Date();
		if(year){
			date.setYear(year);
		}
		date.setMonth(0);
		date.setDate(dayOfYear);
		return CountSystem.formatToRestString(date);
	}
}

CountSystem.renderDate = function(str) {
	if(str){
	var date = new Date(str);
	return date.toDateString();
	}else{
		return 'n/a';
	}
}

CountSystem.formatDate = function(date){
	var _date = new Date(date);
	return _date.getDate()+'-' + CountSystem.months[_date.getMonth()] + '-' + _date.getFullYear();
}

CountSystem.formatToRestString = function(date){
	var tmp = date.getFullYear();
	tmp += "-" + (date.getMonth()+1);
	tmp += "-" + date.getDate();
	return tmp;
}

CountSystem.formatCurrency = function(num, decimals){
	var fixed = decimals || 2;
	if(typeof(num) == 'number'){return CountSystem.addCommas(num.toFixed(fixed));}
	return num;
}

CountSystem.formatInteger = function(num){
	if(typeof(num) == 'number'){return CountSystem.addCommas(num.toFixed(0));}
	return num;
}

CountSystem.formatPercent = function(num){
	if(num){
		var perc = CountSystem.addCommas(num * 100);
		return perc + '%';
	}
	return 'n/a';
}


CountSystem.addCommas = function(nStr){
	nStr += '';
	var x = nStr.split('.');
	var x1 = x[0];
	var x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
}

CountSystem.removeCommas = function(nStr){
	nStr += '';
	var result = '';
	var x = nStr.split(',');
	
	for(var i = 0; i<x.length;i++){
		result += x[i];
	}	
	
	return result;
}
CountSystem.months = [
	"Jan", "Feb", "Mar", "Apr",
	"May", "Jun", "Jul", "Aug",
	"Sep", "Oct", "Nov", "Dec"];

CountSystem.monthToInt = {
	"Jan":0, "Feb":1, "Mar":2, "Apr":3,
	"May":4, "Jun":5, "Jul":6, "Aug":7,
	"Sep":8, "Oct":9, "Nov":10, "Dec":11};
	
	
var events = {
		 
		NOOP :				 		{text:''}
		
		,PLACE_BUY :				{text:'Place buy order for', 	hideshares: false, text_edit: '', label: ''}
		,PLACED_BUY :				{text:'Placed buy order for',	hideshares: false, text_edit: '<b>Placed buy order</b> for', label: '<b>Placed buy order</b>'}
		 
		,PLACE_SELL :				{text:'Place sell order for',	hideshares: false, text_edit: ''}
		,PLACED_SELL :				{text:'Placed sell order for',	hideshares: false, text_edit: '<b>Placed sell order</b> for', label: '<b>Placed sell order</b>'}
		
		,ADJUST :					{text:'Adjust to',				hideshares: false, text_edit: '', label: ''}
		,ADJUSTED:					{text:'Adjusted to',			hideshares: false, text_edit: 'Adjusted to', label: '<b>Adjusted</b>'}
		
		,CANCEL :					{text:'Cancel',					hideshares: false, text_edit: '', label: ''}
		,CANCELED :					{text:'Canceled',				hideshares: false, text_edit: '', label: ''}
		
		,CONSIDER :					{text:'Consider',				hideshares: false, text_edit: '', label: ''}
		,CONSIDERED_CONTINUE :		{text:'Continued monitoring',	hideshares: false, text_edit: 'Continued monitoring', label: '<b>Continued monitoring</b>'}
		
		,BOUGHT : 					{text:'Bought',					hideshares: false, text_edit: '<b>Bought</b>', label: '<b>Bought</b>'}
		,SOLD :						{text:'Sold',					hideshares: false, text_edit: '<b>Sold</b>', label: '<b>Sold</b>'}
	
		,SMALL_MARGIN :				{text:'',						hideshares: false, text_edit: '', label: ''}
		,SMALL_MARGIN_END :			{text:'',						hideshares: false, text_edit: '', label: ''}
		
		,NO_BUY_ORDER_PLACED :		{text:'',						hideshares: false, text_edit: '', label: ''}
		
		,ERROR :					{text:'',						hideshares: false, text_edit: '', label: ''}
	
		,WAS_IT_BOUGHT :			{text:'',						hideshares: false, text_edit: '', label: ''}
		,WAS_IT_SOLD :				{text:'',						hideshares: false, text_edit: '', label: ''}

		,BONUS_RIGHTS :				{text:'Bonus rights',			hideshares: false, text_edit: '<b>Bonus rights</b>', label: '<b>Bonus rights</b>'}
		,DIVIDEND :					{text:'Dividend',				hideshares: true, text_edit: '<b>Dividend</b>', label: '<b>Dividend</b>'}
		 
	};