document.observe("dom:loaded", initBrowser);
var SilvaBrowser;

function initBrowser() {
    var cfg = $('tx_pmtree_pi1_browser_init').value.evalJSON();
    SilvaBrowser = new Browser(cfg);
}

/** Base class for panes in browser
 *
 */
var BrowserPane = Class.create({
    initialize: function(root, id, boxtype, title) {
        this.box_id = id;
        this.title_text = title;
        this.title_state = 'loading';

        root.insert(
            this.root = new Element('div',{'class':'tx_pmtree_pi1_'+boxtype}).update(
                this.title = new Element('p', {'class':'title'}).update(
                    "<span class='checkbox_loading'><a>loading</a></span>"
                )
            ).insert(
                this.content = new Element('div', {'class':'loading'}).update(
                    "loading..."
                )
            )
        );
    },

    destroy: function() {
        this.show();
        this.root.remove();
    },


    updateTitle: function(title, href) {
        this.title_text = title;
        this.title.down().down().update(title).writeAttribute('href',href);
    },

    updateTitleState: function(state) {
        this.title.down().removeClassName('checkbox_'+this.title_state);
        this.title.down().addClassName('checkbox_'+state);
        this.title_state = state;
    },

    updateTitlePopup: function(txt) {
        new Tip(this.title.down(), txt);
    },

    show: function() {
        this.root.show();
    },

    hide: function() {
        this.root.hide();
    }

});

/**
 * Pane showing details for a single sequence
 */
var DetailPane = Class.create(BrowserPane, {
    initialize: function($super, root, id, seq_id, seq_name) {
        $super(root, id, 'detail');
        this.seq_id = seq_id;
        this.seq_name = seq_name;
        this.updateTitle(seq_name,"browser/#l"+seq_id);
        this.title.observe('click', this.cartAction.bind(this));
    },

    cartAction: function(event) {
        event.stop();
        var act = (this.title_state=='none'?'add':'del');
        this.updateTitleState('loading');
        callServer('cart', {id:this.seq_id, obj:'leaf', action:act},
                   this.ajaxCallback.bind(this));
    },

    load: function(opt) {
        if (!opt) opt = {}
        opt.id=this.seq_id;
        opt.action='detail';
        callServer('browser', opt, this.ajaxCallback.bind(this));
        callServer('cart', {id:this.seq_id,obj:'leaf',action:'info'},
                   this.ajaxCallback.bind(this));
    },

    ajaxCallback: function(json) {
        if (json.html) {
            this.content.update('<div class="detail">'+json.html+'</div>');
            this.content.removeClassName('loading');
            this.content.select('.fullDetailBtn').each((function(e) {
                createDetailPopup(e,this.seq_name,this.seq_id);
                e.observe('click',function(f){f.stop()});
            }).bind(this));
        }
        if (json.selected != null) {
            this.updateTitleState(json.selected*1==1?'all':'none');
            if (this.cartSelected != null && json.selected != this.cartSelected) {
                Event.fire(this.root, 'slv:cart', {pane_id:this.box_id});
            }
            this.cartSelected = json.selected;
        }
        if (json.cartSize) {
            updateCartSize(json.cartSize);
        }
    }
});

/**
 * Pane showing Nodes and Leaves
 */
