﻿/// <reference path="../jquery.common.js" />
/// <reference path="../jquery.js" />
/// <reference path="../zw_Runtime.js" />
/// <reference path="../plugins/history/history.js" />

var UrlHelper = {
    splitQuery: function (query) {
        var parameterNames = [];
        var parameterValues = {};

        /* splitting hash into parameterNames and parameterValues */
        var hash = UrlHelper.cleanQuery(query);

        var groups = hash.split('&');
        for (var i = 0; i < groups.length; i++) {
            var group = groups[i];
            if (group == "") {
                continue;
            }
            var equalPosition = group.indexOf("=");
            var parameterName = group.substr(0, equalPosition);
            var parameterValue = group.substr(equalPosition + 1);
            parameterNames.push(parameterName);
            parameterValues[parameterName] = parameterValue;
        }

        return {
            parameterNames: parameterNames,
            parameterValues: parameterValues
        };
    },

    cleanQuery: function (query) {
        var indexOfQuestion = query.lastIndexOf("?");
        if (indexOfQuestion >= 0)
            return query.substr(indexOfQuestion + 1);

        return "";
    }
};

/*
HistoryBase: базовый класс-обертка над jquery.history для работы с историей. 
При желании сменить jquery.history на что-то другое требуется замена только этого класса.
Поддерживает 2 метода:
subscribe(handler) - подписаться на событие изменения истории (HistoryBase.subscribe(function (parameterNames, parameterValues) {})
setQuery(query) - изменить текущее состояние (HistoryBase.setQuery("?documentID=120&documentDate=11.12.2011"))

Использование этого класса напрямую не рекомендуется (следует использовать ZetaHistory)
*/
var HistoryBase = (function ZHistoryBase() {
    var _handlers = [];
    var _history = window.History;
    var _hashChanged = function (hash) {
        var parameters = UrlHelper.splitQuery(hash);

        for (var j = 0; j < _handlers.length; j++) {
            var handler = _handlers[j];
            handler(parameters.parameterNames, parameters.parameterValues);
        }
    };
    var _initialized = false;
    var result = {
        subscribe: function (handler) {
            _handlers.push(handler);
        },

        setQuery: function (query, pushToHistory) {
            query = UrlHelper.cleanQuery(query);

            var title = document.title;
            if (pushToHistory == undefined)
                pushToHistory = true;

            if (_history.emulated.pushState) {
                query += "&_zhuid=" + Math.random();
            }

            if (pushToHistory) {
                _history.pushState(null, null, "?" + query);
            } else {
                _history.replaceState(null, null, "?" + query);
            }

            document.title = title;
        },

        getQuery: function () {
            return _history.getState().url;
        },
        Init: function () {
            if (_initialized)
                return;
            _initialized = true;

            _history.Adapter.bind(window, 'statechange', function () {
                var hash = _history.getState().hash;
                _hashChanged(hash);
            });

            var initialHash = _history.getState().hash;
            _hashChanged(initialHash);

        }
    };

    return result;
})();



