/**
 * @fileoverview
 * This script defines utilities for interacting with data from www.fly-ted.org.
 * @author <a href="http://purl.org/net/aliman">Alistair Miles</a>, Graham Klyne, Jun Zhao
 * @version $Revision:126 $ on $Date: 2009-11-17 10:14:41 +0100 (Tue, 17 Nov 2009) $ by $Author: zhaoj $
 * @requires YAHOO.util.Connect
 * TODO license terms
 */

// create a namespace if not already defined
flykit.namespace("flykit.bdgp");


//flykit.bdgp.provenance = "<a href='ftp://ftp.fruitfly.org/pub/exgomysqldump/archive/current/exgopub-20070309.dump.gz'>data</a> obtained on 2008-10-30";
flykit.bdgp.provenance = "retrieved on 2008-10-30";

/**
 * TODO doc me
 */
flykit.bdgp.Service = function (endpointURL) {
	/**
	 * @private
	 */
	this._endpoint = endpointURL;
}


// extend
flykit.bdgp.Service.prototype = new flykit.sparql.Service();


flykit.bdgp.Service.prototype.findImagesByAnyGeneLabel = function( geneLabel, success, failure) {
    var _context = "flykit.bdgp.Service.prototype.findImagesByAnyGeneLabel";
	try {
		flykit.info("geneLabel: "+geneLabel, _context);
		var successChain = flykit.chain(flykit.bdgp.Service.responseToImages, success);
		var query = flykit.bdgp.Service._buildQueryForFindImagesByAnyGeneLabel(geneLabel);		
		this.query(query, successChain, failure);
	} catch (error) {
        	throw new flykit.UnexpectedException(_context, error);
    }	
}


/**
 * Convert an HTTP response to an array of Images.
 * @param {Object} response a YUI success case response object
 * @type Array<flykit.bdgp.Image>
 * @static
 */
flykit.bdgp.Service.responseToImages = function( response ) {
    var _context = "flykit.bdgp.Service.responseToImages";
    try {
        flykit.debug("response status: "+response.status, _context);
        flykit.debug("response text: "+response.responseText, _context);
        flykit.debug("try parsing response text as json", _context);
        var resultSet = YAHOO.lang.JSON.parse(response.responseText);
        flykit.debug("convert result set to an array of genes", _context);
        var images = flykit.bdgp.Stage.newInstancesFromSPARQLResults(resultSet);
        return images;        
    } catch (e) {
        flykit.debug("caught "+e.name+", "+e.message, _context);
        throw new flykit.UnexpectedException(_context, e);
    }
}


/**
 * Build a SPARQL query to retrieve images by bdgp gene name.
 * @param {String} anyName the gene name to search by
 * @return a SPARQL query
 * @type String
 * @private
 * @static
 */
flykit.bdgp.Service._buildQueryForFindImagesByAnyGeneLabel = function( geneLabel ) {

	try {
		var prefixes = 	"PREFIX bdgp: <http://purl.org/net/bdgp/schema/>  " +
						"PREFIX owl: <http://www.w3.org/2002/07/owl#> " +
						"PREFIX skos: <http://www.w3.org/2004/02/skos/core#> " +
						"PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> " +
						"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> " +		
						"PREFIX : <http://www.wiwiss.fu-berlin.de/suhl/bizer/D2RQ/0.1#> " +
						"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> " +
						"PREFIX dc: <http://purl.org/dc/elements/1.1/> ";					
	
	    var body = "select distinct ?imagepath ?stage ?developmentStage ?expression where {" +
	              "?gp skos:altLabel '" + geneLabel + "'; rdf:type bdgp:GeneProduct ." +
	              "?association bdgp:geneProduct ?gp ; bdgp:associate ?evidence ; bdgp:term ?term." +
	              "?evidence bdgp:evidence ?img ." +
	              "?img rdf:type bdgp:Image ; bdgp:imagePath ?imagepath." +
	              "?img bdgp:imageToTerm ?stage." +
	              "?stage bdgp:name ?developmentStage." +
	              "?term bdgp:name ?expression ." +
	              "}" + 
	              "order by ?stage";
	              
							
		var query = prefixes + body;
	
		return query;
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.bdgp.Service._buildQueryForFindImagesByAnyGeneLabel", error);
    }
};

flykit.bdgp.Stage = function (){
	try {
		var that = this;
		
		this.stageName = null;
		
		this.images = [];
		
		this.annotations = [];
		
		this.stageURI = null;
		
		this.addImage = function (image){
			flykit.util.appendIfNotMember(that.images, image);
		};
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.bdgp.Stage", error);
    }
};

/**
 * TODO doc me
 */
