var Tree = function(parent, container, info, onload) {
    this.parent = parent;
    this.container = $(container);
    this.info = info;
    this.onload = onload || Prototype.emptyFunction;
    this.onopen = Prototype.emptyFunction;
    
    this.isHeading = info.kind == "heading";
    this.isOpen = false;
    this.childNodes = null;
    this.children = null;
    this.icon = null;
    this.childrenLoaded = false;
    this.filters = [];
    
    this.toString = function() {
        return "Tree()";
    }
    
    this.initialize = function() {
        try {
            if (this.parent != null) {
                var cls = "tocContent";
                if (window.pagePath && this.info.path == window.pagePath) {
                    cls += " tocHere";
                }
                var content = Builder.node("div", {"class": cls, "title": this.info.summary || this.info.title}, this.buildContent());
                if (!this.isHeading) {
                    Event.observe(content, "click", this.click.bindAsEventListener(this));
                }
                this.container.appendChild(content);
            }
            if (this.parent == null || this.info.isparent) {
                this.children = Builder.node("div", {"class": "tocChildren"});
                this.container.appendChild(this.children);
            }
        } catch (e) {
            alert("Tree.initialize: "+e+" ("+e.lineNumber+")");
        }
    }
    
    this.buildContent = function() {
        try {
            var titleText = Builder.node("span", {"class": "tocTitleText"}, this.info.title);
            var titleNode = Builder.node("div", {"class": "tocTitle"}, titleText);
            
            if (this.isHeading) {
                return [titleNode];
            } else {
                var controlNode = Builder.node("div", {"class": "tocControl"});
                Event.observe(controlNode, "click", this.clickToggle.bindAsEventListener(this));
                
                this.loader = $(Builder.node("span", {"class": "tocLoader", "style": "display: none"}));
                
                var bg = "";
                if (this.info.icon) {
                    bg = "background-image: url(\"" + this.getIconImage() + "\");"
                }
                this.icon = Builder.node("div", {"class": "tocIcon", "style": bg});
                
                return [controlNode, this.loader, this.icon, titleNode];
            }
        } catch (e) {
            alert("Tree.buildContent: "+e+" ("+e.lineNumber+")");
        }
    }
    
    this.click = function(event) {
        window.location = this.info.path;
    }
    this.clickToggle = function(event) {
        this.toggle();
        Event.stop(event);
    }
    this.toggle = function() {
        this.isOpen ? this.close() : this.open();
    }
    this.open = function(ls) {
        try {
            if (this.info.isparent) {
                this.isOpen = true;
                this.container.removeClassName("closedNode");
                this.container.addClassName("openNode");
                if (this.childrenLoaded) {
                    //this.onopen();
                } else {
                    this.loadChildren();
                }
            }
        } catch (e) {
            alert("Tree.open: "+e+" ("+e.lineNumber+")");
        }
    }
    this.close = function() {
        if (this.info.isparent) {
            this.container.removeClassName("openNode");
            this.container.addClassName("closedNode");
            this.isOpen = false;
        }
    }
    
    this.openList = function(ls) {
        var head = ls.shift();
        var go = function() {
            if (head) {
                for (var i = 0; i < this.childNodes.length; i++) {
                    if (this.childNodes[i].info.path == head) {
                        this.childNodes[i].openList(ls);
                    }
                }
            } else {
                //this.highlight(window.pagePath);
            }
        }
        go = go.bind(this);
        
        if (this.childrenLoaded) {
            this.open();
            go();
        } else {
            this.onload = go;
            this.open();
        }
    }
    
    this.getIconImage = function() {
        try {
            if (this.info.icon) {
                return "/icons/small/" + this.info.icon + ".png";
            }
        } catch (e) {
            alert("Tree.getIconImage: "+e+" ("+e.lineNumber+")");
        }
    }
    
    this.loadChildren = function() {
        try {
            if (!this.childrenLoaded) {
                this.showLoader();
                var target = "/toc?format=json&path=" + this.info.path;
                this.request = new Ajax.Request(target, {
                    "method": "get",
                    "onSuccess": this.loaded.bind(this),
                    "onFailure": this.failedToLoad.bind(this)
                });
            }
        } catch (e) {
            alert("Tree.loadChildren: "+e+" ("+e.lineNumber+")");
        }
    }
    this.loaded = function(transport) {
        try {
            this.hideLoader();
            this.childrenLoaded = true;
            eval("var json="+transport.responseText);
            var nodeinfo
            for (var i = 0; i < json.length; i++) {
                nodeinfo = json[i]
                this.add(nodeinfo);
            }
            this.onload();
            this.onopen();
        } catch (e) {
            alert("Tree.loaded: "+e+" ("+e.lineNumber+")");
        }
    }
    this.failedToLoad = function(transport) {
        this.hideLoader();
        alert("Failed to load: " + transport.responseText);
    }
    this.showLoader = function() {
        if (this.icon && this.loader) {
            this.icon.hide();
            this.loader.show();
        }
    }
    this.hideLoader = function() {
        if (this.icon && this.loader) {
            this.icon.show();
            this.loader.hide();
        }
    }
    
    this.add = function(nodeinfo) {
        try {
            var isHeading = nodeinfo.kind == "heading";
            var cls;
            if (isHeading) {
                cls = "tocHeading";
            } else {
                cls = "tocNode" + (nodeinfo.isparent ? " closedNode" : "");
            }
            var ncontainer = Builder.node("div", {"class": cls})
            var branch = new Tree(this, ncontainer, nodeinfo);
            branch.initialize();
            this.children.appendChild(ncontainer);
            
            if (nodeinfo.children) {
                for (var i = 0; i < node.info.children.length; i++) {
                    branch.add(nodeinfo.children[i]);
                }
                branch.childrenLoaded = true;
            }
            
            if (this.childNodes == null) {
                this.childNodes = [];
            }
            this.childNodes.push(branch);
        } catch (e) {
            alert("Tree.add: "+e+" ("+e.lineNumber+")");
        }
    }
}
