
/**
 * Javascript object that provides pretty much everything needed by the by-gene search form tab.
 * 
 * Requires:
 *      Prototype
 *      jQuery
 *      utilities.js
 */
function ByGeneSearchSupport() {
    
    // instance data
    
    this.jqGeneSymbolTextInput = jQuery("#panel\\:featureSearchForm\\:geneSymbol");
    this.jqSearchButton = jQuery("#panel\\:featureSearchForm\\:searchButton");

    // instance methods

    this.initBindings = function() {
        try {
            var support = this;
            // this handler is needed to overcome an IE-specific bug,
            //
            // see: https://jira.jboss.org/jira/browse/AJSF-16
            //      https://jira.jboss.org/jira/browse/AJSF-29
            //
            // this might not be a problem in new richfaces versions
            // (or new versions of anything using ajax4jsf) but
            // from google searches I'm not 100% convinced
            this.jqGeneSymbolTextInput.keypress(function(event) {
                try {
                    if (!event) return;
                    var key = event.which || event.keyCode;
                    if (key != Event.KEY_RETURN) return;
                    event.returnValue = false;
                    event.cancelBubble = true;
                    var attrVal = support.jqGeneSymbolTextInput.attr("value");
                    support.jqSearchButton.click();
                    return false;
                } catch (err) {
                    alert(err.name + " in geneSymbol.onkeypress: " + err.message);
                }
            });
        } catch (err) {
            alert(err.name + " in ByGeneSearchSupport.initBindings: " + err.message);
        }
    }
    
}

// =====================================================================================================

