/* ГАДЖЕТ ПРОГНОЗОВ ПОГОДЫ */
function __Weather(id)
{
	this.lang = Locale.Gadgets.Weather;
	this.Core = new __StdModuleCore(this, id, 'weather2', this.lang.title, this.lang.desc);

	this.meteoData = {};
	this.firstUpdateFlag = true;
	this.cities = {};
//	this.meteoNumsTpl = {degrees: [], speeds: [], pressures: [], distances: []};
	this.forecastOptions = {cities: {}, nums: {}, units: 'm', degType: 'C', order: []};
	this.meteoUnitsHTML = {degree: '', speed: '', distance: '', pressure: ''};
	this.tries = {};
	this.updatePeriod = 1800000;
	this.createPanelSettings();
	this.constants = {maxCities: 5, maxTries: 3};
	this.numCities = 0;

	this.oData = {cities: {forecast: {}, forecastDesc: {}, delLinks: {}}};
	this.forecastData = {};

	Update.request('Weather', 'module', 'startup', {id: this.id});
}

__Weather.prototype.Relay = function(data, part)
{
	switch(data.event.action)
	{
		case 'startup':
			this.forecastOptions.units = data.variables.settings.units;
			this.forecastOptions.degType = data.variables.settings.degType;
			this.forecastOptions.order = data.variables.settings.order;
			var tmp = {};
			if(!isEmpty(data.variables.cities))
			{
				for(var city_id in data.variables.cities)
				{
					this.forecastOptions.cities[city_id] = data.variables.cities[city_id];
					tmp[city_id] = {days: data.variables.cities[city_id].days, name: data.variables.cities[city_id].name};
				}
				this.setUnits();
				Update.request('Weather', 'module', 'getForecast', { id: this.id }, {cities: tmp}, true);
			}
			break;

		case 'getForecast':
			var self = this;
			var repeat_data = {};
			if(!isEmpty(data.variables))
			{
				this.init();
				for(var city_id in data.variables)
				{
					if(!this.tries[city_id])
						this.tries[city_id] = 0;
					if(data.variables[city_id].service.status == 'ok')
					{
						this.tries[city_id] = 0;
						this.forecastData[city_id] = data.variables[city_id];
						k = arraySearch(this.forecastOptions.order, city_id);
						if(!k && typeof(k) != 'number')	//т.е. не найдено
						{
							this.forecastOptions.order.push(city_id);
						}
					}
					else if(data.variables[city_id].service.status == 'error')
					{
						if(this.tries[city_id] && this.tries[city_id] > this.constants.maxTries)
						{
							var t = this.lang.msg['ServerDoesntResponseByCity'];
							if(data.variables[city_id].city)
								t += ' '+ data.variables[city_id].city;
							window.alert(t);
						}
						else
						{
							this.tries[city_id]++;
							repeat_data[city_id] = {days: data.variables[city_id].service.daysnum};
							if(data.variables[city_id].city)
								repeat_data[city_id]['name'] = data.variables[city_id].city;
						}
					}
				}
				this.processForecast();
			}
			if(!isEmpty(repeat_data))	//есть города с ошибками, требующие повторного запроса
				window.setTimeout(function() {Update.request('Weather', 'module', 'getForecast', {id: self.id}, {cities: repeat_data}, false)}, 500);	//повторяем через паузу
			break;

		default:
			return false;
			break;
	}
}

