/**
 * @fileoverview
 * This script defines a widget for fetching and displaying publications from FlyBase.
 * @author Jun Zhao
 * @requires YAHOO.util.Connect
 * @requires flykit
 * @requires flykit.flybasepub.Service
 * @requires flykit.flybasepub.Publication
 * TODO license terms
 */
 
// create a namespace if not already defined
flykit.namespace("flykit.flybasepub");

flykit.flybasepub.PublicationWidget = function( service, renderer ) {
	try {
		var that = this;
		
		/** @private */
		this._controller = null;
		
		/** @private */
		this._renderer = renderer;
		
		this._model = null;
		
		this._renderer = null;
    
    	this._service = null;
		
		this._init = function() {
			// create a model
			var model = new flykit.mvcutils.GenericModel2();
			model.setDefinition(flykit.flybasepub.PublicationWidget.modelDefinition);
			
			// instantiate the controller
			this._controller = new flykit.flybasepub.PublicationWidget.Controller(model, service, this);
			
			// connect the renderer to the model
			renderer.connect(model);
		};
				
    	// do initialisation
    	this._init(service, renderer);
    } catch (error) {
        throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget", error);
    }	
};




flykit.flybasepub.PublicationWidget.prototype.findPublicationsByFlybaseGeneID = function( fbgn ) {
	// pass through to controller
	try {
		this._controller.findPublicationsByFlybaseGeneID(fbgn);
	}catch (error) {
        throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.prototype.findPublicationsByFlybaseGeneID", error);
    }
};




flykit.flybasepub.PublicationWidget.prototype.findPublicationsByGene = function( gene ) {
    // pass through to controller
    try {
        this._controller.findPublicationsByGene(gene);
    }catch (error) {
        throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.prototype.findPublicationsByGene", error);
    }
};




flykit.flybasepub.PublicationWidget.Controller = function( model, service, widget ) {
	var that = this;
	
	/**
	 * @private
	 */
	this._model = model;
	
	/**
	 * @private
	 */
	this._service = service;
	
	/**
	 * @private
	 */
	this._parent = widget;
	
	
	this._findPublicationsSuccess = function( publications ) {
		try {
			flykit.info("request success");
		
			// set the results
			that._model.set("RESULTS", publications);
			
			// set the state
			that._model.set("STATE", "READY");
		}catch (error) {
        	throw new flykit.UnexpectedException("_findPublicationsSuccess", error);
    	}

	};
	
	this._findPublicationsFailure = function( response ) {
		try {
			flykit.err("request failed, status "+response.status+" "+response.statusText);
			
			// set an error message
			var msg = "There was an error retrieving data from FlyBase, see the logs for more info. The server may be busy or down, please try again later. If this message persists, please contact the Image Bioinformatics Research Group at bioimage@mail.ontonet.org.";		
	
			that._model.set("ERRORMESSAGE", msg);
	
			// set the state
			that._model.set("STATE", "SERVERERROR");
		}catch (error) {
        	throw new flykit.UnexpectedException("_findPublicationsFailure", error);
    	}		
	};
};




/**
 * @private
 */
flykit.flybasepub.PublicationWidget.Controller.prototype._limit = 100;
    



flykit.flybasepub.PublicationWidget.Controller.prototype.findPublicationsByFlybaseGeneID = function( flybaseGeneID ) {
    // pass through to controller
    try {
        // pass through to private implementation
        this._findPublicationsByFlybaseGeneID(flybaseGeneID, this._findPublicationsSuccess, this._findPublicationsFailure);
    }catch (error) {
            throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.Controller.prototype.findPublicationsByFlybaseGeneID", error);
    }
};





flykit.flybasepub.PublicationWidget.Controller.prototype._findPublicationsByFlybaseGeneID = function( flybaseGeneID, success, failure ) {
	try {
		flykit.info("flykit.flybasepub.PublicationWidget.Controller._findPublicationsByFlybaseGeneID :: request: "+flybaseGeneID);

        // set the results to null
        this._model.set("RESULTS", null);
        		
		// set the model pending
		this._model.set("STATE", "PENDING");
		
		// set the query property
		this._model.set("QUERY", flybaseGeneID);
		
		// kick off the request
		this._service.findPubsByUniqueGeneName(flybaseGeneID, success, failure, this._limit);
		
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.Controller._findPublicationsByFlybaseGeneID", error);
    }
};