/*
ZetaHistory - класс для работы с историей.
Поддерживает методы:
ZetaHistory.setQuery("?page=10&param=value"); - изменить текущее состояние.
ZetaHistory.setParameters(new { page: 10, param: value }); - изменить параметры в текущем состоянии.

ZetaHistory.registerHandler("prefix", function (changedParameterName, parameters) { alert('Изменилось значение параметра ' + changedParameterName);} );
подписка на событие изменения URL'a. 
Будет вызываться при изменении параметров, имя которых начинается с "prefix"

!!!Всю работу с историей необходимо проводить через обработку событий в registerHandler, а не "напрямую" по нажатию на ссылку!!!
Это необходимо для вызова хэндлеров при нажатии "вперед-назад".
*/
var ZetaHistory = (function ZetaHistoryClass() {
    var _history = HistoryBase;
    var _params = [];
    var _handlers = [];

    //очищает флаги invoked.
    //должен вызываться перед началом разбора изменившегося URL'а
    var _resetInvokes = function () {
        for (var i = 0; i < _handlers.length; i++) {
            _handlers[i].invoked = 0;
        }
    };

    //вызывает все хэндлеры, зарегистрированные с префиксом prefix
    //флаг invoked служит для вызова хэндлера не больше одного раза за обработку URL'a
    var _invokeHandlers = function (changedParameterName, parameters) {
        for (var i = 0; i < _handlers.length; i++) {
            var handler = _handlers[i];
            if (!handler.invoked) {
                if (changedParameterName.indexOf(handler.prefix) == 0) {
                    handler.handler(changedParameterName, parameters);
                    handler.invoked = 1;
                }
            }
        }
    };

    var _init = function () {
        var url = document.location.href.replace(document.location.hash, "");
        var parameters = UrlHelper.splitQuery(url);
        for (var j = 0; j < parameters.parameterNames.length; j++) {
            var name = parameters.parameterNames[j];
            _params[name] = parameters.parameterValues[name];
        }
    };

    var _combineValues = function (values) {
        var result = "";
        for (var i = 0; i < values.length; i++) {
            var curValue = values[i];
            if (curValue != undefined) {
                result = result + "," + curValue;
            }
        }
        if (result != "") {
            result = result.substr(1);
        }
        return result;
    };

    _init();

    //подписываемся на событие изменения URL'a
    _history.subscribe(function (parameterNames, parameterValues) {
        _resetInvokes();
        var initialParams = $.extend({}, _params);
        _params = $.extend({}, parameterValues);

        for (var i = 0; i < parameterNames.length; i++) {
            var name = parameterNames[i];
            if ((initialParams[name] == undefined) || (initialParams[name] != parameterValues[name])) {
                //запускаем обработчик только если значение параметра изменилось
                var parameterValuesCopy = $.extend({}, parameterValues);
                _invokeHandlers(name, parameterValuesCopy);
            }
        }
        for (var parameterName in initialParams) {
            if (parameterValues[parameterName] == undefined) {
                var parameterValuesCopy2 = $.extend({}, parameterValues);
                _invokeHandlers(parameterName, parameterValuesCopy2);
            }
        }
    });

    return {
        getQuery: function () {
            return _history.getQuery();
        },
        setQuery: function (query, pushToHistory) {
            _history.setQuery(query, pushToHistory);
        },

        setParameters: function (parameters, pushToHistory) {
            ///	<summary>
            ///		Помещает параметры в урл. Пример: setParameters({name: "value"})
            ///	</summary>
            ///	<param name="parameters">
            ///		{name: "value"}
            ///	</param>
            ///	<param name="pushToHistory" type="bool">
            ///		помещать ли изменения в history браузера. По умолчанию - true
            ///	</param>
            var params = $.extend({}, _params);
            jQuery.each(parameters, function (name, value) {
                if (value == "") {
                    delete params[name];
                } else {
                    params[name] = value;
                }
                //params[name] = value;
            });
            var query = webUrl.param(params);
            this.setQuery("?" + query, pushToHistory);
        },

        ///handler - функция с двумя параметрами function(changedParameterName, parameters) {}
        registerHandler: function (prefix, handler) {
            _handlers.push({ prefix: prefix, handler: handler });
        },

        /// добавляет значение параметра к группе.
        /// был url: http://localhost/index?param=123,456
        /// после вызова addParameterToGroup("param", "qwe")
        /// стал url:  http://localhost/index?param=123,456,qwe
        addParameterToGroup: function (name, value) {
            var currentValue = _params[name];
            if (currentValue == undefined) {
                this.setParameter(name, value);
                return;
            }
            var values = currentValue.split(",");
            var pos = $.inArray(value, values);
            if (pos == -1) {
                values.push(value);
            }

            this.setParameter(name, _combineValues(values));
        },

        /// удаляет значение параметра из группы.
        /// был url: http://localhost/index?param=123,456
        /// после вызова removeParameterFromGroup("param", "123")
        /// стал url:  http://localhost/index?param=456
        removeParameterFromGroup: function (name, value) {
            var currentValue = _params[name];

            if (currentValue == undefined) {
                return;
            }

            var values = currentValue.split(",");
            var pos = $.inArray(value, values);
            if (pos != -1) {
                delete values[pos];
            }

            this.setParameter(name, _combineValues(values));

        },

        setParameter: function (name, value) {
            var newParams = {};
            newParams[name] = value;
            this.setParameters(newParams);
        },

        getCurrentParameters: function () {
            var params = $.extend({}, _params);
            return params;
        }

    };

})();