//Создаёт главную управляющую форму настроек гаджета
__Weather.prototype.createPanelSettings = function()
{
	var self = this;
	this.finput = {};	//пожалуй, удобно будет, если все элементы форм будут доступны отовсюду
	this.fpanel = {};
	this.Options.innerHTML = '';

	//Создаём секции управления
	createFormSearchCity();
	createFormSelectCity();
	this.fpanel.currentCities = ce('UL', this.Options, {marginTop: '10px', borderTop: '1px dashed #C2C2C2'});	//блок пользовательских настроек (системы мер и т.п.)
	createFormOptions();

	//Создаёт форму первоначального поиска города
	function createFormSearchCity()
	{
		self.fpanel.searchCity = ce('FORM', self.Options);	//блок поиска города
		self.fpanel.searchCity.innerHTML += Locale['City'] +': ';
		self.finput.searchCity = ce('INPUT', self.fpanel.searchCity, {type: 'text'});	//вводимый для поиска город
		ce('INPUT', self.fpanel.searchCity, {type: 'submit', className: 'std_button', value: Locale['ToSearch']});
		self.fpanel.searchCity.onsubmit = function()
		{
			if(self.numCities >= self.constants.maxCities)
			{
				window.alert(self.lang.msg['ForAddNewCityDelExist'][0] +' '+ self.constants.maxCities + self.lang.msg['ForAddNewCityDelExist'][1]);
				return false;
			}
			if(self.finput.searchCity.value.length < 2)
			{
				window.alert(self.lang.msg['ForSearchEnterMoreLetters'][0] +' 2 '+ self.lang.msg['ForSearchEnterMoreLetters'][1]);
				return false;
			}
			new Ajax.Request('/proxy/weather/', {
				onSuccess: function(r)
				{
					self.showSelectCity(r.responseText);
				},
				method: 'POST',
				parameters: {name: self.finput.searchCity.value, lang: Lang}
			});
			return false;
		}
	}

	//Создаёт форму выбора города из найденных по запросу
	function createFormSelectCity()
	{
		self.fpanel.selectCity = ce('FORM', null, null, {display: 'none', margin: '10px 0px'});	//блок выбора города из списка, уточнения параметров прогноза
		var t = ce('TR', ce('TBODY', ce('TABLE', self.fpanel.selectCity, null, {marginBottom: '10px'})));
		ce('TD', t, {innerHTML: self.lang['ForecastOn'] +' '});
		self.finput.selectDays = ce('SELECT', ce('TD', t), null, {margin: '0px 7px'});
		for(var i=1; i<=5; i++)
			ce('OPTION', self.finput.selectDays, {value: i, innerHTML: i});
		self.finput.selectDays.options[2].selected = true;
		ce('TD', t, {innerHTML: self.lang['Days']});

		ce('SPAN', self.fpanel.selectCity, {innerHTML: self.lang['FoundedCities'] +': '});
		self.finput.selectCity = ce('SELECT', self.fpanel.selectCity);
		ce('INPUT', self.fpanel.selectCity, {type: 'submit', className: 'std_button', value: Locale['ToAdd']});
		self.Options.appendChild(self.fpanel.selectCity);

		self.fpanel.selectCity.onsubmit = function()	//сохраняем выбор города
		{
			//Обрабатываем выбор города: отправляем настройки серверному контроллеру, грузим и обрабатываем контент
			if(self.numCities >= self.constants.maxCities)
			{
				window.alert(self.lang.msg['ForAddNewCityDelExist'][0] +' '+ self.constants.maxCities + self.lang.msg['ForAddNewCityDelExist'][1]);
				return false;
			}
			var t = {};
			self.cities[self.finput.selectCity.value] = self.finput.selectCity[self.finput.selectCity.selectedIndex].text;
			t[self.finput.selectCity.value] = {days: self.finput.selectDays.value, name: self.finput.selectCity[self.finput.selectCity.selectedIndex].text};
			self.tries[self.finput.selectCity.value] = 0;
			Update.request('Weather', 'module', 'getForecast', {id: self.id}, {cities: t, k: (self.numCities+1)}, true);
			self.fpanel.selectCity.style.display = 'none';
			return false;
		}
	}

	//Создаёт форму изменения и сохранения опций
	function createFormOptions()
	{
		self.fpanel.options = ce('FORM', self.Options, {marginTop: '10px', borderTop: '1px dashed #C2C2C2'});	//блок пользовательских настроек (системы мер и т.п.)
/*
		self.fpanel.options.innerHTML += 'Локальное время: ';	//НАДО БУДЕТ ДОДЕЛАТЬ!!!
		ce('INPUT', self.fpanel.options, {type: 'checkbox', defaultChecked: true});	//селектор местного времени
*/
		var oTbody = ce('TBODY', ce('TABLE', self.fpanel.options, null, {marginTop: '15px'}));
		var oTr = ce('TR', oTbody);
		ce('TD', oTr, {innerHTML: self.lang['Temperature'] +':'});
		var oTd = ce('TD', oTr, null, {paddingLeft: '10px'});
		oTd.innerHTML = '<input type="radio" name="'+ self.id +'_degType" id="'+ self.id +'_degTypeC" style="marginRight: 3px"/>';
		self.finput.optionsDegTypeC = document.getElementById(self.id +'_degTypeC');	//шкала градусов
		if(!self.forecastOptions.degType || self.forecastOptions.degType == 'C')
			self.finput.optionsDegTypeC.defaultChecked = true;

		ce('SPAN', oTd, {innerHTML: '&deg;C'});
		oTd = ce('TD', oTr, null, {paddingLeft: '10px'});
		oTd.innerHTML = '<input type="radio" name="'+ self.id +'_degType" id="'+ self.id +'_degTypeF" style="marginRight: 3px"/>';
		self.finput.optionsDegTypeF = document.getElementById(self.id +'_degTypeF');	//шкала градусов
		if(self.forecastOptions.degType && self.forecastOptions.degType == 'F')
			self.finput.optionsDegTypeF.defaultChecked = true;
		ce('SPAN', oTd, {innerHTML: '&deg;F'});

		oTr = ce('TR', oTbody);
		ce('TD', oTr, {innerHTML: self.lang['WindSpeed'] +':'});
		oTd = ce('TD', oTr, null, {paddingLeft: '10px'});
		oTd.innerHTML = '<input type="radio" name="'+ self.id +'_units" id="'+ self.id +'_unitsM" style="marginRight: 3px"/>';
		self.finput.optionsUnitsM = document.getElementById(self.id +'_unitsM');	//система мер
		ce('SPAN', oTd, {innerHTML: self.lang.units.metersPS});
		oTd = ce('TD', oTr, null, {paddingLeft: '10px'});
		oTd.innerHTML = '<input type="radio" name="'+ self.id +'_units" id="'+ self.id +'_unitsE" style="marginRight: 3px"/>';
		self.finput.optionsUnitsE = document.getElementById(self.id +'_unitsE');	//система мер
		if(self.forecastOptions.units && self.forecastOptions.units == 'e') self.finput.optionsUnitsE.defaultChecked = true;
		else self.finput.optionsUnitsM.defaultChecked = true;
		ce('SPAN', oTd, {innerHTML: self.lang.units.milesPH});

		var oTd = ce('TD', ce('TR', oTbody), {colSpan: 3});
		ce('INPUT', oTd, {type: 'hidden', value: 'ru'});	//локаль (временно)
		ce('INPUT', oTd, {type: 'submit', className: 'std_button', value: Locale['ToSave']})
		self.fpanel.options.onsubmit = function()
		{
			var flag = false;
			if(self.finput.optionsDegTypeF.checked && self.forecastOptions.degType=='C')
			{
				self.forecastOptions.degType = 'F';
				flag = true;
			}
			else if(self.finput.optionsDegTypeC.checked && self.forecastOptions.degType=='F')
			{
				self.forecastOptions.degType = 'C';
				flag = true;
			}
			if(self.finput.optionsUnitsE.checked && self.forecastOptions.units=='m')
			{
				self.forecastOptions.units = 'e';
				flag = true;
			}
			else if(self.finput.optionsUnitsM.checked && self.forecastOptions.units=='e')
			{
				self.forecastOptions.units = 'm';
				flag = true;
			}
			if(flag)
			{
				self.setUnits();
				self.processForecast();
				Update.request('Weather', 'module', 'changeSettings', { id: self.id }, {
					units: self.forecastOptions.units,
					degType: self.forecastOptions.degType
				});
			}
			self.Core.ToggleOptions();
			return false;
		}
	}
}