function TableTabSupport(myTabName, ratingClassNames) {
    
    // instance data
    
    this.cookieName = "gcnmp-seen";
    this.cookieExpiryDays = 14;
    this.cursors = [];
    this.otherTabName = (myTabName == "amps") ? "dels" : "amps";
    this.summaryTabId = "#panel\\:featureSearch\\:" + myTabName;
    this.otherSummaryTabId = "#panel\\:featureSearch\\:" + this.otherTabName;
    this.summaryTableId = "#panel\\:featureSearch\\:" + myTabName + "Table";
    this.genesTableId = "#" + myTabName + "GenesTable";
    this.jqBody = jQuery("body")
    this.jqSummaryTab = jQuery(this.summaryTabId);
    this.jqSummaryTable = jQuery(this.summaryTableId);
    this.jqGenesTable = jQuery(this.genesTableId);
    this.jqGenesDisplay = this.jqGenesTable.find("td.peakGenes");
    this.ratingClasses = ratingClassNames;

    // instance methods
    
    this.getSrcTagName = function(event) {
        try {
            if (event == null) return null;
            var srcElt = Event.element(event);
            if (srcElt == null) return null;
            var tagName = srcElt.tagName;
            if (tagName == null) return null;
            return tagName.toUpperCase();
        } catch (err) {
            alert(err.name + " in getSrcTagName: " + err.message);
        }
    }
    
    this.getRatingClass = function(row, tr) {
        try {
            var ratingClass = jQuery.data(tr, "cn-rating-class");
            if (ratingClass != null) return ratingClass;
            var numClasses = this.ratingClasses.length;
            for (var i = 0; i != numClasses; i++) {
                var rc = this.ratingClasses[i];
                if (!row.hasClass(rc)) continue;
                jQuery.data(tr, "cn-rating-class", rc);
                return rc;
            }
        } catch (err) {
            alert(err.name + " in getRatingClass: " + err.message);
        }
    }
    
    this.getUniqueElement = function(elementId, elementDesc) {
        try {
            if (elementId.charAt(0) != "#") {
                elementId = "#" + elementId;
            }
            var element = jQuery(elementId);
            if (element.length == 1) return element;
            throw new Error(elementDesc + " not found, id=" + elementId);
        } catch (err) {
            alert(err.name + " in getUniqueElement: " + err.message);
        } 
    }
    
    this.maintainSymbolDataBackground = function(selectedRow, tr) {
        try {
            this.jqSummaryTable.find("tr.selected").removeClass("selected");
            selectedRow.addClass("selected");
            var selectedType = this.getRatingClass(selectedRow, tr);
            var tab = this.jqSummaryTab;
            var tabElt = tab.get(0);
            var prevSelectedType = jQuery.data(tabElt, "cn-selected-type");
            tab.find(".genes-view").each(function() {
                var target = jQuery(this);
                if (prevSelectedType == null) {
                    target.removeClass("nogenes");
                }
                if (selectedType != prevSelectedType) {
                    if (prevSelectedType != null) {
                        target.removeClass(prevSelectedType);
                    }
                    target.addClass(selectedType);
                }
            });
            var ul = this.jqGenesDisplay.find("ul");
            ul.addClass(selectedType);
            ul.find("li.selected").removeClass("selected");
            jQuery.data(tabElt, "cn-selected-type", selectedType);
        } catch (err) {
            alert(err.name + " in maintainSymbolDataBackground: " + err.message);
        }
    }
    
    this.restoreSymbolDataToPreviousSelectedRow = function() {
        try {
            var prevSelectedRow = jQuery.data(this.jqSummaryTable.get(0), "cn-selected-row");
            if (prevSelectedRow == null) return;
            var symbols = this.clearGeneSymbols();
            if (symbols.length > 0) {
                // put the data back where it belongs
                jQuery(prevSelectedRow).find(".geneSymbolsContainer").append(symbols.get(0));
            }
        } catch (err) {
            alert(err.name + " in restoreSymbolDataToPreviousSelectedRow: " + err.message);
        }
    }
    
    this.clearGeneSymbols = function() {
        try {
            var symbols = this.jqGenesDisplay.find(".geneSymbols");
            if (symbols.length > 0) {
                // stop showing the data
                symbols.addClass("hidden");
                // gc the handlers we previously added
                symbols.find("li").unbind("click");
                return symbols;
            }
        } catch (err) {
            alert(err.name + " in clearGeneSymbols: " + err.message);
        }
    }
    
    this.pushCursor = function(newCursor) {
        try {
            var currentCursor = this.jqBody.css("cursor");
            currentCursor = !currentCursor ? "default" : currentCursor;
            this.cursors.push(currentCursor);
            this.jqBody.css("cursor", newCursor);
        } catch (err) {
            alert(err.name + " in pushCursor: " + err.message);
        }
    }
    
    this.popCursor = function() {
        try {
            var cursor = this.cursors.pop();
            cursor = !cursor ? "default" : cursor;
            this.jqBody.css("cursor", cursor);
        } catch (err) {
            alert(err.name + " in popCursor: " + err.message);
        }
    }
    
    this.initCursor = function() {
        try {
            this.cursors.length = 0;
            this.popCursor();
        } catch (err) {
            alert(err.name + " in initCursor: " + err.message);
        }
    }
    
    this.getHelpMessage = function() {
        try {
            return this.jqGenesTable.find("td.peakGenes p");
        } catch (err) {
            alert(err.name + " in getHelpMessage: " + err.message);
        }
    }
    
    this.removeHelpMessage = function() {
        try {
            var helpMsg = this.getHelpMessage();
            helpMsg.stop(); // abort any effects
            this.removeQuietly(helpMsg);
        } catch (err) {
            alert(err.name + " in removeHelpMessage: " + err.message);
        }
    }
        
    this.removeQuietly = function(obj) {
        try {
            var target = (obj instanceof jQuery) ? obj : jQuery(obj);
            target.remove(); 
        } catch (err) {
            // protect against race condition where node(s) already removed (e.g. in an effect)
        }
    }
    
    this.useHelpPrefs = function() {
        try {
            var seen = this.incrementCookie();
            switch (seen) {
                case 0  : return { type:"letter", fade:7000, opacity:0.75 };
                case 1  : return { type:"letter", fade:4000, opacity:0.70 };
                case 2  : return { type:"word",   fade:3000, opacity:0.65 };
                default : return { type:"silent", fade:1000, opacity:0.60 };
            }
        } catch (err) {
            alert(err.name + " in useHelpPrefs: " + err.message);
        }
    }
    
    this.incrementCookie = function() {
        try {
            var value = eval(jQuery.cookie(this.cookieName));
            value = (value == null) ? 0 : value;
            var nextValue = Math.min(value + 1, 3);
            jQuery.cookie(this.cookieName, nextValue, {expires:this.cookieExpiryDays});
            return value;
        } catch (err) {
            alert(err.name + " in incrementCookie: " + err.message);
        }
    }
    
}
    
// =====================================================================================================

/**
 * Javascript object that provides pretty much everything needed by the by-gene amplifications or deletions tab.
 * 
 * Requires:
 *      Prototype
 *      jQuery
 *      jQuery jTypeWriter plugin
 *      jQuery Cookie plugin
 *      jQuery Dimensions plugin (can be eliminated when RichFaces and jQuery are updated)
 *      jQuery BGIFrame plugin (not required but usually a good idea with IE)
 *      
 */
