1 /** @namespace */ 2 var SequenceStore; if( !SequenceStore ) SequenceStore = {}; 3 4 /** 5 * Storage backend for sequences broken up into chunks, stored and 6 * served as static text files. 7 * @class 8 * @constructor 9 * @extends Store 10 */ 11 SequenceStore.StaticChunked = function(args) { 12 Store.call( this, args ); 13 14 this.chunkCache = {}; 15 16 this.compress = args.compress; 17 this.urlTemplate = args.urlTemplate; 18 this.baseUrl = args.baseUrl; 19 }; 20 21 SequenceStore.StaticChunked.prototype = new Store(''); 22 23 /** 24 * @param {Object} seq object describing the sequence to operate on 25 * @param {Number} start start coord, in interbase 26 * @param {Number} end end coord, in interbase 27 * @param {Function} callback function that takes ( start, end, seq ) 28 */ 29 SequenceStore.StaticChunked.prototype.getRange = function( seq, start, end, callback) { 30 31 var seqname = seq.name; 32 var chunkSize = seq.seqChunkSize; 33 var firstChunk = Math.floor( Math.max(0,start) / chunkSize ); 34 var lastChunk = Math.floor( (end - 1) / chunkSize ); 35 var chunk; 36 37 // if a callback spans more than one chunk, we need to wrap the 38 // callback in another one that will be passed to each chunk to 39 // concatenate the different pieces from each chunk and *then* 40 // call the main callback 41 if( firstChunk != lastChunk ) { 42 callback = (function() { 43 var chunk_seqs = [], 44 chunks_still_needed = lastChunk-firstChunk+1, 45 orig_callback = callback; 46 return function( start, end, seq, chunkNum) { 47 chunk_seqs[chunkNum] = seq; 48 if( --chunks_still_needed == 0 ) 49 orig_callback( start, end, chunk_seqs.join("") ); 50 }; 51 })(); 52 } 53 54 var callbackInfo = { start: start, end: end, callback: callback }; 55 56 if( !this.chunkCache[seqname] ) { 57 this.chunkCache[seqname] = []; 58 } 59 var chunkCacheForSeq = this.chunkCache[seqname]; 60 61 for (var i = firstChunk; i <= lastChunk; i++) { 62 //console.log("working on chunk %d for %d .. %d", i, start, end); 63 64 chunk = chunkCacheForSeq[i]; 65 if (chunk) { 66 if (chunk.loaded) { 67 callback( start, 68 end, 69 chunk.sequence.substring( 70 start - i*chunkSize, 71 end - i*chunkSize 72 ), 73 i 74 ); 75 } else { 76 //console.log("added callback for %d .. %d", start, end); 77 chunk.callbacks.push(callbackInfo); 78 } 79 } else { 80 chunk = { 81 loaded: false, 82 num: i, 83 callbacks: [callbackInfo] 84 }; 85 chunkCacheForSeq[i] = chunk; 86 87 var sequrl = Util.resolveUrl( this.baseUrl, 88 Util.fillTemplate( this.urlTemplate, 89 {'refseq': seq.name} )); 90 91 dojo.xhrGet({ 92 url: sequrl + i + ".txt" + ( this.compress ? 'z' : '' ), 93 load: function (response) { 94 var ci; 95 chunk.sequence = response; 96 for (var c = 0; c < chunk.callbacks.length; c++) { 97 ci = chunk.callbacks[c]; 98 ci.callback( ci.start, 99 ci.end, 100 response.substring( ci.start - chunk.num*chunkSize, 101 ci.end - chunk.num*chunkSize 102 ), 103 i 104 ); 105 } 106 chunk.callbacks = undefined; 107 chunk.loaded = true; 108 } 109 }); 110 } 111 } 112 }; 113