var debug = {
	enabled: false,
	log: function(log){
		if (this.enabled){
			var ie = /*@cc_on!@*/false;

			if (!ie){
				if (typeof console !== "undefined"){
					console.log(log);
				}
			}
		}
	}
}

/* Updater */

var Updater = (function(){

	"use strict";

	//Private section

	var queue = [];
	var transaction = [];
	var gcd = 1;
	var round = 0;
	var interval = 0;
	var url = '?update';

	function tick(){
		round += gcd;
		transaction = [];

		if (round){
			for (var i = 0, len = queue.length; i < len; i++){
				if (!(round % queue[i].context.period)){
					transaction.push({
						stamp: '' + new Date().getTime() + parseInt(Math.random() * 1000000),
						obj: queue[i]
					});
				}
			}
		}

		send();
	}

	function send(){
		var request = [];
		var xhr = getXHR();

		for (var i = 0, len = transaction.length; i < len; i++){
			request.push({
				stamp: transaction[i].stamp,
				name: transaction[i].obj.name,
				event: transaction[i].obj.context.event,
				params: transaction[i].obj.context.params
			});
		}

		xhr.onreadystatechange = function(){
			if (xhr.readyState == 4 && xhr.status == 200){
				var response = eval('(' + xhr.responseText + ')');

				for (var stamp in response){
					for (var i = 0, len = transaction.length; i < len; i++){
						if (transaction[i].stamp == stamp){
							switch (response[stamp].status){
								case 'error':
									transaction[i].obj.context.error(response[stamp].result);
									break;
								default:
									transaction[i].obj.context.ok(response[stamp].result);
									break;
							}

							transaction.splice(i, 1);
							break;
						}
					}
				}
			}
		}

		xhr.open('POST', url, true);
		xhr.send(JSON.stringify(request));
	}

	function getXHR(){
		if (typeof XMLHttpRequest === 'undefined'){
			XMLHttpRequest = function(){
				try {
					return new ActiveXObject('Msxml2.XMLHTTP.6.0');
				} catch (e){}
				try {
					return new ActiveXObject('Msxml2.XMLHTTP.3.0');
				} catch (e){}
				try {
					return new ActiveXObject('Msxml2.XMLHTTP');
				} catch (e){}
				try {
					return new ActiveXObject('Microsoft.XMLHTTP');
				} catch (e){}
			}
		}

		return new XMLHttpRequest();
	}

	function getGCD(x, y){
		var z;

		while (y){
			z = x % y;
			x = y;
			y = z;
		}

		return x;
	}

	//Public section

	return {
		exec: function(name, context){
			for (var i = 0, len = context.length; i < len; i++){
				var obj = {
					name: name,
					context: context[i]
				};

				if (context[i].period){
					this.init(obj);
					debug.log(name + ' registered')
				} else {
					transaction.push({
						stamp: '' + new Date().getTime() + parseInt(Math.random() * 1000000000),
						obj: obj
					});
					debug.log(name + '.' + obj.context.event + ' sent');
				}
			}

			if (transaction.length){
				send();
			}
		},

		init: function(obj){
			if (interval) {
				clearInterval(interval);
			}

			queue.push(obj);

			switch (queue.length){
				case 1:
					gcd = obj.context.period;
					break;
				default:
					gcd = getGCD(gcd, obj.context.period);
					break;
			}

			interval = setInterval(function(){
				tick();
			}, gcd * 1000);
		}
	}
})();

/* Market Leaders */

var updateMarketLead = {
	ok: function(block_ident, response){
			try {
				var data = eval('(' + response + ')');
			} catch (e) {
				debug.log(block_ident + ' update: bad data');
				return;
			}

			for (var leader in data){
				switch (leader){
					case 'high_leaders':
						var rows = $('#' + block_ident).find('#high_leaders table.indexes tr');

						for (var i = 0, len = data[leader].length; i < len; i++){
							var row = rows.eq(i);

							row.find('td:eq(0)').find('div.text a').text(data[leader][i].ticker).attr('title', data[leader][i].title);
							row.find('td:eq(1)').text(data[leader][i].znach);
							row.find('td:eq(2)').text(data[leader][i].izm + '%');
						}
						break;
					case 'low_leaders':
						var rows = $('#' + block_ident).find('#low_leaders table.indexes tr');

						for (var i = 0, len = data[leader].length; i < len; i++){
							var row = rows.eq(i);

							row.find('td:eq(0)').find('div.text a').text(data[leader][i].ticker).attr('title', data[leader][i].title);
							row.find('td:eq(1)').text(data[leader][i].znach);
							row.find('td:eq(2)').text(data[leader][i].izm + '%');
						}
						break;
					case 'time':
						$('#' + block_ident).find('table.links p.link').eq(0).text('Данные на ' + data[leader]);
						break;
				}
			}

			debug.log(block_ident + ' update: ok');
	},
	error: function(block_ident, response){
		debug.log(block_ident + ' update: service error');
	}
}