function GeneTableTabSupport(myTabName) {
    
    // instance data
    
    var ratingClasses = [ "rate", "ratepeaksig", "ratenonpeaksig", "ratepeaknonsig" ];
    this.tabSupport = new TableTabSupport(myTabName, ratingClasses);
    this.jqGeneSymbolTextInput = jQuery("#panel\\:featureSearchForm\\:geneSymbol");
    this.jqSearchButton = jQuery("#panel\\:featureSearchForm\\:searchButton");

    // instance methods
    
    this.maintainGenesDisplayHeight = function(symbols) {
        try {
            var viewTd = this.tabSupport.jqGenesDisplay.get(0);
            var availHeight = jQuery.data(viewTd, "cn-genes-height");
            if (availHeight == null) {
                availHeight = this.getSummaryTableBodyInnerHeight()-20;
                availHeight = Math.max(availHeight, 200);
                // we use the empty TD to decide how much space we have
                jQuery.data(viewTd, "cn-genes-height", availHeight);
            }
            // and we constrain the UL accordingly
            symbols.css("max-height", availHeight);
        } catch (err) {
            alert(err.name + " in GeneTableTabSupport.maintainGenesDisplayHeight: " + err.message);
        }
    }
    
    this.getSummaryTableBodyInnerHeight = function() {
        try {
            var tableBody = this.tabSupport.jqSummaryTable.find("tbody");
            var ih = tableBody.innerHeight();
            if (ih > 0) return ih;
            // IE doesn't have an inner height on borderlesss elements
            return tableBody.height();
        } catch (err) {
            alert(err.name + " in GeneTableTabSupport.getSummaryTableBodyInnerHeight: " + err.message);
        }
    }
    
    this.moveSymbolDataFromSelectedRow = function(selectedRow, symbols) {
        try {
            this.tabSupport.removeHelpMessage();
            this.tabSupport.jqGenesDisplay.append(symbols.get(0));
            var geneLiStyles = {
                "font-weight": "normal",
                "font-size": "10px",
                "line-height": "14px"
            };
            var support = this;
            var items = symbols.find("li"); 
            items.each(function() {
                var target = jQuery(this);
                target.css(geneLiStyles);
                target.click(function() {
                    var geneLi = jQuery(this);
                    geneLi.addClass("selected");
                    support.tabSupport.pushCursor('wait');
                    var gs = geneLi.text();
                    support.jqGeneSymbolTextInput.attr("value", gs);
                    support.jqSearchButton.click();
                });
            });
            symbols.removeClass("hidden");
            jQuery.data(this.tabSupport.jqSummaryTable.get(0), "cn-selected-row", selectedRow.get(0));
        } catch (err) {
            alert(err.name + " in GeneTableTabSupport.moveSymbolDataFromSelectedRow: " + err.message);
        }
    }

    this.selectRow = function(tr, event) {
        this.tabSupport.pushCursor("wait");
        // process the select in another thread because moving many gene symbols takes time
        var support = this;
        var job = function() {
            support.selectRowNow(tr, event);
            support.tabSupport.popCursor();
        };
        // leave time for the browser to update the cursor display and then run job
        setTimeout(job, 10);
    }
    
    this.selectRowNow = function(tr, event) {
        try {
            if (this.tabSupport.getSrcTagName(event) == "A") return;
            // this is an event we will handle here
            event.returnValue = false;
            event.cancelBubble = true;
            var selectedRow = jQuery(tr);
            var symbolsContainer = selectedRow.find(".geneSymbolsContainer");
            var symbols = symbolsContainer.find(".geneSymbols");
            this.maintainGenesDisplayHeight(symbols);
            if (symbols.length > 0) {
                this.tabSupport.restoreSymbolDataToPreviousSelectedRow();
                this.moveSymbolDataFromSelectedRow(selectedRow, symbols);
                this.tabSupport.maintainSymbolDataBackground(selectedRow, tr);
            }
        } catch (err) {
            alert(err.name + " in GeneTableTabSupport.selectRow: " + err.message);
        }
    }
    
    this.onTabEnter = function() {
        try {
            // hide other tabs
            this.tabSupport.getUniqueElement("#panel\\:featureSearch\\:sum", "tab").css("display", "none");
            this.tabSupport.getUniqueElement(this.tabSupport.otherSummaryTabId, "tab").css("display", "none");
            // hide text message to stop position flash before heading resize (if still present in tab)
            var helpMsg = this.tabSupport.getHelpMessage();
            helpMsg.addClass("hidden");
            // show current tab
            this.tabSupport.jqSummaryTab.css("display", "inline");
            // fix cursor if its broken
            this.tabSupport.initCursor();
            // show text message and animate (if still present in tab)
            helpMsg.removeClass("hidden");
            var helpPrefs = this.tabSupport.useHelpPrefs();
            // decouple help animation from other browser activity
            var helpJob = function() {
                if (helpPrefs.type == "silent") {
                    helpMsg.fadeTo(helpPrefs.duration, helpPrefs.opacity);
                } else {
                    helpMsg.jTypeWriter({duration:1, type:helpPrefs.type, onComplete:function(){
                        helpMsg.fadeTo(helpPrefs.duration, helpPrefs.opacity);
                    }});
                }
            };
            setTimeout(helpJob, 10);
        } catch (err) {
            alert(err.name + " in GeneTableTabSupport.onTabEnter: " + err.message);
        }
    }

    this.initBindings = function() {
        try {
            var support = this;
            this.tabSupport.jqSummaryTable.find("tbody tr").click(function(event){
                support.selectRow(this, event);
            });
        } catch (err) {
            alert(err.name + " in GeneTableTabSupport.initBindings: " + err.message);
        }
    }
    
}

