/**
 * Синглтон дерева каталога
 * @namespace $G.Catalog
 */
$G.Catalog.Tree = function() {

    var SCROLL_DURATION = 300;

    var root;
    var eventDispatcher = new $G.EventDispatcher();

    var _$header;
    /**
     * Поднастроить высоту дерева и положение прокрутки окна
     */
    function adjustHeight() {
        if (!_$header)
            _$header = $('#cnt-wrap .eshop-h');
        var _body = Browser.getScrollBody();
        root._$.css({
            height : document.documentElement.clientHeight - _$header.height() - $G.Catalog.WRAP_HEIGHT_OFFSET,
            overflow : 'auto'
        });
        $(_body).animate({
            scrollTop: _$header.offset().top - ($G.Catalog.WRAP_HEIGHT_OFFSET / 2)
        }, SCROLL_DURATION, 'swing');
    }

    function setupVisuals() {
        if (jQuery.browser.opera)
            $('.eshop-tree').css({
                position : 'absolute'
            });
        adjustHeight();
    }

    function _getItemById(id) {
        return root.getChildById(id);
    }

    function loadAndSelectItem(id) {
        $G.getJSON({
            _do  : 'eshop_tree',
            open : 'open',
            id   : id
        }, function(data) {
            root.constructChilds(data, true, true, id);
        });
    }

    return {
        /**
         * Инициализация дерева
         * @param {Object} el DOM-элемент контенера
         * @param {Number} rootId id корневого элемента
         * @param {Number} loadedNodeId id загруженного элемента
         */
        init: function(el, rootId, loadedNodeId) {
            root = new $G.Catalog.Tree.Item(null, 'branch', rootId, 'root');
            root._$ = $(el).scrollTop(0).empty();
            if (loadedNodeId)
                loadAndSelectItem(loadedNodeId, true);
            else
                root.open(true);
            setupVisuals();
            $(window).resize(function() {
                adjustHeight();
            })
        },
        attachEventListener: function(event, handler) {
            eventDispatcher.attachEvent(event, handler);
        },
        removeEventListener: function(event, handler) {
            eventDispatcher.removeEvent(event, handler);
        },
        getRoot: function() {
            return root;
        },
        select: function(item, justHightlight) {
            eventDispatcher.dispatchEvent('select', item, justHightlight);
        },
        construct: function(data) {
            root.constructChilds(data, true)
        },
        openAll: function() {
            root.openAll();
        },
        getFirstLeaf: function() {
            return root.getFirstLeaf();
        },
        selectById: function(id, justHighlight) {
            var item = _getItemById(id);
            if (item) {
                item.select(true, justHighlight);
            } else {
                loadAndSelectItem(id);
            }
        }
    }
}();


/**
 * Класс для элемента дерева
 */