//Callback-функция отображения списка городов, соответсвующих искомому, а также обрабатывающая выбор одного из них
__Weather.prototype.showSelectCity = function(jsonCities)
{
	this.finput.selectCity.innerHTML = '';	//чистим на случай, если ещё остался список от прежнего поиска

	try
	{
		var cities = eval('('+ jsonCities +')');
	}
	catch(failed)
	{
		return false;
	}

	var flag = false;
	var t = '';
	if(!isEmpty(cities))
		for(var city_id in cities)
		{
			flag = true;
			t = cities[city_id].city +', '+ cities[city_id].country;
			if(t.length > 30) t = t.substr(0, 27) + '...';
			ce('OPTION', this.finput.selectCity, {city_id: city_id, value: city_id, innerHTML: t});
		}
	if(flag)
	{
		this.fpanel.selectCity.style.display = '';
	}
	else
	{
		window.alert(this.lang.msg['CityNotFound']);
	}
}

__Weather.prototype.showSelectCityXML = function(xmlCities)
{
	this.finput.selectCity.innerHTML = '';	//чистим на случай, если ещё остался список от прежнего поиска

	var cities = null;
	if(xmlCities && (cities = xmlCities.getElementsByTagName('loc')))
	{
		for(var i=0; i<cities.length; i++)
		{
			var city_id = cities[i].getAttribute('id');
			ce('OPTION', this.finput.selectCity, {city_id: city_id, value: city_id, innerHTML: cities[i].firstChild.nodeValue});
		}
	}
	this.fpanel.selectCity.style.display = '';
}