// =====================================================================================================

/**
 * Javascript object that provides pretty much everything needed by the by-tumor search form tab.
 * 
 * Requires:
 *      Prototype
 *      jQuery
 *      utilities.js
 */
function ByTumorSearchSupport() {
    
    // instance data
    
    this.jqTumorTypeTextInput = jQuery("#panel\\:featureSearchForm\\:tumorType");
    this.jqSearchButton = jQuery("#panel\\:featureSearchForm\\:searchButton");

    // instance methods

    this.initBindings = function() {
        try {
            var support = this;
            // this handler is needed to overcome an IE-specific bug,
            //
            // see: https://jira.jboss.org/jira/browse/AJSF-16
            //      https://jira.jboss.org/jira/browse/AJSF-29
            //
            // this might not be a problem in new richfaces versions
            // (or new versions of anything using ajax4jsf) but
            // from google searches I'm not 100% convinced
//            this.jqTumorTypeTextInput.keypress(function(event) {
//                try {
//                    if (!event) return;
//                    var key = event.which || event.keyCode;
//                    if (key != Event.KEY_RETURN) return;
//                    event.returnValue = false;
//                    event.cancelBubble = true;
//                    var attrVal = support.jqTumorTypeTextInput.attr("value");
//                    support.jqSearchButton.click();
//                    return false;
//                } catch (err) {
//                    alert(err.name + " in tumorType.onkeypress: " + err.message);
//                }
//            });
        } catch (err) {
            alert(err.name + " in ByTumorSearchSupport.initBindings: " + err.message);
        }
    }
    
}

// =====================================================================================================

/**
 * Javascript object that provides pretty much everything needed by the by-tumor amplifications or deletions tab.
 * 
 * Requires:
 *      Prototype
 *      jQuery
 *      jQuery jTypeWriter plugin
 *      jQuery Cookie plugin
 *      jQuery Dimensions plugin (can be eliminated when RichFaces and jQuery are updated)
 *      jQuery BGIFrame plugin (not required but usually a good idea with IE)
 *      
 */