var NodesPane = Class.create(BrowserPane, {
    initialize: function($super, root, id, node_id, node_name) {
        $super(root,id,'browserbox');
        this.selected = null;
        this.from = 0;
        this.showLeafTab = false;
        this.node_id = node_id;

        this.content.update(
            "<div class='tabs'></div>"
            + "<div class='tabsNavi'></div>"
            + "<div class='content'></div>"
            );

        this.tabheader = this.content.down();
        this.pagebrowser = this.tabheader.next();
        this.listpanel = this.pagebrowser.next();

        this.updateTitle(node_name,"browser/#n"+node_id);

        this.pagebrowser.observe('click', (function(e) {
            e.stop();
            var a = e.findElement('a');
            if (a) {
                if (a.innerHTML == "prev") {
                    this.from -= this.pageLimit;
                } else {
                    this.from += this.pageLimit;
                }
                this.load();
            }
        }).bind(this));

        this.listpanel.observe('click', (function(e) {
            var elem = e.findElement('a');
            if (elem) {
                var memo = {
                    is_leaf: elem.readAttribute('href').match(/browser\/#l/),
                    pane_id: this.box_id,
                    node_id: elem.readAttribute('href').replace(/browser\/#./,''),
                    node_name: elem.innerHTML
                };
                // e.memo = memo; (prototype API, yet does not work on IE)
                elem.memo = memo; // seems to work
            } else {
                e.stop();
            }
        }).bind(this));

        this.tabheader.observe('click', this.tabClickHandler.bind(this));
        this.title.observe('click', this.cartAction.bind(this));
    },

    cartAction: function(event) {
        event.stop();
        var act = (this.title_state=='none'?'add':'del');
        this.updateTitleState('loading');
        callServer('cart', {id:this.node_id, obj:'node', action:act},
                   this.ajaxCallback.bind(this));
    },

    select: function(id) {
        this.selected = id;
        this.root.select('a').each(function(e) {
            e.up().removeClassName('open');
            e.up().removeClassName('select');
            if (e.readAttribute('href') == "browser/#n" + id) {
                e.up().addClassName('open');
            }
            if (e.readAttribute('href') == "browser/#l" + id) {
                e.up().addClassName('select');
            }
        });
    },

    showTabs: function() {
        var txt = "";

        if (this.node_size > 0) {
            txt += "<span class='node "
                +  ((this.showLeafTab)?'closedNode':'openedNode')
                +  "'><a href='browser/#'>(" + this.node_size + ")</a></span>";
        }

        if (this.leaf_size > 0) {
            txt += "<span class='element "
                +  ((this.showLeafTab)?'openedElement':'closedElement')
                +  "'><a href='browser/#'>(" + this.leaf_size + ")</a></span>";
        }

        this.tabheader.update(txt);

    },


    showNodes: function() {
        if (this.node_size == 0) {
            this.setShowLeafTab(true);
            return;
        }
        var txt="<div class='nodes'><ul>";
        this.node_data.each(function(node,i) {
            txt += '<li class="folder"><a href="browser/#n'+node.id+'">'+node.name+'</a></li>';
        });
        txt += "</ul></div>";

        this.pagebrowser.update("");
        this.listpanel.update(txt);
        this.select(this.selected);
        if (this.cartNodes) {
            this.showNodesSelected();
        }
    },

    showNodesSelected: function() {
        this.root.select('.cartInfo').each(Element.remove);
        this.root.select('.marked').invoke('removeClassName','marked');
        var arr =  this.listpanel.select('li');
        arr.push(this.title.down());
        arr.each((function(node) {
            var nodeId = node.down().readAttribute('href').replace(/browser\/#n/,'');
            var cartNode = this.cartNodes.find(function(n) { return n.id == nodeId; });
            if (cartNode) {
                node.addClassName('marked');

                var num = cartNode.sel/cartNode.accs*100;
                var text = Math.round(num);
                var alt = cartNode.sel+" of "+cartNode.accs + " sequences selected";
                if (num<1) {
                    text = Math.round(num*100)/100;
                } else if (num <10) {
                    text = Math.round(num*10)/10;
                }

                var span = new Element('span', {'class':'cartInfo'}).update("("+text+"%)");
                node.insert(span);
                new Tip (span, alt);
            }
        }).bind(this));
    },

    showLeaves: function() {
        if (!this.leaf_data) {
            this.load();
            return;
        }
        if (this.leaf_size > this.leaf_data.length) {
            var txt = " ";
            if (this.from > 0) {
                txt += "<span class='prev'><a href='browser/#'>prev</a></div>";
            }
            txt += "(" + Math.ceil((this.from + 1) / this.pageLimit)
                +  "/" + Math.ceil(this.leaf_size / this.pageLimit) + ")";
            if (this.from + this.leaf_data.length < this.leaf_size) {
                txt += "<span class='next'><a href='browser/#'>next</a></div>";
            }
            this.pagebrowser.update(txt);
        }

        var txt=           "<div class='elements'><ul>";
        this.leaf_data.each(function(node,i) {
            txt += '<li class="sheet"><a href="browser/#l'+node.id+'">'+node.name+'</a></li>';
        });
        txt += "</ul></div>";

        this.listpanel.update(txt);
        this.select(this.selected);
        if (this.cartLeaves) {
            this.showLeavesSelected();
        }
    },

    showLeavesSelected: function() {
        this.root.select('.marked').invoke('removeClassName','marked');
        var items = this.listpanel.select('LI');
        this.cartLeaves.each(function(leaf) {
            var href = "browser/#l" + leaf.id;
            var item = items.find(function(n) { return n.down().readAttribute('href')==href;});
            if (item) item.addClassName('marked');
        });

    },

    load: function(args) {
        if (!args) args = {};
        args.action = 'node';
        args.id = this.node_id;
        if (this.showLeafTab) {
            args.from = this.from;
            args.action = 'leaf';
        }
        callServer('browser', args, this.ajaxCallback.bind(this));
        this.reloadCart();
    },

    reloadCart: function() {
        this.updateTitleState('loading');
        callServer('cart', {action:'info',obj:'node', id:this.node_id},
                   this.ajaxCallback.bind(this));
    },

    ajaxCallback: function(json) {
        if (json.pageLimit) {
            this.pageLimit = json.pageLimit * 1;
        }

        if (json.nodes) {
            this.node_data = json.nodes;
            this.node_size = json.nodes.size();
            if (!this.showLeafTab) {
                this.showNodes();
                      }
        }

        if (json.leafCount) {
            this.leaf_size = json.leafCount * 1;
            this.showTabs();
        }

        if (json.leaves) {
            this.leaf_data = json.leaves;
            if (this.showLeafTab) {
                this.showLeaves();
            }
        }

        if (this.leaf_data || this.node_data) {
            this.content.removeClassName('loading');
        }

        if (json.total) {
            if (this.cartSelected != null &&
                this.cartSelected != json.selected *1) {
                Event.fire(this.root, 'slv:cart', {pane_id:this.box_id});
            }
            this.cartTotal = json.total * 1;
            this.cartSelected = json.selected *1;


            var state;
            var nodeTxt = "This group contains <b>"+json.total+"</b> sequence entries.";
            if (this.cartSelected == 0) {
                state = 'none';
                nodeTxt += "<br/>None of them are currently in your cart."
                        + "<br/>Clicking here will <b>add</b> them to your cart.";
            } else if (this.cartTotal == this.cartSelected) {
                state = 'all';
                nodeTxt += "<br/>All of them are currently in you cart."
                        + "<br/>Clicking here will <b>remove</b> them from your cart.";
            } else {
                state = 'subset';
                nodeTxt += "<br/><b>"+this.cartSelected
                        +  "</b> of them are currently in your cart."
                        +  "<br/>Clicking here will <b>remove</b> them from your cart.";
            }
            this.updateTitlePopup(nodeTxt);
            this.updateTitleState(state);
        }

        if (json.cartNodes) {
            this.cartNodes = json.cartNodes;
            this.showNodesSelected();
        }
        if (json.cartLeaves) {
            this.cartLeaves = json.cartLeaves;
            if (this.showLeafTab) {
                this.showLeavesSelected();
            }
        }
        if (json.cartSize) {
            updateCartSize(json.cartSize);
        }

    },


    tabClickHandler: function(e) {
        e.stop();
        var el = e.findElement('span');
        if (!el) return;
        this.setShowLeafTab(!el.hasClassName('node'));
    },

    setShowLeafTab: function(b) {
        if (b == this.showLeafTab) return;
        this.showLeafTab = b;
        if (b) {
            this.showLeaves();
        } else {
            this.showNodes();
        }
        this.showTabs();
    }
});

/**
 * Controller class for browser
 */
var Browser = Class.create({
     visibleRange: 4,
     initialize: function(cfg) {
         this.root = $("tx_pmtree_pi1_root");
         this.panes = [];
         this.num_panes = 0;
         this.root.observe('click', this.clickHandler.bind(this));
         this.visibleFirst = 0;

         this.buttonScrollLeft = $('tx_pmtree_pi1_navi_left');
         this.buttonScrollLeft.observe('click', (function(e){
             e.stop();
             this.scroll(this.visibleFirst-1);
         }).bind(this));

         this.buttonScrollRight = $('tx_pmtree_pi1_navi_right');
         this.buttonScrollRight.observe('click', (function(e) {
             e.stop();
             this.scroll(this.visibleFirst+this.visibleRange);
         }).bind(this));

         this.path_container = $('tx_pmtree_pi1_path');
         this.path_container.observe('click', this.pathClickHandler.bind(this));
         this.path = [];

         this.root.observe('slv:cart', this.cartAction.bind(this));
         this.root.update("");

         this.setPath(cfg);

         $('tx_pmtree_dbselect').observe('change', this.dbChanged.bind(this));
         $('tx_pmtree_taxselect').observe('change', this.taxChanged.bind(this));

         document.observe('slv:reloadCart', (function() {
             this.panes.invoke('reloadCart');
         }).bind(this));;
     },

     dbChanged: function(event){
        location.href='/browser/'+getDB().split("-")[0];
     },

     taxChanged: function(event){
         var taxname=$F('tx_pmtree_taxselect');
         var regex = '/browser/'+getDB().split("-")[0]+'/[\\\w/]+';
         if(location.href.match(regex)) {
            callServer('browser',{action:'path', 'taxname':taxname}, function(){location.href='/browser/'+getDB().split("-")[0];});
         } else {
            callServer('browser',{action:'path', 'taxname':taxname}, this.setPath.bind(this));
         }
     },

     cartAction: function(event) {
         event.stop();
         var pane_id = event.memo.pane_id;
         var newState = this.panes[pane_id].title_state;
         for (var i=0; i< pane_id; ++i) {
             this.panes[i].reloadCart();
         }
         for (var i=pane_id+1; i<=this.num_panes; i++) {
             this.panes[i].reloadCart();
         }
     },

     clickHandler: function(e) {
         var elem = e.findElement('a');
         if (elem.memo) {
             var memo = elem.memo;
             var num = memo.pane_id;

             if (memo.is_leaf) {
                 this.openDetailPane(num+1, memo.node_id, memo.node_name);
             } else {
                 this.openNodePane(num+1, memo.node_id, memo.node_name);
             }
             this.panes[num+1].load();
             e.stop();
         }
     },

     pathClickHandler: function(e) {
         e.stop();
         var a = e.findElement('a');
         if (a) {
             var num = (a.readAttribute('href') || "").replace(/browser\/#/,'') * 1;
             this.scroll(num);
         }
     },

     openPane: function(num, obj, nodeId, nodeName) {
         for (var i=this.panes.size()-1;i>=num;--i) {
             this.panes.pop().destroy();
             this.path.pop().remove();
         }

         this.path[num] = new Element('span', {'class':'pathVisible'});
         this.path[num].update('<a href="browser/#'+num+'">'+nodeName+'</a>');
         this.path_container.insert(this.path[num]);
         if (num>0) {
             this.path[num-1].addClassName('arrowBlack');
         }

         this.panes[num] = obj;
         if (num>0) {
            this.panes[num-1].select(nodeId);
         }
         this.num_panes = num;
         this.scroll(num);
     },

     openNodePane: function(num, nodeId, nodeName) {
         var np = new NodesPane(this.root, num, nodeId, nodeName);
         this.openPane(num, np, nodeId, nodeName);
     },

     openDetailPane: function(num, nodeId, nodeName) {
         var lp = new DetailPane(this.root, num, nodeId, nodeName);
         this.openPane(num, lp, nodeId, nodeName);
     },


     setPath: function(cfg) {
         if (cfg.error){
             $('tx_pmtree_pi1_root').update(cfg.error);
             return;
         }
         var path=cfg.path;
         var leaf = null;

         if (path.last().leaf_id) {
             leaf = path.pop();
         }

         path.each((function(p, i) {
             this.openNodePane(i, p.node_id, p.node_name);
             this.panes[i].load({save:false});
         }).bind(this));

         if (leaf) {
             this.openDetailPane(path.length,leaf.leaf_id,leaf.leaf_name);
             this.panes[path.length].load({save:false});
         }
     },

     scroll: function(num) {
         if (num >= this.visibleFirst + this.visibleRange) {
             this.visibleFirst = num - this.visibleRange + 1;
         } else if (num < this.visibleFirst) {
             this.visibleFirst = num;
         }

         var i = 0;
         for (; i<this.visibleFirst; i++) {
             this.panes[i].hide();
             this.path[i].removeClassName('pathVisible');
         }

         for (;  i < this.visibleFirst + this.visibleRange
              && i <= this.num_panes; i++) {
             this.panes[i].show();
             this.path[i].addClassName('pathVisible');
         }

         for (; i <= this.num_panes; i++) {
             this.panes[i].hide();
             this.path[i].removeClassName('pathVisible');
         }

         if (this.visibleFirst > 0) {
             this.buttonScrollLeft.show();
         } else {
             this.buttonScrollLeft.hide();
         }

         if (this.visibleFirst + this.visibleRange <= this.num_panes) {
             this.buttonScrollRight.show();
         } else {
             this.buttonScrollRight.hide();
         }
     }
 });


/*
 Local Variables:
 mode:js2
 indent-tabs-mode:nil
 End:
*/