flykit.bdgp.Stage.newInstancesFromSPARQLResults = function( resultSet ) {
	try {
	
		var stagePool = new flykit.bdgp.StagePool();
		var imagePool = new flykit.bdgp.ImagePool();
		var bindings = resultSet.results.bindings;
		
		for (var i=0; i<bindings.length; i++) {
			var binding = bindings[i];
			var stageURI = binding.stage.value;
			var stage = stagePool.get (stageURI);	
					
			if (binding.developmentStage && !stage.stageName) {
				stage.stageName = binding.developmentStage.value;
			}
			
			if (binding.imagepath){
				var imageURI = binding.imagepath.value;
				var image = imagePool.get(imageURI);
				
				if (!image.expressions){
					image.expressions = new Array();
				}
	
				if (binding.expression) {
					var expression = binding.expression.value;
					if (expression == "stage1-3" || expression == "stage4-6" || expression == "stage7-8" || expression == "stage9-10" || expression == "stage11-12" || expression == "stage13-16"){
						flykit.debug("test: " + expression + " is not an expression term" );
					}
					else {
						flykit.util.appendIfNotMember(image.expressions, expression);
						flykit.util.appendIfNotMember(stage.annotations, expression);
					}
				}
				stage.addImage(image);
			}		
		}
		return stagePool.toArray();
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.bdgp.Stage.newInstancesFromSPARQLResults", error);
    }
};

/**
 * Create a pool of image objects.
 * @class
 * A pool of image objects.
 * @constructor
 */
 
flykit.bdgp.ImagePool = function() {
	/**
	 * @private
	 */
	this._pool = new Object();
};

flykit.bdgp.StagePool = function() {
	this._pool = new Array();
}

flykit.bdgp.StagePool.prototype.get = function( stageURI ) {
	try {
		var stage = this._pool[stageURI];
		
		if ( typeof stage == "undefined" || !stage ) {
			stage = new flykit.bdgp.Stage();
			stage.stageURI = stageURI;
			this._pool[stageURI] = stage;	
		}
		
		return stage;
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.bdgp.StagePool.prototype.get", error);
    }
};

flykit.bdgp.StagePool.prototype.toArray = function() {
	try {
		var array = new Array();	
		for (var key in this._pool) {
			array[array.length] = this._pool[key];
		}
		return array;
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.bdgp.StagePool.prototype.toArray", error);
    }
}

/**
 * Get a image object from the pool, or create a new one if it doesn't exist.
 * @param {String} imagepath 
 * @return a flykit.bdgp.Image object
 */
flykit.bdgp.ImagePool.prototype.get = function( imagepath ) {
	try {
		var image = this._pool[imagepath];
		
		if (!image ) {
			image = new Object();
			image.fullImageURL = "http://www.fruitfly.org/insituimages/insitu_images/" + imagepath;
			image.thumbnailURL = "http://www.fruitfly.org/insituimages/insitu_images/thumbnails/" + imagepath;
			this._pool[imagepath] = image;	
		}
		
		return image;
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.bdgp.ImagePool.prototype.get", error);
    }
};

flykit.bdgp.ImagePool.prototype.toArray = function() {
	try {
		var array = new Array();
		for (var key in this._pool) {
			array[array.length] = this._pool[key];
		}
		return array;
	}catch (error) {
        	throw new flykit.UnexpectedException("flykit.bdgp.ImagePool.prototype.toArray", error);
    }
}










flykit.bdgp.Service.prototype.findImagesByAnyGeneLabelBatch = function( labels, success, failure ) {
    var _context = "flykit.bdgp.Service.prototype.findImagesByAnyGeneLabelBatch";
    try {
        
        flykit.debug("labels: "+labels, _context);
        if (labels.length == 0) {
            success({});
        }
        else {
            var chain = flykit.chain(flykit.bdgp.Service.transformResponseForFindImagesByAnyGeneLabelBatch, success);
            var query = this._buildQueryForFindImagesByAnyGeneLabelBatch(labels);
            flykit.debug("query: "+query, _context);
            this.postQuery(query, chain, failure);        
        }
    } 
    catch (unexpected) {
        flykit.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }    
};