function TumorTableTabSupport(myTabName) {
    
    // instance data

    var ratingClasses = [ "tumorpeak" ];
    this.tabSupport = new TableTabSupport(myTabName, ratingClasses);
    this.jqGeneSymbolTextInput = jQuery("#panel\\:byGeneSearchForm\\:geneSymbol");
    this.jqGeneSearchButton = jQuery("#panel\\:byGeneSearchForm\\:geneSearchButton");
    
    // instance methods
    
    this.maintainGenesDisplayHeight = function(symbols) {
        try {
            var viewTd = this.tabSupport.jqGenesDisplay.get(0);
            var availHeight = jQuery.data(viewTd, "cn-genes-height");
            if (availHeight == null) {
                availHeight = this.getSummaryTableBodyInnerHeight()-20;
                availHeight = Math.max(availHeight, 200);
                // we use the empty TD to decide how much space we have
                jQuery.data(viewTd, "cn-genes-height", availHeight);
            }
            // and we constrain the UL accordingly
            symbols.css("max-height", availHeight);
        } catch (err) {
            alert(err.name + " in TumorTableTabSupport.maintainGenesDisplayHeight: " + err.message);
        }
    }
    
    this.getSummaryTableBodyInnerHeight = function() {
        try {
            var tableBody = this.tabSupport.jqSummaryTable.find("tbody");
            var ih = tableBody.innerHeight();
            if (ih > 0) return ih;
            // IE doesn't have an inner height on borderlesss elements
            return tableBody.height();
        } catch (err) {
            alert(err.name + " in TumorTableTabSupport.getSummaryTableBodyInnerHeight: " + err.message);
        }
    }
    
    this.moveSymbolDataFromSelectedRow = function(selectedRow, symbols) {
        try {
            this.tabSupport.removeHelpMessage();
            this.tabSupport.jqGenesDisplay.append(symbols.get(0));
            var geneLiStyles = {
                "font-weight": "normal",
                "font-size": "10px",
                "line-height": "14px"
            };
            var support = this;
            var items = symbols.find("li"); 
            items.each(function() {
                var target = jQuery(this);
                target.css(geneLiStyles);
                target.click(function() {
                    var geneLi = jQuery(this);
                    geneLi.addClass("selected");
                    support.tabSupport.pushCursor('wait');
                    var gs = geneLi.text();
                    support.jqGeneSymbolTextInput.attr("value", gs);
                    support.jqGeneSearchButton.click();
                });
            });
            symbols.removeClass("hidden");
            jQuery.data(this.tabSupport.jqSummaryTable.get(0), "cn-selected-row", selectedRow.get(0));
        } catch (err) {
            alert(err.name + " in TumorTableTabSupport.moveSymbolDataFromSelectedRow: " + err.message);
        }
    }

    this.selectRow = function(tr, event) {
        this.tabSupport.pushCursor("wait");
        // process the select in another thread because moving many gene symbols takes time
        var support = this;
        var job = function() {
            support.selectRowNow(tr, event);
            support.tabSupport.popCursor();
        };
        // leave time for the browser to update the cursor display and then run job
        setTimeout(job, 10);
    }
    
    this.selectRowNow = function(tr, event) {
        try {
            if (this.tabSupport.getSrcTagName(event) == "A") return;
            // this is an event we will handle here
            event.returnValue = false;
            event.cancelBubble = true;
            var selectedRow = jQuery(tr);
            var symbolsContainer = selectedRow.find(".geneSymbolsContainer");
            var symbols = symbolsContainer.find(".geneSymbols");
            this.maintainGenesDisplayHeight(symbols);
            if (symbols.length > 0) {
                this.tabSupport.restoreSymbolDataToPreviousSelectedRow();
                this.moveSymbolDataFromSelectedRow(selectedRow, symbols);
                this.tabSupport.maintainSymbolDataBackground(selectedRow, tr);
            }
        } catch (err) {
            alert(err.name + " in TumorTableTabSupport.selectRowNow: " + err.message);
        }
    }
    
    this.onTabEnter = function() {
        try {
            // hide other tabs
            this.tabSupport.getUniqueElement("#panel\\:featureSearch\\:sum", "tab").css("display", "none");
            this.tabSupport.getUniqueElement(this.tabSupport.otherSummaryTabId, "tab").css("display", "none");
            // hide text message to stop position flash before heading resize (if still present in tab)
            var helpMsg = this.tabSupport.getHelpMessage();
            helpMsg.addClass("hidden");
            // show current tab
            this.tabSupport.jqSummaryTab.css("display", "inline");
            // fix cursor if its broken
            this.tabSupport.initCursor();
            // show text message and animate (if still present in tab)
            helpMsg.removeClass("hidden");
            var helpPrefs = this.tabSupport.useHelpPrefs();
            // decouple help animation from other browser activity
            var helpJob = function() {
                if (helpPrefs.type == "silent") {
                    helpMsg.fadeTo(helpPrefs.duration, helpPrefs.opacity);
                } else {
                    helpMsg.jTypeWriter({duration:1, type:helpPrefs.type, onComplete:function(){
                        helpMsg.fadeTo(helpPrefs.duration, helpPrefs.opacity);
                    }});
                }
            };
            setTimeout(helpJob, 10);
        } catch (err) {
            alert(err.name + " in TumorTableTabSupport.onTabEnter: " + err.message);
        }
    }

    this.initBindings = function() {
        try {
            var support = this;
            this.tabSupport.jqSummaryTable.find("tbody tr").click(function(event){
                support.selectRow(this, event);
            });
        } catch (err) {
            alert(err.name + " in TumorTableTabSupport.initBindings: " + err.message);
        }
    }
    
    this.removeBindings = function() {
        try {
            var support = this;
            // stop showing gene symbols
            this.tabSupport.clearGeneSymbols();
            // eliminate memory of height for the gene symbols area
            var viewTd = this.tabSupport.jqGenesDisplay.get(0);
            jQuery.removeData(viewTd, "cn-genes-height");
            // remove click handlers that are about to be replaced
            this.tabSupport.jqSummaryTable.find("tbody tr").unbind('click');
        } catch (err) {
            alert(err.name + " in TumorTableTabSupport.removeBindings: " + err.message);
        }
    }
    
}