__Weather.prototype.onStartResize = function()
{
	for(var i in this.oData.cities.forecast)
	{
		this.oData.cities.forecast[i].style.width = '0';
	}
}

__Weather.prototype.onStartDrag = function()
{
	for(var i in this.oData.cities.forecast)
	{
		this.oData.cities.forecast[i].style.width = '0';
	}
}

__Weather.prototype.onStopDrag = function()
{
	for(var i in this.oData.cities.forecast)
	{
		this.oData.cities.forecast[i].style.width = (this.Content.getWidth()-this.Content.getOuterWidth())+'px';
	}
}

__Weather.prototype.onStopResize = function()
{
	var w = String(this.Content.getWidth()-this.Content.getOuterWidth())+'px';
	for(var i in this.oData.cities.forecast)
	{
		this.oData.cities.forecast[i].style.width = w;
	}
}

__Weather.prototype.onStartDrag = function()
{
	for(var i in this.oData.cities.forecast)
	{
		this.oData.cities.forecast[i].style.width = '0';
	}
}

__Weather.prototype.onStopDrag = function()
{
	for(var i in this.oData.cities.forecast)
	{
		this.oData.cities.forecast[i].style.width = ((document.getElementById('GhostItem').getWidth()-40) + 'px');
	}
}

//Очищает (как бы инициализирует) гаджет перед обновлением информации
__Weather.prototype.init = function()
{
	this.Content.innerHTML = '';
	this.fpanel.currentCities.innerHTML = '';
	this.forecastOptions.cities = {};
	this.oData.cities.forecast = {};
	this.oData.cities.forecastDesc = {};
	this.oData.cities.delLinks = {};
	this.numCities = 0;
}