/* My Indicators */

var updateMyInd = {
	ok: function(block_ident, response){
			try {
				var data = eval('(' + response + ')');
			} catch (e) {
				debug.log(block_ident + ' update: bad data');
				return;
			}

			var rows = $('#' + block_ident + ' .indexes tr');

			for (var i = 0, len = data.length; i < len; i++){
				var row = rows.eq(i);
				var color = data[i].color;

				row.find('td:eq(0)').removeClass('minus plus green red').addClass(color);
				row.find('td:eq(2)').html(data[i].time);
				row.find('td:eq(3)').html(data[i].value);
				row.find('td:eq(4)').removeClass('minus plus green red').addClass(color).html('<nobr>' + data[i].ch_value + '%</nobr>');
			}

			debug.log(block_ident + ' update: ok');
	},
	error: function(block_ident, response){
		debug.log(block_ident + ' update: service error');
	}
}

/* Stock Rates */

var updateStockRates = {
	init: function(block_ident, context){
		tabsNavigation('#' + block_ident);
		$("#" + block_ident + " ul.tabs li a").click(function() {
			context.params.url = 'update/' + $('#' + block_ident + " .tabs .current").attr('id');
			debug.log(context.params.url);
		});
	},
	ok: function(block_ident, response){
			try {
				var data = eval('(' + response + ')');
			} catch (e) {
				debug.log(block_ident + ' update: bad data');
				return;
			}

			for (var pane in data){
				var rows = $('#' + block_ident).find('div.pane.' + pane + ' .indexes tr');

				for (var i = 0, len = data[pane].length; i < len; i++){
					var row = rows.eq(i);
					var color = data[pane][i].color;

					row.find('td:eq(0)').removeClass('green red').addClass(color);
					row.find('td:eq(2)').html(data[pane][i].time);
					row.find('td:eq(3)').html(data[pane][i].value);
					row.find('td:eq(4)').removeClass('green red').addClass(color).html('<nobr>' + data[pane][i].ch_value + '%</nobr>');
				}
			}

			debug.log(block_ident + ' update: ok');
	},
	error: function(block_ident, response){
		debug.log(block_ident + ' update: service error');
	}
}