flykit.flybasepub.PublicationWidget.Controller.prototype.findPublicationsByGene = function( gene ) {
    // pass through to controller
    try {
        // pass through to private implementation
        this._findPublicationsByGene(gene, this._findPublicationsSuccess, this._findPublicationsFailure);
    }catch (error) {
            throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.Controller.prototype.findPublicationsByFlybaseGeneID", error);
    }
};





flykit.flybasepub.PublicationWidget.Controller.prototype._findPublicationsByGene = function( gene, success, failure ) {
    try {
        flykit.info("flykit.flybasepub.PublicationWidget.Controller._findPublicationsByGene :: request: "+gene.flybaseID);

        // set the results to null
        this._model.set("RESULTS", null);
                
        // set the model pending
        this._model.set("STATE", "PENDING");
        
        // set the query property
        this._model.set("QUERY", gene);
        
        // kick off the request
        this._service.findPubsByUniqueGeneName(gene.flybaseID, success, failure, this._limit);
    }catch (error) {
            throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.Controller._findPublicationsByGene", error);
    }
};





flykit.flybasepub.PublicationWidget.modelDefinition = {
	properties : [ "STATE", "RESULTS", "QUERY", "ERRORMESSAGE" ],
	
	values : {
		"STATE" : [ "PENDING", "READY", "SERVERERROR", "UNEXPECTEDERROR" ]
	},
	
	initialize : function( data ) {
		data["STATE"] = "READY";
		data["RESULTS"] = null;
		data["QUERY"] = null;
		data["ERRORMESSAGE"] = null;
	}

};

flykit.flybasepub.PublicationWidget.DefaultRenderer = function() {
	
	/** @private */
    this._canvas = null;
    
    /** @private */
    this._pendingPane = null;
    
    /** @private */
    this._resultsPane = null;
    
    /** @private */
    this._resultsSummaryPane = null;
    
    /** @private */
    this._messagePane = null;
    
    /** @private */
    this._explanationPane = null;
    
	
};

flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype.setCanvas = function( canvas ) {
    try {
	    this._canvas = $(canvas);
	    this._initCanvas();
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype.setCanvas", error);
    }
};




/**
 * @private
 * TODO doc me
 */
flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._initCanvas = function() {
    var _context = "flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._initCanvas";
	try {
		flykit.debug("_initCanvas", _context);
		
		var canvas = this._canvas;
        canvas.addClass("flybasePublicationWidget");
		
	    // set up the pending pane
		var pp = $("<p class='pendingPane'>pending...</p>").hide();
        canvas.append(pp);
        this._pendingPane = pp;
	    
	    // set up the message pane
		var msp = $("<p class='messagePane'>this text should never be displayed</p>").hide();
        canvas.append(msp);
        this._messagePane = msp;    
	    	    
	    // setup results summary pane
		var rsp = $("<p class='resultsSummaryPane'>this text should never be displayed</p>").hide();
        canvas.append(rsp);
        this._resultsSummaryPane = rsp;
	    
	    // setup results pane
		var rp = $("<div class='resultsPane'></div>").hide();
        canvas.append(rp);
        this._resultsPane = rp;

	    // setup explanation pane
        var ep = $("<p class='explanationPane'>this text should never be displayed</p>").hide();
        canvas.append(ep);
        this._explanationPane = ep;    
	    
	} catch (error) {
        	throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._initCanvas", error);
    }
};




flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onModelChanged = function(type, args, self) {
    var _context = "flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onModelChanged";
    try {
	    var handlers = {
	        "STATE":"_onStateChanged",
	        "QUERY":"_onQueryChanged",
	        "RESULTS":"_onResultsChanged",
	        "ERRORMESSAGE":"_onErrorMessageChanged"
	    };
	    var handler = handlers[type];
	    flykit.debug("handler: "+handler, _context);
	    // call the handler
	    self[handler](args[0], args[1], args[2]);
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onModelChanged", error);
    }
};




flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onStateChanged = function( from, to, get ) {
	var _context = "flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onStateChanged";
	try {
	    if ( to == "PENDING" ) {
            this._pendingPane.show();
            this._messagePane.empty().hide();
            this._resultsSummaryPane.hide();
            this._resultsPane.hide();
            this._explanationPane.hide();
            
		} else if (to == "READY") {
		    this._pendingPane.hide();
            this._messagePane.hide(); // hide for now, not needed yet
            this._resultsSummaryPane.show();
            this._resultsPane.show();     
            
		}else if ( to == "SERVERERROR" || to == "UNEXPECTEDERROR" ) {
		    this._pendingPane.hide();
            this._messagePane.show();
            this._resultsSummaryPane.hide();
            this._resultsPane.hide(); 
            this._explanationPane.hide();
		} 
		else {
		    // this should never happen
	    	throw {name:"flykit.flybasepub.PublicationWidget.UnexpectedStateError", message:"Invalid state: "+newState};
		}
	} catch (error) {
        	throw new flykit.UnexpectedException(_context, error);
    }
};

flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onQueryChanged = function( from, to ) {
	try {
    	// store query
    	this._query = to;
    }catch (error) {
        	throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onQueryChanged", error);
    }
};


flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onResultsChanged = function( from, to ) {
	var _context = "flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onResultsChanged";	
	try {
        flykit.debug("empty results summary and explanation panes", _context);
        
        if (to == null) {

	        this._resultsPane.empty();
	        this._resultsSummaryPane.empty();
	        this._explanationPane.empty();
	        
	    } else {

	        flykit.debug("collect publications in results", _context);
	        
	        flykit.debug("empty results summary pane", _context);
            this._resultsSummaryPane.empty();
            flykit.debug("empty results pane", _context);
            this._resultsPane.empty();
            
            flykit.debug("render results summary", _context);
		    this._renderResultsSummary(this._query, to.length);
		    
		    if (to.length > 0) {
		        flykit.debug("render the results "+to.length, _context);
		        //this._resultsPane.innerHTML = this._publicationsToDivHTML(to);
		        this._renderResults(to); 
		
		    }
		    else {
	//	        flykit.info("hide results and explanation panes", _context);
	//	        flykit.mvcutils.hide(this._resultsPane);
	//            flykit.mvcutils.hide(this._explanationPane);
		    }
	    }
	} catch (error) {
        	throw new flykit.UnexpectedException(_context, error);
    }
};


flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onErrorMessageChanged = function( from, to) {
    try {
    	this._messagePane.innerHTML = to;
    }catch (error) {
        	throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._onErrorMessageChanged", error);
    }
};


flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype.connect = function( model ) {
	try {
    	model.subscribeAll(this._onModelChanged, this);
    }catch (error) {
        	throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype.connect", error);
    }

};




flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._renderResultsSummary = function( query, count ) {
    var _context = "flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._renderResultsSummary";
	try {
	    
		flykit.debug("building results summary content", _context);
		
		if (query instanceof flykit.flybase.Gene) {
		    query = query.flybaseID; // handle legacy
		}
        
        var content = "";
        
        if (count < 30) {
        	content += "found <span>";
        	content += count;
		    content += "</span> publication";
		    content += (count == 0 || count > 1) ? "s " : " ";		    
        }
        else{
        	content += "found more than 30 publications";
        	content += " (only the most recent 30 records displayed) ";	
        }
        
	    content += "from <a href='http://www.flybase.org'>www.flybase.org</a> for ";
	    content += "<a href='http://flybase.org/reports/" + query + ".html'>" + query + "</a>";
	    content += " (data retrieved on 2009-02). ";
	    
	    content += "A full list of publicaiton can be found from ";
	    content += "<a href='http://flybase.org/reports/" + query + ".html'>" + "www.flybase.org" + "</a>";
	    content += " ...";
//	    
	    //this._resultsSummaryPane.innerHTML = content;
	    this._resultsSummaryPane.html(content);
	    
	} catch (error) {
        	throw new flykit.UnexpectedException(_context, error);
    }
};





flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._renderResults = function( publications ) {
    var _context = "flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._renderResults";
    try {
	    // build the divs
	    
	    flykit.debug("build div content for publications "+publications.length, _context);
	    
	    var pane = this._resultsPane;
	    
	    // the header
	    var content = "<table class='resultsTable'>";
	    content += "<thead><tr><th>Number</th><th>Mini Reference</th><th>Title</th><th>Year</th></tr></thead>"
	    
	    var count = 0;
	    for ( var i in publications ) {
	        if (publications[i]){
	        	if (count < 30) {
		        	var number = parseInt(i) + 1; 
		        	content += this._publicationToDivHTML(publications[i],number);
		        	flykit.debug("Generate the pub div" + content, _context);
		        	count ++;
	        	}
	        } 
	    }
	    content += "</table>";
	    //return content;
	    pane.append($(content));
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._imagesToDivHTML", error);
    }
};

flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._publicationToDivHTML = function( publication, number ) {
    var _context = "flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._publicationToDivHTML";
  	try {
	    flykit.debug("build content for each publication record"+publication.title, _context);
	    
	    var content =   "<tr>";
	    content +=	"<td>" + number + "</td>" ;	    
	    content +=	"<td>" + publication.miniref + "</td>" ;
	    content +=	"<td>" + publication.title + "</td>" ;
	    content +=	"<td>" + publication.pyear + "</td>" ;
    	content +=  "</tr>";
	    return content;
	} catch (error) {
        	throw new flykit.UnexpectedException("flykit.flybasepub.PublicationWidget.DefaultRenderer.prototype._imageToDivHTML", error);
    }
};






/*
 * ----------------------------------------------------------------
 *                        SIMPLE RENDERER
 * ----------------------------------------------------------------
 */



/**
 * @class
 * @extends flykit.flybasepub.PublicationWidget.DefaultRenderer
 */
flykit.flybasepub.PublicationWidget.SimpleRenderer = function() {};




// extend
flykit.flybasepub.PublicationWidget.SimpleRenderer.prototype = new flykit.flybasepub.PublicationWidget.DefaultRenderer();





/**
 * @private
 */
flykit.flybasepub.PublicationWidget.SimpleRenderer.prototype._renderResultsSummary = function( query, count ) {
    var _context = "flykit.flybasepub.PublicationWidget.SimpleRenderer.prototype._renderResultsSummary";
    try {
        
        flykit.debug("building results summary content", _context);
        
        var content = "";
        
        content += "found " + count + " reference";
        content += (count == 0 || count > 1) ? "s " : " ";          
        content += "from <a href='http://flybase.org'>flybase.org</a> (" + flykit.flybase.provenance + ") for gene ";
        
        var n = query;
        var fbgn = query;
        
        if (query instanceof flykit.flybase.Gene) {
            n = query.symbols[0];
            fbgn = query.flybaseID;
        }

        content += "<strong>" + n + "</strong> ";

        if (count == 100) {
            content += "(only "+flykit.flybasepub.PublicationWidget.Controller.prototype._limit+" most recent results are shown, see FlyBase gene report <a href='http://flybase.org/reports/" + fbgn + ".html'>" + fbgn + "</a> for a complete list)";
        }
        else {
            content += "(FlyBase report: <a href='http://flybase.org/reports/" + fbgn + ".html'>" + fbgn + "</a>) ";
        }     
        content += " ...";

        this._resultsSummaryPane.html(content);
        
    } catch (unexpected) {
        flykit.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};




flykit.flybasepub.PublicationWidget.SimpleRenderer.prototype._renderResults = function( publications ) {
    var _context = "flykit.flybasepub.PublicationWidget.SimpleRenderer.prototype._renderResults";
    try {
        // build the divs
        
        flykit.debug("build div content for publications "+publications.length, _context);
        
        var pane = this._resultsPane;
        
        // the header
        var content = "<table class='resultsTable'>";
        content += "<tbody>"
        
        var count = 0;
        for ( var i=0; i<publications.length; i++) {
            var pub = publications[i];
            content += "<tr><td>" + pub.miniref + "<br/>" + pub.title + " [<a href='http://flybase.org/reports/"+pub.uniquename+".html'>"+pub.uniquename+"</a>]</td></tr>";
        }
        
        content += "</tbody></table>";
        //return content;
        pane.append($(content));

    } catch (unexpected) {
        flykit.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};