$G.Catalog.Tree.Item = function(parent, type, id, name) {
    this.parent = parent;
    this.type = type;
    this.id = id;
    this.name = name;
    this.childs = new Array();
    this.isRoot = (this.parent == null);
    this.closed = true;
}
$G.Catalog.Tree.Item.SLIDE_DURATION = 200;
$G.Catalog.Tree.Item.prototype = {
    loadChilds: function(drawAfter, selectAfter) {
        var self = this;
        if (this._loading)
            return;
        this._loading = true;
        $G.getJSON({
            _do: 'eshop_tree',
            id: this.id
        }, function(data) {
            self._loading = false;
            self.constructChilds(data, drawAfter, selectAfter);
        });
    },
    constructChilds: function(data, drawAfter, selectAfter, idToSelect) {
        var eventFlag = true;
        this.childs.splice(0, this.childs.length);
        for (var i = 0; i < data.length; i ++) {
            var item = new $G.Catalog.Tree.Item(this, data[i]['type'], data[i]['id'], data[i]['name']);
            item._root = this._root || this;
            item.__childsData = data[i].childs;
            this.childs.push(item);
        }
        if (drawAfter)
            this.drawChilds();
        for (var i = 0; i < this.childs.length; i ++) {
            if (this.childs[i].__childsData)
                this.childs[i].constructChilds(this.childs[i].__childsData, drawAfter);
        }
        if (selectAfter) {
            if (idToSelect) {
                var child = this.getChildById(idToSelect);
                if (child) {
                    child.parent.open(false, true);
                    child.select(false, true);
                }
            } else {
                this.select();
            }
        }

    },
    draw: function() {
        var self = this;
        if (!this.isRoot) {
            var $a = $(document.createElement('a'))
                .attr('href', '#/' + this.id)
                .html(this.name)
                .click(function() {
                    self.select(false, true);
                    return false;
                });
            this._$ = $(document.createElement('li'))
                .addClass(this.type)
                .addClass('closed')
                .append($a)
                .append(document.createElement('em'));
            $(document.createElement('ins'))
                .click(function() {
                    self.toggle();
                })
                .appendTo(this._$);
        }
        if (this.type == 'branch') {
            this._$ul = $(document.createElement('ul')).hide().appendTo(this._$);
        }
        this._drawn = true;
    },
    drawChilds: function() {
        if (!this._drawn)
            this.draw();
        this._$ul.hide().empty();
        for (var i = 0; i < this.childs.length; i ++) {
            this.childs[i].draw();
            this.childs[i]._$.appendTo(this._$ul);
        }
        if (!this.closed)
            this.open();
    },
    /**
     * Выбрать элемент
     * @param {Boolean} [openAfter] открыть дерево
     * @param {Boolean} [justHighlight] только подсветить в таблице
     */
    select: function(openAfter, justHighlight) {
        this.makeSelected();
        if ((this.type == 'branch') && (!this.childs.length)) {
            this.loadChilds(true);
        }
        $G.Catalog.Tree.select(this, justHighlight);

        if (openAfter) {
            if (this.type == 'branch') {
                this.open();
            } else {
                this.parent.open();
            }
        }
    },
    makeSelected: function() {
        var root = this._root || this;
        root._$ul.find('li.active').removeClass('active');
        if (!this.isRoot) {
            this._$.addClass('active');

            var top = this._$.offset().top;
            var rootTop = root._$.offset().top;
            var _scrollTop = root._$.scrollTop();
            var d =  top - rootTop;
            if (d > 0) {
                d =  (top + this._$.find('a').height()) - (rootTop + root._$.height()) + 20;
                if (d < 0)
                    d = 0;
            }
            if (d)
                root._$.stop().animate({
                    scrollTop: _scrollTop + d
                }, $G.Catalog.Tree.Item.SLIDE_DURATION);
        } else {
            root._$.stop().animate({
                scrollTop: 0
            }, $G.Catalog.Tree.Item.SLIDE_DURATION);
        }
    },
    toggle: function() {
        if (this.closed)
            this.open()
        else
            this.close();
    },
    /**
     * Открыть ветку
     */
    open: function(selectAfter, fast, notRecursive) {
        if (this.type == 'leaf')
            return;
        if ((this.parent) && (!notRecursive))
            this.parent.open(false, fast);
        this.closed = false;
        if (!this.childs.length) {
            this.loadChilds(true, selectAfter);
        } else {
            this._$.addClass('open').removeClass('closed');
            if (fast) {
                this._$ul.show();
            } else {
                this._$ul.slideDown($G.Catalog.Tree.Item.SLIDE_DURATION);
            }
            if (selectAfter)
                this.select();
        }
    },
    /**
     * Открывает ветку рекурсивно
     */
    openAll: function(rec) {
        if ((this.childs) && (this.childs.length > 0)) {
            this.open(false, true, rec);
        }
        for (var i = 0; i < this.childs.length; i++)
            this.childs[i].openAll(true);
    },
    /**
     * Закрыть ветку
     */
    close: function() {
        this.closed = true;
        this._$.removeClass('open').addClass('closed');
        this._$ul.slideUp($G.Catalog.Tree.Item.SLIDE_DURATION);
    },
    /**
     * Очистить ветку
     */
    clear: function() {
        if (this._$ul)
            this._$ul.empty();
        this.childs.splice(0, this.childs.length);
    },
    /**
     * Получить потомка по id
     * @param {String} id идентификатор
     * @return {Object}
     */
    getChildById: function(id) {
        for (var i = 0; i < this.childs.length; i++) {
            if (this.childs[i].id == id) {
                return this.childs[i];
            } else {
                var item = this.childs[i].getChildById(id);
                if (item)
                    return item;
            }
        }
        return null;
    },
    /**
     * Получить первуй встретившуюся детальку
     */
    getFirstLeaf: function() {
        if ((!this.childs) || (!this.childs.length) || (this.type == 'leaf'))
            return this;
        return this.childs[0].getFirstLeaf();
    }
}