//Обрабатывает данные от сервера и выводит прогноз погоды по городам
__Weather.prototype.processForecast = function()
{
	var self = this;
	this.setUnits();
	var t = null;
	for(var l=0; l<this.forecastOptions.order.length; l++)
	{
		var city_id = this.forecastOptions.order[l];
		if(!this.forecastData[city_id])	//ориентируемся то мы на массив порядка, но он не даёт представления о наличии данных
			continue;
		this.numCities++;
		this.oData.cities.delLinks[city_id] = ce('LI', this.fpanel.currentCities, null, {listStyleType: 'none'});

		//Добавляем контентный и управляющий удалением блоки в гаджет
		if(!this.oData.cities.forecast[city_id])
		{
			this.oData.cities.forecast[city_id] = ce('DIV', this.Content, null, {width: (this.Content.getWidth()-this.Content.getOuterWidth())+'px', height: '92px', overflow: 'auto', overflowX: 'auto', overflowY: 'hidden'});
		}
		else
			this.oData.cities.forecast[city_id].innerHTML = '';
		var t = null;

		//формируем блок управления удалением городов
		if(!this.forecastOptions.cities[city_id])
			this.forecastOptions.cities[city_id] = this.forecastData[city_id].city;
		ce('IMG', this.oData.cities.delLinks[city_id], {className: 'href', src: '/img/icons/x2.gif', title: Locale['ToDelete'], cid: city_id, onclick: delCity});
		ce('SPAN', this.oData.cities.delLinks[city_id], {innerHTML: ' '+ this.forecastData[city_id].city});

		if(this.cities[city_id])
			var title = this.cities[city_id];
		else
			var title = this.forecastData[city_id].city;
		ce('DIV', this.oData.cities.forecast[city_id], {innerHTML: '<strong><u>'+ title +'</u></strong>'});

		var days = this.forecastData[city_id].days;
		var tod = null;
		var todl = null;
		var k=0;
		var oTr = ce('TR', ce('TBODY', ce('TABLE', this.oData.cities.forecast[city_id])));
		this.oData.cities.forecastDesc[city_id] = {};
		for(var i=0; i<days.length; i++)
		{
			//Выводим подробный прогноз по дням
			var oTd = ce('TD', oTr, null, {padding: '4px 25px 4px 0px', textAlign: 'center', whiteSpace: 'nowrap'});
			var fdate = new Date((this.forecastData[city_id].tstamp + (86400*k++))*1000);	//дата
			oTd.innerHTML += '<strong>'+ Locale.WeekDaysCtd[days[i].dow] +',&nbsp;'+ addZero(fdate.getDate()) +'.'+ addZero(fdate.getMonth()+1) +'</strong><br/>';
			this.oData.cities.forecastDesc[city_id][i] = [];
			for(var j=0; j<2; j++)
			{
				this.oData.cities.forecastDesc[city_id][i][j] = '';
				var oDesc = this.oData.cities.forecastDesc[city_id][i];
				if(j==0)
				{	//числа и единицы изм-я не только выводим, но и храним в спец. массивах для возм. конвертации
					tod = days[i].day;
					todl = 'd';
					var oImgs = ce('DIV', oTd, null, {whiteSpace: 'nowrap'});
					var suf = '';
				}
				else
				{
					tod = days[i].night;
					todl = 'n';
					suf = 'n';
				}
				if(tod.t == 'N/A') continue;

				if(i==0)
				{	//подробности, выдающиеся только на первый день или текущее время (???)

					oDesc[j] += this.lang['Pressure'] +': ';
					if(this.forecastOptions.units == 'm')
						oDesc[j] += Math.round(this.forecastData[city_id].bar*25.4);
					else
						oDesc[j] += this.forecastData[city_id].bar;
					oDesc[j] += '&nbsp;'+ this.meteoUnitsHTML.bar;
					oDesc[j] += ',<br/>'+ this.lang['Visibility'] +': ';
					if(this.forecastOptions.units == 'm')
						oDesc[j] += Math.round(this.forecastData[city_id].vis*16.09)/10;
					else
						oDesc[j] += this.forecastData[city_id].vis;
					oDesc[j] += '&nbsp;'+ this.meteoUnitsHTML.dist +'<br/>';
				}

				var oImg = ce('IMG', oImgs, {src: '/img/weather/24x24/'+ tod.icon +suf +'.gif', width: 24, height: 24, city: city_id, day: i, tod: j, onmouseover: showTip, onmouseout: hideTip});
				if(j)
				{
					oImg.style.backgroundColor = '#000000';
					oImg.style.marginLeft = '5px';
				}
				t = ce('SPAN', oTd);
				if(this.forecastOptions.degType == 'C')
					t.innerHTML = Math.round((tod.t - 32)/1.8);
				else
					t.innerHTML = tod.t;
				t.innerHTML	+= this.meteoUnitsHTML.degree;
				if(!j)
					t.innerHTML	+= '&nbsp;/&nbsp;';

				oDesc[j] += this.lang['Wind'] +' '+ this.transformWind(tod.wdir) +', ';
				if(this.forecastOptions.units == 'm')
					oDesc[j] += Math.round(tod.wspeed * 0.447);
				else
					oDesc[j] += tod.wspeed;

				oDesc[j] += '&nbsp;'+ this.meteoUnitsHTML.speed;
				oDesc[j] += '<br/>'+ this.lang['ProbPrec'] +': '+ tod.ppcp +'%';
				oDesc[j] += '<br/>'+ this.lang['Humidity'] +': '+ tod.hmid +'%';
				if(!j)
					oDesc[j] += '<br/>'+ this.lang['Sunrise'] +': '+ this.transformTime(days[i].sunrise) +', '+ this.lang['Sunset'] +': '+ this.transformTime(days[i].sunset);
			}
		}
		if(this.numCities >= this.constants.maxCities) break;
	}
	this.onStopResize();	//регулируем ширину данных
	this.oCopyrights = ce('DIV', this.Content, {innerHTML: '<small>Powered by: The Weather Channel &reg;</small>'}, {borderTop: '1px dotted #CCCCCC', marginTop: '10px', clear: 'both', fontStyle: 'italic'});

	function delCity()
	{
		self.initDelCity(this.cid);
		return false;
	}

	function showTip(e)
	{
		e = e || window.event;
		Tooltip.Show(self.oData.cities.forecastDesc[this.city][this.day][this.tod], Event.element(e), 200);
	}

	function hideTip()
	{
		Tooltip.Hide();
	}
}

