// В этом файле содержится общий код таймера, который можно применять в любом месте.
// Код не привязан к DOM и реализует общий алгоритм работы таймера.
// Для обновления DOM в каждом случае будет разный код.
// Для получения значений таймера см. список методов объекта.
// Свойства, имена которых начинаются с подчеркивания, являются служебными и
// не должны использоваться как API.

// Лимит таймера - 12 часов
var MAX_ALLOWED_VALUE = 60 * 60 * 12;

// Получаем GET-параметр id из адресной строки.
// Если параметра нет, или он не является числом, то возвращаем undefined.
function getIdFromUrl(){
	var id = window.location.search.split('id=');
	if (id[1]) {
		id = id[1].split('&');
		id = parseInt(id[0]);
		return isNaN(id) ? undefined : id;
	}
	return undefined;
}

// Конструктор таймера
// id - некий уникальный идентификатор, например, номер баги или тикета
// onUpdate - функция, вызываемая при обновлении таймера. Опциональна.
function Timer(id, onUpdate, limit){
    this.limit = limit || MAX_ALLOWED_VALUE;
    this._storageKey = id;
    this.onUpdate = onUpdate;
    
    var storedValue = parseInt(Timer.storage.get(this._storageKey));
	var storedPauseValue = parseInt(Timer.storage.get(this._storageKey + Timer.PAUSE_SUFFIX));
	

	var startTime, pauseStartTime;
    // Определяем геттеры/сеттеры, чтобы при записи свойства автоматически обновлялся storage
    Object.defineProperty(this, '_startTime', {
        get: function(){
            return startTime;
        },
        set: function(value){
            startTime = value;
            if(value === null){
                Timer.storage.remove(this._storageKey);
            } else {
                Timer.storage.set(this._storageKey, value);
            }
        }
    });
    
    Object.defineProperty(this, '_pauseStartTime', {
        get: function(){
            return pauseStartTime;
        },
        set: function(value){
            pauseStartTime = value;
            if(value === null){
                Timer.storage.remove(this._storageKey + Timer.PAUSE_SUFFIX);
            } else {
                Timer.storage.set(this._storageKey + Timer.PAUSE_SUFFIX, value);
            }
        }
    });
	

	// Если есть сохраненные значения, то используем их
	if(!isNaN(storedValue)){
		startTime = storedValue;
		pauseStartTime = isNaN(storedPauseValue) ? null : storedPauseValue;
	} else {
		// Если сохраненного значения нет, то принимаем текущее время за начало работы
		this._startTime = new Date().getTime();
		this._pauseStartTime = null;
	}

    this.update();
}

// Очищаем сохраненные значения
// Используем, когда делаем submit задачи
Timer.prototype.clear = function(){
	Timer.storage.remove(this._storageKey);
	Timer.storage.remove(this._storageKey + Timer.PAUSE_SUFFIX);
}

// Возвращает количество секунд с момента старта с вычетом пауз.
// Не изменяет состояния таймера, лишь считывает текущее значение
Timer.prototype.getElapsedSeconds = function(){
    if(this.isPaused()){
		return Math.floor((this._pauseStartTime - this._startTime)/1000);
	} else {
		return Math.floor((new Date() - this._startTime)/1000);
	}
}

// Возвращает отформатированную строку, которую можно выводить на экран
// Не изменяет состояния таймера, лишь считывает текущее значение
Timer.prototype.getFormattedString = function(){
    var secondsFull = this.getElapsedSeconds();
    var minutesFull = Math.floor(secondsFull/60);
    var hours = Math.floor(minutesFull/60);
    var minutes = minutesFull - hours*60;
    var seconds = secondsFull - minutesFull*60;

	if (seconds < 10) {
		seconds = "0"+seconds;
	}
	
    if (minutes < 10) {
        minutes = "0"+minutes;
    }
    if (hours < 10) {
        hours = "0"+hours;
    }

	return hours + ":" + minutes + ":" + seconds;
}

// Таймер на паузе?
Timer.prototype.isPaused = function(){
    return this._pauseStartTime !== null;
}

// Сброс таймера. Если таймер стоял на паузе, то после сброса он останется на паузе.
// Новые значения автоматически записываются в storage.
Timer.prototype.reset = function(){
    this._startTime = new Date().getTime();
    // Если таймер был на паузе, то после сброса оставляем его на паузе
    this._pauseStartTime = this.isPaused() ? new Date().getTime() : null;
    this.update();
}

// Включить автообноление с заданным интервалом
// Функция onUpdate будет вызываться при каждом обновлении
Timer.prototype.setAutoUpdate = function(interval){
    interval = interval || 1000;
    if(this._updateIntervalId){
        clearInterval(this._updateIntervalId);
    }
    this._updateIntervalId = setInterval(this.update.bind(this), interval);
}

// Изменяет состояние паузы. Если нет изменений, то ничего не произойдет.
// При изменении состояния, новые значения автоматически запишутся в storage.
Timer.prototype.setPause = function(state){
    // Ничего не делаем, если нет изменений
    if(state === this.isPaused()) return;
    
    if(state){
        this._pauseStartTime = new Date().getTime();
	} else {
		this._startTime += (new Date().getTime() - this._pauseStartTime);
        this._pauseStartTime = null;
	}
    this.update();
}

// Выключает автообновление, если включено
Timer.prototype.stopAutoUpdate = function(){
    if(this._updateIntervalId){
        clearInterval(this._updateIntervalId);
        this._updateIntervalId = null;
    }
}

// Включает/выключает паузу
Timer.prototype.togglePause = function(){
    this.setPause(!this.isPaused());
}

// Вызывает onUpdate, если определена.
// Используется при автообнолении и при изменении состояния таймера
Timer.prototype.update = function(){
    if(this.getElapsedSeconds() > this.limit){
        this.reset();
        return;
    }
    if(typeof this.onUpdate === 'function'){
        this.onUpdate();
    }
}

// Суффикс, с которым сохраняется время паузы
Timer.PAUSE_SUFFIX = 'p';
// Не используется, чтобы не ломать обратную совместимость с уже сохраненными сессиями
Timer.PREFIX = 'timer_';

// Обертка над sessionStorage
// При необходимости, можно будет заменить на другое хранилище
Timer.storage = {
    get: function(key){
        if (!window.sessionStorage) {
            // Ведем себя, будто ключ не найден
            return null;
	    } else {
		    return sessionStorage.getItem(key);
	    }
    },
    remove: function(key){
        if(!window.sessionStorage){
            return false;
        } else {
            sessionStorage.removeItem(key);
            return true;
        }
    },
    set: function(key, data) {
	    if (window.sessionStorage) {
		    try {
			    sessionStorage.setItem(key, data);
			    return true;
		    } catch(e) {
			    return false;
		    }
	    }
	    return false;
    }
};