/* Market Map */
var marketMap;
var updateMarketMap = {
	init: function(marketMapData){

		// Класс "Карта рынка"
		window.equote.MarketMap = function(histogramTableSelector, companiesTableSelector) {

			// Свойство - данные по Карте рынка
			this.data = function(value) {
				if (value == undefined) {
					return this._data;
				};
				this._data = value;
				this._updateView();
			};

			// Свойство - номер текущей закладки (номер первой закладки = 0)
			this.currentIndex = function(value) {
				if (value == undefined) {
					return this._currentIndex;
				}
				this._currentIndex = value;
				this._updateView();
			};

			// Обработчик клика на вкладку
			this.tabClickHandler = function(index) {
				if (this._currentIndex != index) {
					// Если кликнули по другой вкладке, выбираем её
					this.currentIndex(index);
				} else {
					// Если кликнули по той же вкладке
					try {
						var ticker = this._data[index].ticker;
						var url = "http://stock.rbc.ru/online/rusindex.0/intraday/" + ticker + ".rus.shtml?show=intra3";
						window.open(url,'_blank');
					} catch(e) {
					}
				}
			};

			// Приватные члены
			this._histogramTableSelector = histogramTableSelector;
			this._companiesTableSelector = companiesTableSelector;
			this._data = new Array;
			this._currentIndex = 0;
			this._tableRowCount = 3; // Константа - количество строк в таблице с гистограммами

			// Обновляет данные в блоке
			this._updateView = function() {
				try {
					if (this._data.length < 1) {
						throw "Отсутствуют отрасли";
					}
					// Корректируем номер закладки, если это необходимо
					var industryIndex = this._currentIndex;
					if ((industryIndex < 0) || (industryIndex > this._data.length - 1)) {
						industryIndex = 0;
					}

					// Шаблонизация и отображение отраслевых гистограмм
					var histogramData = {data:this._buildHistogramData(this._data), currentIndex:industryIndex};
					var histogramBody = $("#indices_table_template").tmpl(histogramData);
					$(this._histogramTableSelector).html(histogramBody);

					// Сортировка данных по компаниям по P/E, если они ещё не отсортированы
					this._data[industryIndex].companies.sort(this._compareCompanies);
					// Шаблонизация и отображение данных по компаниям
					var companiesData = {data:this._data[industryIndex].companies};
					var companiesContent = $("#companies_table_template").tmpl(companiesData);
					$(this._companiesTableSelector).html(companiesContent);

					// Устанавливаем обработчик клика на гистограмму
					for (var r = 1; r <= this._tableRowCount; r++) {
						for (var i = 0; i < this._data.length; i++) {
							var selector = "#industry_" + r + "_" + i;
							$(selector).click(this._histogramClick);
						}
					}

					// Устанавливаем обработчик клика на названия компаний
					for (var c = 0; c < this._data[industryIndex].companies.length; c++) {
						var selector = "#company_" + this._data[industryIndex].companies[c].id_enterpise;
						$(selector).click(this._companyClick);
					}

					// Устанавливаем обработчики для подсветки строк
					// Аналогично механизму index.js (нужно переделать)
					$("table.selectable tbody tr").hover(
						function () {$(this).addClass("selected")},
						function () {$(this).removeClass("selected")}
					);

				} catch(e) {}
			};

			// Обработчик клика на гистограмму
			this._histogramClick = function() {
				var id = this.id;

				// Извлекаем номер гистограммы из id элемента, по которому кликнули
				for (var r = 1; r <= marketMap._tableRowCount; r++) {
					var subSelector = "industry_" + r + "_";
					var pos = id.indexOf(subSelector);
					if (pos >= 0) {
						var index = parseInt(id.slice(subSelector.length));
						if (!isNaN(index)) {
							// Нашли номер гистограммы. Устанавливаем его как текущий.
							marketMap.tabClickHandler(index);
							return;
						}
					}
				}
			};

			// Обработчик клика на название компании
			this._companyClick = function() {
				var id = this.id;
				var subSelector = "company_"
				var pos = id.indexOf(subSelector);
				if (pos >= 0) {
					var index = parseInt(id.slice(subSelector.length));
					if (!isNaN(index)) {
						var url = "http://quote.rbc.ru/fterm/emitent.shtml?" + index;
						window.open(url,'_blank');
					}
				}
				return false;
			};

			// Строит данные для шаблонизации отраслевых гистограмм
			this._buildHistogramData = function(indicesData) {
				var result = new Array;

				// Поиск наименьшего и наибольшего значений изменения
				var minChange = NaN;
				var maxChange = NaN;
				for (var i = 0; i < indicesData.length; i++) {
					var currentChange = indicesData[i].last_change_percent;
					if ((isNaN(minChange)) || (currentChange < minChange)) {
						minChange = currentChange;
					}
					if ((isNaN(maxChange)) || (currentChange > maxChange)) {
						maxChange = currentChange;
					}
				}

				// Вычисление диапазона значений изменения
				if (minChange > 0) {
					minChange = 0;
				}
				if (maxChange < 0) {
					maxChange = 0;
				}
				var range = maxChange - minChange;

				var rangeHeight = 85; // Константа - максимальная высота гистограмм - 85 пикселей

				// Заполнение массива гистограмм
				for (var i = 0; i < indicesData.length; i++) {
					var indicesItem = indicesData[i];

					// Высота гистограммы
					var height = (range > 0)?
						(Math.round(Math.abs(indicesItem.last_change_percent)*rangeHeight/range))
						:
						0;

					// Элемент массива данных
					var item = {
						id: indicesItem.id,
						html: indicesItem.html,
						last: indicesItem.last,
						last_change_percent: indicesItem.last_change_percent,
						topDisplay: (indicesItem.last_change_percent >= 0),
						bottomDisplay: (indicesItem.last_change_percent < 0) && (range > 0),
						height: height
					};
					result.push(item);
				}
				return result;
			};

			// Функция сравнения компаний для сортировки по P/E
			this._compareCompanies = function(company1, company2) {
				var veryBigNumber = 1000000;
				if (isNaN(company1.p_e)) {
					return veryBigNumber;
				}
				if (isNaN(company2.p_e)) {
					return -veryBigNumber;
				}
				return company2.p_e - company1.p_e;
			};
		};

		marketMap = new window.equote.MarketMap("#chart_table", ".companies_table_body");
		marketMap.data(marketMapData);
	},
	ok: function(block_ident, response){
		try {
			var data = eval('(' + response + ')');
		} catch (e) {
			debug.log(block_ident + ' update: bad data');
			return;
		}

		marketMap.data(data);
		debug.log(block_ident + ' update: ok');
	},
	error: function(block_ident, response){
		debug.log(block_ident + ' update: service error');
	}
};