//удаляет город
__Weather.prototype.initDelCity = function(city_id)
{
	Update.request('Weather', 'module', 'delCities', { id: this.id }, {cities: [city_id]}, true);
	delete this.forecastData[city_id];
	delete this.forecastOptions.cities[city_id];
	this.forecastOptions.order.splice(arraySearch(this.forecastOptions.order, city_id), 1);
	de(this.oData.cities.forecast[city_id]);
	delete this.oData.cities.forecast[city_id];
	for(var i in this.oData.cities.forecastDesc[city_id])
	{
		de(this.oData.cities.forecastDesc[city_id][i].d);
		de(this.oData.cities.forecastDesc[city_id][i].n);
	}
	delete this.oData.cities.forecastDesc[city_id];	//блок удаляется вместе с основным
	de(this.oData.cities.delLinks[city_id]);
	delete this.oData.cities.delLinks[city_id];
	delete this.tries[city_id];
	this.numCities--;
	return false;
}

//Устанавливает единицы измерения в соответствии с системой мер
__Weather.prototype.setUnits = function()
{
	if(this.forecastOptions.degType == 'C')
	{
		this.meteoUnitsHTML.degree = '&deg;';
		this.finput.optionsDegTypeC.checked = true;
	}
	else
	{
		this.meteoUnitsHTML.degree = '&deg;';
		this.finput.optionsDegTypeF.checked = true;
	}

	if(this.forecastOptions.units == 'm')
	{
		this.meteoUnitsHTML.speed = this.lang.units['metersPS'];
		this.meteoUnitsHTML.dist = this.lang.units['km'];
		this.meteoUnitsHTML.bar = this.lang.units['mmMerc'];
		this.finput.optionsUnitsM.checked = true;
	}
	else
	{
		this.meteoUnitsHTML.speed = this.lang.units['milesPH'];
		this.meteoUnitsHTML.dist = this.lang.units['miles'];;
		this.meteoUnitsHTML.bar = this.lang.units['in'];
		this.finput.optionsUnitsE.checked = true;
	}
}

//Конвертирует направление ветра из градусов в буквы
__Weather.prototype.transformWind = function(degrees)
{
	if(degrees <= 22 || degrees >= 343) return this.lang.orient['N'];
	if(degrees >= 23 && degrees <= 67) return this.lang.orient['NE'];
	if(degrees >= 68 && degrees <= 112) return this.lang.orient['E'];
	if(degrees >= 113 && degrees <= 157) return this.lang.orient['SE'];
	if(degrees >= 158 && degrees <= 202) return this.lang.orient['S'];
	if(degrees >= 203 && degrees <= 257) return this.lang.orient['SW'];
	if(degrees >= 258 && degrees <= 292) return this.lang.orient['W'];
	if(degrees >= 293 && degrees <= 342) return this.lang.orient['NW'];
	return '';
}

//Конвертирует дату и время в приятный душе формат
__Weather.prototype.transformTime = function(timeStr)
{
	var tstamp = new Date();
	var time = new Date(Date.parse((tstamp.getMonth()+1) +'/'+ tstamp.getDate() +'/'+ tstamp.getFullYear() +' '+ timeStr));
	return addZero(time.getHours()) +':'+ addZero(time.getMinutes());
}