flykit.bdgp.Service.prototype._buildQueryForFindImagesByAnyGeneLabelBatch = function( labels ) {
    var _context = "flykit.bdgp.Service.prototype._buildQueryForFindImagesByAnyGeneLabelBatch";
    try {
        /*
        # query to select data on multiple genes
        
        PREFIX bdgp: <http://purl.org/net/bdgp/schema/>  
        PREFIX skos: <http://www.w3.org/2004/02/skos/core#> 
        
        SELECT DISTINCT ?label ?imagepath ?expression ?stage WHERE 
        {
          {
            {
              LET (?label := "FBgn0036925" )
            }
            UNION
            {
              LET (?label := "FBgn0033960" )
            }
          }
          {
            ?gp skos:altLabel ?label ; 
              a bdgp:GeneProduct .
            ?association bdgp:geneProduct ?gp ; 
              bdgp:associate ?evidence ; 
              bdgp:term [ bdgp:name ?expression ] . 
            FILTER regex(?expression, "^(?!stage)", "i")
            ?evidence bdgp:evidence ?img .
            ?img bdgp:imagePath ?imagepath ; bdgp:imageToTerm [ bdgp:name ?stage ] .
          }
        }
        */
    
        var query =         "PREFIX bdgp: <http://purl.org/net/bdgp/schema/>\n" +
                            "PREFIX skos: <http://www.w3.org/2004/02/skos/core#>\n";
                            
        query +=            "SELECT DISTINCT ?label ?imagepath ?expression ?stage WHERE \n" +
                            "{\n" +
                            "  {\n" +
                            "    { LET (?label := \""+labels[0]+"\" ) }\n";
                            
        for (var i=0;i<labels.length;i++) {
            query +=        "    UNION\n" +
                            "    { LET (?label := \""+labels[i]+"\" ) }\n";
        }
        
        query +=            "  }\n" +
                            "  {\n" +
                            "    ?gp skos:altLabel ?label ;\n" +
                            "      a bdgp:GeneProduct .\n" +
                            "    ?association bdgp:geneProduct ?gp ;\n" +
                            "      bdgp:associate ?evidence ;\n" +
                            "      bdgp:term [ bdgp:name ?expression ] .\n" +
                            "    FILTER regex(?expression, \"^(?!stage)\", \"i\")\n" +
                            "    ?evidence bdgp:evidence ?img .\n" +
                            "    ?img bdgp:imagePath ?imagepath ;\n" +
                            "      bdgp:imageToTerm [ bdgp:name ?stage ] .\n" +
                            "  }\n" +
                            "}";  
        
        return query;
    } 
    catch (unexpected) {
        flykit.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }    
};








 
flykit.bdgp.Service.transformResponseForFindImagesByAnyGeneLabelBatch = function( response ) {
    var _context = "flykit.bdgp.Service.transformResponseForFindImagesByAnyGeneLabelBatch";
    try {
        
        /* Turn results of query into result object like...
         * {
         *   "FBgn0036925" : {
         *     "stage4-6" : {
         *       "images" : [ 
         *         { "fullImageURL" : "...", "thumbnailURL" : "..." }, 
         *         { "fullImageURL" : "...", "thumbnailURL" : "..." } 
         *        ],
         *       "terms" : [ "gonad", "foo" ]
         *     },
         *     "stage7-8" : {
         *       "images" : [ 
         *         { "fullImageURL" : "...", "thumbnailURL" : "..." }, 
         *         { "fullImageURL" : "...", "thumbnailURL" : "..." } 
         *        ],
         *       "terms" : [ "gonad", "foo" ]
         *     },
         *     ...
         *   },
         *   "FBgn0012345" : {
         *     "stage4-6" : {
         *       "images" : [ 
         *         { "fullImageURL" : "...", "thumbnailURL" : "..." }, 
         *         { "fullImageURL" : "...", "thumbnailURL" : "..." } 
         *        ],
         *       "terms" : [ "gonad", "foo" ]
         *     },
         *     "stage7-8" : {
         *       "images" : [ 
         *         { "fullImageURL" : "...", "thumbnailURL" : "..." }, 
         *         { "fullImageURL" : "...", "thumbnailURL" : "..." } 
         *        ],
         *       "terms" : [ "gonad", "foo" ]
         *     },
         *     ...
         *   }
         * }
         */

        flykit.debug("response status: "+response.status, _context);
        flykit.debug("try parsing response text as json", _context);
        flykit.debug("parsing response: "+response.responseText, _context);

        var resultSet = YAHOO.lang.JSON.parse(response.responseText);
        
        flykit.debug("convert result set to a map of labels to images indexed by stage", _context);
        
        var map = {};
        var imagePool = new flykit.bdgp.ImagePool();
        var bindings = resultSet.results.bindings;
        
        for (var i=0; i<bindings.length; i++) {
            var binding = bindings[i];
            var lbl = binding["label"].value;
            var imgpath = binding["imagepath"].value;
            var image = imagePool.get(imgpath);
            var expr = binding["expression"].value;
            var stage = binding["stage"].value;
            
            if (typeof map[lbl] == "undefined" || !map[lbl]) {
                flykit.debug("initialising gene label: "+lbl, _context);
                map[lbl] = {};
            }
            
            if (typeof map[lbl][stage] == "undefined" || !map[lbl][stage]) {
                flykit.debug("initialising gene label: "+lbl+" stage: "+stage, _context);
                map[lbl][stage] = {"images":[],"terms":[]};
            }
            
            var images = map[lbl][stage].images;
            var terms = map[lbl][stage].terms;
            
            flykit.util.appendIfNotMember(images, image);
            flykit.util.appendIfNotMember(terms, expr);
            
        }
            
        return map;
    
    } 
    catch (unexpected) {
        flykit.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }    
};