/* Key Indicators */
var updateKeyInd = {
	init: function(block_ident, page_key_chart){
		var chart = $('<tr class="chart"><td colspan="5"><div id="' + block_ident + '_chart"></div></td></tr>');
		var key_ind = $('#' + block_ident + ' .key_ind tr.current');
		var hover;

		function refreshKeyIndicatorsChart(){
			var key_ind_chart = $('#' + block_ident + '_chart');
			var key_tr = key_ind_chart.parents('tr.chart');
			var key_meta = key_tr.prev().find('td:eq(1) a');
			var intraday = (key_meta.attr('has_intraday') == '1') ? '1:Day' : '1:Month';

			key_ind_chart.flash({
				id: 'chart_' + parseInt(Math.random() * 1000000, 10),
				swf: url_swf_object,
				width: '100%',
				height: 140,
				flashvars: {
					serverName: url_swf_server_name,
					initialSourceID: key_meta.attr('sourceid'),
					initialTickerID: key_meta.attr('tickerid'),
					clickReferences: key_meta.attr('href'),
					defaultPeriodCode: intraday,
					intradayUpdateRPS: 300,
					archiveRPS: 3600,
					navigateWindow: '_blank',
					showTabControl: false,
					distended: true
				}
			});
		}

		if (key_ind.hasClass('even')){
			chart.addClass('even');
		} else if (key_ind.hasClass('odd')){
			chart.addClass('odd');
		}

		key_ind.after(chart);

		$('#' + block_ident + ' .key_ind tr:not(current, chart)').hover(function(){
			var self = $(this);

			if (!(self.hasClass('chart') || self.hasClass('current'))){
				hover = setTimeout(function(){
					chart.prev().removeClass('current');
					self.addClass('current').after(chart);

					if (self.hasClass('even')){
						chart.addClass('even').removeClass('odd');
					} else if (self.hasClass('odd')){
						chart.addClass('odd').removeClass('even');
					}

					cookie.set(page_key_chart, self.attr("id"), 120, "/");
					refreshKeyIndicatorsChart();
				}, 250);
			}
		}, function(){
			if (hover){
				clearTimeout(hover);
			}
		}).find('a').focus(function(){
			var self = $(this);

			chart.prev().removeClass('current');
			self.parent().parent('tr').addClass('current').after(chart);
			if (self.parent().parent('tr').hasClass('even')){
				chart.addClass('even').removeClass('odd');
			} else if (self.parent().parent('tr').hasClass('odd')){
				chart.addClass('odd').removeClass('even');
			}
		});

		refreshKeyIndicatorsChart();
	},
	ok: function(block_ident, response){
			try {
				var data = eval('(' + response + ')');
			} catch (e) {
				debug.log(block_ident + ' update: bad data');
				return;
			}

			var rows = $('#' + block_ident + ' .key_ind tr:not(.chart)');

			for (var i = 0, len = data.length; i < len; i++){
				var row = rows.eq(i);
				var color = data[i].color;

				row.find('td:eq(0)').removeClass('minus plus green red').addClass(color);
				row.find('td:eq(2)').html(data[i].time);
				row.find('td:eq(3)').html(data[i].value);
				row.find('td:eq(4)').removeClass('minus plus green red').addClass(color).html('<nobr>' + data[i].ch_value + '%</nobr>');
			}

			debug.log(block_ident + ' update: ok');
	},
	error: function(block_ident, response){
		debug.log(block_ident + ' update: service error');
	}
};
/* Cash */

var updateCash = {
	ok: function(block_ident, response){
			try {
			var data = eval('(' + response + ')');
			} catch (e) {
				debug.log(block_ident + ' update: bad data');
				return;
			}

			$('#' + block_ident + ' .cash tr:eq(1) td.time').text(data.usd.time);
			$('#' + block_ident + ' .cash tr:eq(1) td.buy').text(data.usd.buy);
			$('#' + block_ident + ' .cash tr:eq(1) td.sell').text(data.usd.sell);

			$('#' + block_ident + ' .cash tr:eq(2) td.time').text(data.eur.time);
			$('#' + block_ident + ' .cash tr:eq(2) td.buy').text(data.eur.buy);
			$('#' + block_ident + ' .cash tr:eq(2) td.sell').text(data.eur.sell);

			debug.log(block_ident + ' update: ok');
	},
	error: function(block_ident, response){
		debug.log(block_ident + ' update: service error');
	}
}
