// $ID: b-timer.js, Wed Oct 12 2011 15:14:58 GMT+0400 (MSD), Leonid 'n3o' Knyazev $
// String.sprintf
(function(window, undefined){
	String.prototype.sprintf = String.prototype.sprintf || function () {
		if (arguments.length) {
			var _arguments = arguments, _i = -1;
			
			return this.replace(/%s/g, function(){
				_i++;
				return _arguments[_i] == undefined ? '' : _arguments[_i] ;
			});
		} else {
			return this.replace(/%s/g, '');
		}
	}
})(window);


/**
 * @class Timer
 * @description Таймер обратного отсчёта до 130-ти летия МГТС.
 * 
 * @author Leonid Knyazev (leonid@knyazev.me | n3o@design.ru)
 * @copyright (c) Art. Lebedev | http://www.artlebedev.ru/
 * 
 * @requires jQuery
 */
;(function (window, $, undefined) {
	//@private
	var _templates = {
		layout : '<div class="counter-layout">%s<div class="counter-days"></div><div class="counter-hours"></div><div class="counter-minutes"></div></div>',
		title  : '<div class="counter-title">%s</div>',
		digits : '<div class="digits"></div><div class="digit-title">%s</div>',
		digit  : '<div class="single-digit-border"><div class="single-digit"></div></div>'
	};
	
	
	//@contructor
	var Timer = function (oSettings) {
		/**
		 * Параметры.
		 * @name _settings
		 * @type {Object}
		 * @private
		 * 
		 * @param {String} [selector] Класс или id DOM-элемента для счётчика.
		 * @param {Date} [server] Серверное время.
		 * @param {Date} [ending] Дата, до которой надо сделать отсчёт.
		 * @param {Integer} [offset] Высоца изображения с цифрой.
		 * @param {Integer} [delay] Задержка для setTimeout с перерасчётами.
		 * @param {Object} [lang] Объект содержит подписи, заголовки, лейблы
		 */
		this._settings = $.extend({
			selector   : '#celebrate-counter',
			endTime    : null, // 2012, 6, 13, 0, 0
			serverTime : null,
			locale     : 'ru',
			offset     : -22,
			delay      : 100,
			pid        : -1,
			messages   : {
				'ru' : {
					title   : 'До&nbsp;130-летия осталось',
					days    : ['день', 'дня', 'дней'],
					hours   : ['час', 'часа', 'часов'],
					minutes : ['минута', 'минуты', 'минут']
				},
				'en' : {
					title   : 'Until 130th anniversary left',
					days    : ['day', 'days', 'days'],
					hours   : ['hour', 'hours', 'hours'],
					minutes : ['minute', 'minutes', 'minutes']
				}
			}
		}, oSettings);
		
		// Cache last values
		this._last = {
			days    : -1,
			hours   : -1,
			minutes : -1
		};
		
		this._numCache = [];
		this._numCases = [2, 0, 1, 1, 1, 2];
		
		// Вызываем инициализацию класса.
		if (this._settings.pid != 2 && this._settings.locale != 'en') {
			this.init();
		}
	};
	
	
	//@methods
	$.extend(Timer.prototype, {
		/**
		 * Инициализация класса.
		 * @name Timer.init
		 * @function
		 * @public
		 */
		init : function () {
			var _this = this;
			
			// Обернули в .getJSON, что бы выполнить инициализацию счётчика после того, как мы получим с сервера время.
			$.getJSON(_this._settings.serverTime, function (data) {
				_this._serverTime = (data.moscow ? data.moscow : new Date()).valueOf() / 1000 >> 0;
				_this._diffTime   = (((new Date()).valueOf() / 1000 >> 0) - _this._serverTime);
				_this._endTime    = (_this._settings.endTime ? _this._settings.endTime : new Date()).valueOf() / 1000 >> 0;
				
				if ((_this._endTime - ((new Date()).valueOf() / 1000 >> 0) + _this._diffTime) <= 0) {
					_this._doHappy(); return;
				}
	
				_this._initDOM();
				_this._initEvents();
				 
				_this.show((_this._endTime - ((new Date()).valueOf() / 1000 >> 0) + _this._diffTime));
			});
		},
		
		_doHappy : function () {
			$(this._settings.selector).html($('<img />').attr('src', '/f/1/global/b-timer/test_'+ this._settings.locale +'.png'));
		},
		
		/**
		 * Инициализация DOM-объектов. 
		 * @name _initDOM
		 * @function
		 * @private
		 */
		_initDOM : function () {
			this.dom = {
				object : $(this._settings.selector)
			};
			
			if (this.dom.object.length) {
				this.dom.object.show();
				
				// init layout
				this.dom.layout = $(_templates.layout.sprintf(_templates.title.sprintf(this._settings.messages[this._settings.locale].title)));

				var l = ['days', 'hours', 'minutes'];
				
				for (var i = 0; i < l.length; i++) {
					var group = $(_templates.digits);
					
					this.dom[l[i]] = [];
					
					for (var j = 0; j < (l[i] == 'days' ? 3 : 2); j++) {
						var d = $(_templates.digit);
							d.filter("div.single-digit-border").addClass("single-digit-border-" + j);
							d.appendTo(group.filter('div.digits'));
							
						this.dom[l[i]].push({digit: 0, object: d.find('div.single-digit')});
					}
					
					group.appendTo(this.dom.layout.find('div.counter-' + l[i]));
				}
				
				
				this.dom.object.append(this.dom.layout);
			};
		},
		
		
		/**
		 * Инициализации событий.
		 * @name _initEvents
		 * @function
		 * @private
		 */
		_initEvents : function () {
			var self = this;
			this._interval = setInterval(function () {
				self.show((self._endTime - ((new Date()).valueOf() / 1000 >> 0) + self._diffTime));
			}, 500);
		},
		
		
		show : function (seconds) {
			var div = {
				d: (24 * 60 * 60),
				h: (60 * 60),
				m: (60)
			};
			
			var move = {
				days: (seconds / div.d) >> 0
			};
			
			move.hours   = ((seconds - move.days * div.d) / div.h) >> 0;
			move.minutes = ((seconds - move.days * div.d - move.hours * div.h) / div.m) >> 0;

			if (move.days == 0 && move.hours == 0 && move.minutes == 0) {
				this._doHappy();
				this._updateLabels(move);
				clearInterval(this._interval);
			} else {
				for (var i in move) {
					if (move.hasOwnProperty(i)) {
						this._moveTo(this.dom[i], (move[i] < 10 ? '0' + move[i] : move[i]), i);
					}
				}
				
				this._updateLabels(move);
			}
		},
		
		
		_moveTo : function (what, to, type) {
			var self = this,
				sDigits = to.toString(),
				iDigitsCount = sDigits.length,
				aDigits = [];
			
			
			for (var i = 0; i < iDigitsCount; i++) {
				var _currentDigit = sDigits.substring(i, i + 1);
					aDigits.push(_currentDigit);
			}

			for (var t = 0; t < what.length; t++) {
				var _digit = aDigits[t];
					onEnd = function(){};
				
				if (what[t].aDigits == 9 && _digit == 0) {
					_digit = 10;
					onEnd = (function(what){
						return function(){
							self._moveOne(what, 0, 0)
						}
					})(what[t].object);
					
				}
				
				if (_digit != what[t].aDigits) {
					this._moveOne(what[t].object, _digit, what[t].aDigits, onEnd);
					what[t].aDigits = (_digit == 10 ? 0 : _digit);
				}
			}
		},
		
		
		_moveOne : function (what, to, from, callback) {
			if (to == 0 && from == 0) {
				what.animate({top:this._settings.offset * 10}, 1);
			} else {
				if (typeof callback != "function") {
					callback = function(){}
				}
				what.animate({top: this._settings.offset * to}, 200, callback);
			}
		},
		
		
		_updateLabels : function (data) {
			for (var i in data) {
				var _type = i,
					_currentValue = data[i],
					_lastValue = this._last[i];
					
				if (_currentValue != _lastValue) {
					var _oLabel = $('.counter-' + i +' .digit-title', this.dom.layout)
						_sLabel = this._getLabel(data[i], this._settings.messages[this._settings.locale][i]);
						_oLabel.text(_sLabel);
					
					this._last[i] = _currentValue;
				}
			}
		},
		
		_getLabel : function (number, titles) {
			if(!this._numCache[number]) {
				this._numCache[number] = number % 100 > 4 && number % 100 < 20 ? 2 : this._numCases[Math.min(number % 10, 5)];
			}
			
			return titles[this._numCache[number]];
		}
	});
	
	
	//@export
	window.Timer = Timer;
})(window, window.jQuery);
