1 /**
  2  * A global object which keeps track of user data.
  3  * @extends Workbench.component.Component
  4  * @author Andrew, Amit Kumar
  5  *  // added chunkList getters and setters
  6  */
  7 
  8 Monk.component.DataManager = function(args) {
  9 
 10     this.projectId = null;
 11     this.worksetId = null;
 12     this.toolsetId = null;
 13     this.instanceId = null;
 14     this.chunkType = null;
 15     this.worklist = {};
 16     this.featureList = [];
 17     // to store documentlist from the similarity tool
 18     // and the search/browse tool
 19     this.chunkList = [];
 20     //search query parameters are stored here
 21     this.queryParam=null;
 22     this.decisionTree = "";
 23     this.decisionTreeSummary="";
 24     this.resultSummary="";
 25     this.worksetName = null;
 26     this.itinerary = "";
 27     this.feature = "";
 28     this.lastWorksetLoadedTimestamp = 0;
 29     this.unsavedWorksetData = false;
 30 
 31     this.currentChunk = null;
 32 
 33     this.projectData = null;
 34 
 35     // parameters used when running analyses
 36     this.performingAnalysis = false;
 37     this.progressDialog = null;
 38     this.cachedData = null;
 39     this.token = null;
 40     this.jobStatusTimer = null;
 41     this.timerInterval = 5000;
 42     this.similaritySearchURL = Monk.data.PROXY_URL + "get/AnalyticsManager.getMoreLikeThisWorkset";
 43     this.searchAndBrowseURL = Monk.data.PROXY_URL + "get/SearchManager.getWorksWithFeature";
 44     this.worksetSearchURL = Monk.data.PROXY_URL+"get/WorkSetsManager.getWorkset";
 45     this.simpleSearchURL = Monk.data.PROXY_URL+"get/SearchManager.getWorksWithAnyFeature";
 46     // supports workset/any search criterion the other similarity call will retire
 47     this.similarityAllSearchURL = Monk.data.PROXY_URL + "get/AnalyticsManager.getMoreLikeThis";
 48 
 49 
 50     // definition of the work record
 51     this.workDef = Ext.data.Record.create([
 52           {name: 'id', mapping: '@id'},
 53           {name: 'collection', mapping: '@collection_id'},
 54           {name: 'type', mapping: '@type'},
 55           {name: 'circulationStart', mapping: 'publication/@start'},
 56           {name: 'circulationEnd', mapping: 'publication/@end'},
 57           {name: 'circulationPeriod' ,mapping:'publication/@start',convert: function(value){
 58               var start = Math.floor(value/10)*10;
 59               var end = parseInt(start)+10;
 60               return start+"-"+end;
 61           }},
 62           {name: 'genre', mapping: 'genre'},
 63           {name: 'scoreRange', mapping: 'score', convert:  function(value){
 64                var start =Math.floor(value*10)/10;
 65                var end = Math.ceil(value*10)/10;
 66                return start+"-"+end;
 67           }},
 68           {name: 'score', mapping: 'score'},
 69           {name: 'author', mapping: 'authors/author/@id'},
 70           {name: 'authorBirthYear', mapping:'authors/author/@birthdate'},
 71           {name: 'authorDeathYear', mapping:'authors/author/@enddate'},
 72           {name: 'authorGender', mapping:'authors/author/@gender'},
 73           {name: 'label', mapping: 'label'},    // "mapping" property not needed if it's the same as "name"
 74           {name: 'workLabel', mapping: 'work_label'} //used by workpart
 75     ]);
 76 
 77     // this reads the XML formatted work results
 78     this.searchXMLReader = new Ext.ux.ErrorHandlingXmlReader({
 79                 totalRecords: "@totalCount", // The element which contains the total dataset size (optional)
 80                 record: "work",           // The repeated element which contains row information
 81                 id: "@id"                 // The element within the row that provides an ID for the record (optional)
 82              }, this.workDef);
 83 
 84     // the search result store -used by the searchAndbrowse tool and similarity tool
 85     this.resultStore = new Ext.data.GroupingStore({
 86            proxy: new Ext.data.HttpProxy(
 87                new Ext.data.Connection({
 88                 url: Monk.data.PROXY_URL + "get/CorpusManager.getWorksWithFeature",
 89                 method: 'POST',
 90                 timeout: 60000
 91                })
 92            )
 93            ,listeners: {
 94                 'beforeload': function(proxy, params){
 95                     var li = Ext.getCmp('loading-indicator');
 96                     if (li) li.show();
 97                 },
 98                 'load': function(proxy, data, callback){
 99                     var li = Ext.getCmp('loading-indicator');
100                     if (li) li.hide();
101                 },
102                 'loadexception': function(proxy, data, callback, exception){
103                     var li = Ext.getCmp('loading-indicator');
104                     if (li) li.hide();
105                 }
106            }
107            ,reader : this.searchXMLReader
108            ,baseParams: {format:'xml',start: 0, maxDocuments : '-1',limit:1000}
109            ,autoLoad: false
110            ,sortInfo:{field: 'label', direction: "ASC"}
111            ,groupField: 'circulationPeriod'
112     });
113 
114     Monk.component.DataManager.superclass.constructor.call(this, args);
115 }
116 
117 Workbench.extend(Monk.component.DataManager, Workbench.component.Component, {
118     label : "Data Manager",
119     description : "For managing data in Monk.",
120 
121     getResultStore : function(){
122     	return this.resultStore;
123     },
124 
125     /**
126      * Takes a node from MonkServices and adapts it to what will be the new implementation.
127      * @param {Object} node The node to fix
128      * @param {String} collectionId The ID for the collection this node belongs to
129      * @return {Object} The fixed node
130      */
131 /*    fixNode : function(node, collectionId) {
132         // prepend the collectionId if necessary
133         var id = (node.id == collectionId) ? collectionId : collectionId + "." + node.id;
134         var newNode = {
135             id: id,
136             text: node.label,
137             chunkType: node.type
138         };
139         return newNode;
140     },*/
141 
142     /**
143      * This applies the fixNode method recursively to a tree of nodes,
144      * and flattens the tree into the passed array.
145      * @param {Object} node The tree root
146      * @param {Array} nodes The resulting collection of nodes
147      */
148 /*    recursiveFix : function(node, nodes) {
149         if (node.length != null) {
150             for (var i=0;i<node.length;i++) {
151                 this.recursiveFix(node[i], nodes);
152             }
153         } else if (node.node) {
154             // don't add collections
155             if (node.type != 'collection') nodes.push(this.fixNode(node, this.getCollectionId()));
156             this.recursiveFix(node.node, nodes);
157         } else {
158             if (node.type != 'collection') nodes.push(this.fixNode(node, this.getCollectionId()));
159         }
160     },*/
161 
162     /**
163      * Called when a user checks a chunk.
164      * Adds/removes the chunk to the worklist based on the checked attribute.
165      * @param {Object} chunk The chunk to be processed
166      */
167     processChunk : function(chunk) {
168         if (chunk.checked != false) {
169             if (this.worklist[chunk.id] == null) {
170                 this.worklist[chunk.id] = {
171                     chunkType: chunk.chunkType,
172                     text: chunk.text,
173                     corpus: ""
174                 };
175             } else {
176                 this.worklist[chunk.id].chunkType = chunk.chunkType;
177                 this.worklist[chunk.id].text = chunk.text;
178                 this.worklist[chunk.id].corpus= "";
179                 
180             }
181 
182         } else {
183             // if the chunk was unchecked then remove it from the list
184             delete this.worklist[chunk.id];
185         }
186 
187         this.unsavedWorksetData = true;
188     },
189    // returns the document list in the result store
190     getDocumentList: function(){
191         var documentArray = new Array(Monk.component.dataManager.getResultStore().getCount());
192         var i=0;
193         Monk.component.dataManager.getResultStore().each(function(record,options){
194             documentArray[i] = record.data.id;
195             i++;
196         },this);
197         return documentArray;
198     },
199 
200     /**This functions calls the backend to do the analysis
201      *
202      * @param string type /workset/collection or author
203      * @param featureType feature_spelling_gender, feature_lemma_gender
204      * @param {} queryParam
205      */
206      doFeatureComparison: function(type,featureType,queryParam){
207        Workbench.console.info("here do the comparison... " + type + "   " + featureType + "  " + queryParam);
208 
209        var featureQueryParam={"featureType":featureType};
210        featureQueryParam["queryTypes"]=type;
211        if(type=="collection"){
212        	featureQueryParam["queryValues"]=queryParam.corpusCriterion;
213        }else if(type=="workset"){
214         featureQueryParam["queryValues"]=queryParam;
215        }
216        /*
217        Monk.chart.getFeatureComparison(type,featureType,featureQueryParam);
218        Ext.ux.ErrorHandlingConnection
219        Workbench.component.manager.notify(new Monk.event.chart.FeatureComparisonChartRetrieved({
220                     label: 'compare features: '
221        }), {"featureType":featureType,"imgUrl":"http://www.google.com/intl/en_ALL/images/logo.gif"});
222      */
223        	Monk.chart.getFeatureComparison(type,featureType,featureQueryParam);
224 
225     },
226 
227     /**
228      * Set query param
229      */
230     setSearchQueryParam: function(queryParams){
231         var append = queryParams[1] || false;
232     	this.queryParam = queryParams[0];
233         if ((this.resultStore.getCount() == 0 && !this.resultStore.isFiltered()) || append) {
234             if (this.queryParam.worksetIdCriterion != null && !append) {
235                 // loading a workset, so clear out the current one
236                 this.resetWorkset();
237             }
238             this.resultStore.baseParams = this.queryParam;
239             this.resultStore.proxy.conn.url = this.searchAndBrowseURL;
240             this.resultStore.on('load',function(store,records,options){
241                 Workbench.component.manager.notify(new Monk.event.chunk.ChunksSimilarRetrieved({
242                     label: 'search documents retrieved: '
243                  }), this.getDocumentList());
244             },this, {single: true});
245             this.resultStore.load({
246                 params: {start: 0,limit: 1000},
247                 add: append
248             });
249         } else {
250         	Workbench.console.info("filtering resultStore");
251             this.resultStore.filterBy(function(record, id){
252                 var match = false;
253                 for (var name in queryParams[0]) {
254                     switch (name) {
255                         case 'corpusCriterion':
256                             if (record.data.collection.indexOf(queryParam[name]) != -1) match = true;
257                         case 'authorName':
258                             if (record.data.author.indexOf(queryParam[name]) != -1) match = true;
259                         case 'authorGender':
260                             if (record.data.authorGender.indexOf(queryParam[name]) != -1) match = true;
261                         case 'authorStartBirthYear':
262                             if (record.data.authorBirthYear >= queryParam[name]) match = true;
263                         case 'authorStartDeathYear':
264                             if (record.data.authorDeathYear >= queryParam[name]) match = true;
265                         case 'authorEndBirthYear':
266                             if (record.data.authorBirthYear <= queryParam[name]) match = true;
267                             else match = false;
268                         case 'authorEndDeathYear':
269                             if (record.data.authorDeathYear <= queryParam[name]) match = true;
270                             else match = false;
271                         case 'titlePattern':
272                             var pattern = new RegExp(queryParam[name], 'i');
273                             if (record.data.label.match(pattern) != null) match = true;
274                         case 'genre':
275                             if (record.data.genre.indexOf(queryParam[name]) != -1) match = true;
276                         case 'circulationDateStart':
277                             if (record.data.circulationStart >= queryParam[name]) match = true;
278                         case 'circulationDateEnd':
279                             if (record.data.circulationEnd <= queryParam[name]) match = true;
280                         case 'workpartIdCriterion':
281                             if (record.data.workpartIdCriterion == queryParam[name]) match = true;
282                     }
283                 }
284                 return match;
285             }, this);
286         }
287     },
288     
289     doSimpleQuery: function(queryParam, append){
290         append = append || false;
291     	this.queryParam = queryParam;
292         if (this.resultStore.getCount() == 0 && !this.resultStore.isFiltered()) {
293         	this.resultStore.baseParams = this.queryParam;
294             this.resultStore.proxy.conn.url = this.simpleSearchURL;
295             this.resultStore.on('load',function(store,records,options){
296                 Workbench.component.manager.notify(new Monk.event.chunk.ChunksSimilarRetrieved({
297                     label: 'search documents retrieved: '
298                  }), this.getDocumentList());
299             },this, {single: true});
300             this.resultStore.load({params: {start: 0,limit: 1000}, add: append});
301         } else {
302             this.resultStore.filterBy(function(record, id){
303                 var match = false;
304                 for (var name in record.data) {
305                     var pattern = new RegExp(queryParam.featureValue, 'i');
306                     if (record.data[name].match(pattern) != null) {
307                         match = true;
308                         break;
309                     }
310                 }
311                 return match;
312             }, this);
313         }
314     },
315     /**This call allows all the containers -worksets/search criterion etc.
316      * the setSimilarQueryParam call is redundant
317      * 
318      * @param {} queryParam
319      */
320     doSimilarityQuery: function(queryParam, append){
321         append = append || false;
322     	this.queryParam = queryParam;
323         this.queryParam.format = "xml";
324         Workbench.console.info("here in data manager -similar all query:  "+ this.queryParam.feature);
325         this.resultStore.baseParams = this.queryParam;
326         this.resultStore.proxy.conn.url = this.similarityAllSearchURL;
327         this.resultStore.on('load',function(store,records,options){
328             Workbench.component.manager.notify(new Monk.event.chunk.ChunksSimilarRetrieved({
329                 label: 'search documents retrieved: '
330              }), this.getDocumentList());
331              Workbench.console.info("===> retrieved the documents. In resultstore: " + this.resultStore.getCount());
332         },this, {single: true});
333         this.resultStore.load({params: {start: 0,limit: 1000, format: 'xml'}, add: append});
334     },
335 
336     /**
337      * Set similar search query param
338      * @deprecated
339      */
340    setSimilarQueryParam: function(queryParam, append){
341         append = append || false;
342         this.queryParam = queryParam;
343         Workbench.console.info("here in data manager -similar query:  "+ this.queryParam.feature);
344         this.resultStore.baseParams = this.queryParam;
345         this.resultStore.proxy.conn.url = this.similaritySearchURL;
346         this.resultStore.on('load',function(store,records,options){
347             Workbench.component.manager.notify(new Monk.event.chunk.ChunksSimilarRetrieved({
348                         label: 'search documents retrieved: '
349              }), this.getDocumentList());
350         },this, {single: true});
351         this.resultStore.load({params: {start: 0,limit: 1000, format: 'xml'}, add: append});
352     },
353 
354     /**This query will retrieve the workset information from the
355      * middleware and update the common work store that is used by the
356      * result summary tool
357      *
358      */
359     setWorksetQueryParam: function(id, append){
360         append = append || false;
361         this.queryParam={'worksetId':id};
362         Workbench.console.info("here in data manager -workset load query:  "+ this.queryParam.id);
363         this.resultStore.baseParams = this.queryParam;
364         this.resultStore.proxy.conn.url = this.worksetSearchURL;
365         this.resultStore.on('load',function(store,records,options){
366             Workbench.component.manager.notify(new Monk.event.chunk.ChunksSimilarRetrieved({
367                         label: 'workset documents retrieved: '
368              }), this.getDocumentList());
369         },this, {single: true});
370         this.resultStore.load({params: {start: 0,limit: 1000, format: 'xml'}, add: append});
371     },
372 
373 
374     handle : function(monkEvent, data){
375         if (monkEvent.instanceOf((Monk.event.analysis.GotSeasrAnalysisResults))) {
376             var instanceId = data.instanceId;
377 
378             var jsonString = Monk.utils.xml2json(data.results, " ");
379             var json = "";
380             (eval('json='+jsonString));
381 
382             if (json.results.result.length == null) {
383                 json.results.result = [json.results.result]; // json array fix
384             }
385 
386             // reset analysis values
387             this.setFeatureList([]);
388             this.setDecisionTree("");
389             this.setDecisionTreeSummary("");
390 
391             var results = this.processResults(instanceId, json.results.result);
392 
393             if (this.performingAnalysis) {
394                 var conn = new Ext.data.Connection();
395                 conn.request({
396                     url: Monk.data.PROXY_URL + 'get/SeasrManager.getConfigParameters',
397                     method: 'GET',
398                     params: {instanceId: instanceId},
399                     success: function(responseObject) {
400                         var result = responseObject.responseXML.getElementsByTagName('result')[0];
401                         if (result != null) {
402                             var entries = result.getElementsByTagName('params');
403                             for (var i = 0, length = entries.length; i < length; i++) {
404                                 var entry = entries[i];
405                                 var type = entry.getAttribute('name')
406                                 if (type == 'toolsetId') {
407                                     this.cachedData.toolsetId = entry.getElementsByTagName('value')[0].firstChild.data;
408                                 }
409                                 if (type == 'worksetId') {
410                                     this.cachedData.worksetId = entry.getElementsByTagName('value')[0].firstChild.data;
411                                 }
412                                 if (type == 'flowId') {
413                                     this.cachedData.itinerary = entry.getElementsByTagName('value')[0].firstChild.data;
414                                 }
415                                 if (type == 'resultDescription') {
416                                     this.cachedData.description = entry.getElementsByTagName('value')[0].firstChild.data;
417                                 }
418                                 if (type == 'resultName') {
419                                     this.cachedData.name = entry.getElementsByTagName('value')[0].firstChild.data;
420                                 }
421                             }
422                         }
423 
424                         // temp date
425                         var date = new Date();
426                         var dateStarted = date.format('Y-m-d h:i:s');
427                         var dateEnded = dateStarted;
428 
429                         // copy values to the results
430                         for (var i = 0, length = results.tempResults.length; i < length; i++) {
431                             results.tempResults[i].dateEnded = dateEnded;
432                             results.tempResults[i].dateStarted = dateStarted;
433                             results.tempResults[i].description = this.cachedData.description;
434                             results.tempResults[i].flowId = this.cachedData.itinerary;
435                             results.tempResults[i].name = this.cachedData.name;
436                             results.tempResults[i].toosletId = this.cachedData.toolsetId;
437                             results.tempResults[i].userId = 'null';
438                             results.tempResults[i].worksetId = this.cachedData.worksetId;
439                         }
440 
441                         // add result to project data
442                         Monk.component.dataManager.getProjectData().results.add(instanceId, results.tempResults);
443 
444                         Ext.getCmp('runAnalysisProgressBar').reset();
445                         Ext.getCmp('runAnalysisProgressBar').updateProgress(1, 'Analysis complete');
446                         this.progressDialog.buttons[0].enable(); // show results button
447                         this.progressDialog.buttons[2].disable(); // cancel button
448 
449                         Workbench.component.manager.notify(
450                             new Monk.event.workset.AnalysisResultsProcessed(
451                             {label: 'Analysis results processed: '+ this.getWorksetName()}
452                             ),
453                             {worksetId: this.getWorksetId(), instanceId: instanceId, results: results.resultsProcessed, performingAnalysis: this.performingAnalysis}
454                         );
455                         this.performingAnalysis = false;
456                         this.cachedData = null;
457                     },
458                     failure: function(response, options) {
459                         Ext.Msg.alert('Data Manager', 'Error trying to get config parameters for the analysis call.<br/><b>Error</b>: '+response.statusText);
460                     },
461                     scope: this
462                 });
463             } else {
464                 Workbench.component.manager.notify(
465                     new Monk.event.workset.AnalysisResultsProcessed(
466                     {label: 'Analysis results processed: '+ this.getWorksetName()}
467                     ),
468                     {worksetId: this.getWorksetId(), instanceId: instanceId, results: results.resultsProcessed, performingAnalysis: this.performingAnalysis}
469                 );
470             }
471         } else if (monkEvent.instanceOf(Monk.event.flowmanager.StepSelected)) {
472             if (data == 'toolstep-003' && !this.performingAnalysis && this.progressDialog != null) {
473                 this.progressDialog.close();
474             }
475         } else if (monkEvent.instanceOf(Monk.event.chunk.ChunkChecked)) {
476             this.processChunk(data);
477         } else if (monkEvent.instanceOf(Monk.event.chunk.ChunksChecked)) {
478             for (var i = 0; i < data.length; i++) {
479                 this.processChunk(data[i]);
480             }
481         } else if (monkEvent.instanceOf(Monk.event.workset.WorksetCreated)) {
482             // get the new workset ID and set it
483             var xml = data.response.responseXML;
484             var worksetId = xml.getElementsByTagName('workset')[0].getAttribute('id');
485             this.worksetId = worksetId;
486 
487             var workset = this.getWorkset();
488             // add extra info for WorksetSelector
489             var todaysDate = new Date();
490             todaysDate = todaysDate.format('Y-m-d G:i:s');
491             workset.date = [{'#text':todaysDate}];
492             workset.id = worksetId;
493             workset.label = workset.worksetName;
494             this.getProjectData().worksets.add(worksetId, workset);
495 
496             if (this.performingAnalysis) {
497                 this.runAnalysis();
498             }
499 
500             this.unsavedWorksetData = false;
501         } else if (monkEvent.instanceOf(Monk.event.workset.WorksetSaved)) {
502             if (this.performingAnalysis) {
503                 this.runAnalysis();
504             }
505             this.updateProjectDataWorkset();
506 
507             this.unsavedWorksetData = false;
508         } else if (monkEvent.instanceOf(Monk.event.workset.WorksetDeleted)) {
509             this.getProjectData().worksets.removeKey(data.worksetId);
510 
511             // reset everything if the deleted workset matches the current one
512             if (this.getWorksetId() == data.worksetId) {
513                 this.reset();
514             }
515         } else if (monkEvent.instanceOf(Monk.event.workset.GotWorkpartLabels)) {
516         	//debugger;
517             var json = Monk.utils.xml2json(data.response.responseXML, " ");
518             var labels = "";
519             (eval('labels='+json));
520             //debugger;
521             if (labels.nodes != null && labels.nodes.node!=null) {
522                 var labelsArray = labels.nodes.node;
523                 for (var i = 0, length = labelsArray.length; i < length; i++) {
524                     var labelNode = labelsArray[i];
525                     
526                     if (this.worklist[labelNode.id] == null) {
527                     } else {
528                         this.worklist[labelNode.id].text = labelNode.label['#text'];
529                        // this.worklist[labelNode.id].genre= labelNode.genre;
530                        // this.worklist[labelNode.id].circulation_year= labelNode.circulation_year;
531                        this.worklist[labelNode.id].corpus= labelNode.corpus;
532                     }
533                 }
534             }
535 			this.lastWorksetLoadedTimestamp = new Date().getTime();
536             Workbench.component.manager.notify(
537                 new Monk.event.workset.WorksetLoaded({
538 					label: 'Workset loaded: ' + this.getWorksetName()
539 				}), {
540 					id: this.getWorksetId(),
541 					timestamp : this.lastWorksetLoadedTimestamp
542 				}
543             );
544 
545             this.unsavedWorksetData = false;
546         } else if (monkEvent.instanceOf(Monk.event.chunk.ChunkSelected)) {
547             this.setCurrentChunk(data);
548         } else if (monkEvent.instanceOf(Monk.event.chunk.ChunkRated)) {
549             // set the rating to the specified chunk
550             var chunkId = data.chunkId;
551             var rating = data.rating;
552             this.worklist[chunkId].userRating = rating;
553 
554             this.unsavedWorksetData = true;
555         } else if (monkEvent.instanceOf(Monk.event.chunk.ChunksRated)) {
556 			for (var i=0;i<data.length;i++) {
557 				this.worklist[data[i].id] = data[i];
558 			}
559 
560             this.unsavedWorksetData = true;
561         } else if (monkEvent.instanceOf(Monk.event.workset.WorksetReset)) {
562             this.reset();
563         } else if (monkEvent.instanceOf(Monk.event.analysis.SeasrAnalysisRun)) {
564             this.updateProgress(data);
565         } else if (monkEvent.instanceOf(Monk.event.ServerError)) {
566             if (data.url != null) {
567             	if (data.url.match(/SchedulerManager.runAnalysis/) != null) {
568                     this.progressDialog.close();
569                     Monk.component.messenger.alert('Analysis Tool', '<b>There was an error getting the prediction:</b><br />'+data.error);
570                 }
571             }
572         } else if (monkEvent.instanceOf(Monk.event.analysis.GotJobStatus)) {
573             this.processStatus(data);
574         }else if(monkEvent.instanceOf(Monk.event.chunk.ChunksSimilarRetrieved)){
575         	this.setChunkSimilar(data);
576         }else if(monkEvent.instanceOf(Monk.event.workbench.AdvancedSearchQuery)){
577         	this.setSearchQueryParam(data);
578         }else if(monkEvent.instanceOf(Monk.event.workbench.SimilarSearchQuery)){
579             this.setSimilarQueryParam(data);
580         }else if(monkEvent.instanceOf(Monk.event.project.LoadSelectedWorkset)){
581             this.setWorksetQueryParam(data);
582         }else if(monkEvent.instanceOf(Monk.event.chart.FeatureComparison)){
583         	this.doFeatureComparison(data.type,data.featureType,data.queryParam);
584         }else if(monkEvent.instanceOf(Monk.event.workbench.SimpleSearchQuery)){
585         	this.doSimpleQuery(data);
586         }else if(monkEvent.instanceOf(Monk.event.workbench.ClearSearch)){
587             if (data.clearAll) {
588                 this.resultStore.removeAll();
589             } else {
590                 this.resultStore.clearFilter();
591             }
592         }else if(monkEvent.instanceOf( Monk.event.workbench.WorksetDocumentComparison)){
593         	if(data.method.toString()=="SimilarFeatures"){
594             // do a similarity search here...
595         		this.doSimilarityQuery(data);
596              }else if( data.method.toString()=="SimilarFeatures:swap"){
597              	this.doSimilarityQuery(data);
598              }else{
599             	Workbench.console.info("unsupported method: " + data.method +"=="+data.method.toString());
600             }
601         }
602     },
603 
604     /**
605      * Returns list of chunks saved from the previous similarity/search browse
606      */
607     getChunkSimilar: function(){
608         return this.chunkList;
609     },
610 
611     /**
612      * Return the query parameter
613      */
614     getQueryParam: function(){
615         return this.queryParam;
616     },
617 
618 
619     /**
620      * Store the list of chunks retrieved as a result of a search/browse
621      * or Similarity search
622      * @param {String array}
623      */
624     setChunkSimilar: function(chunkList){
625     	this.chunkList=chunkList;
626     },
627 
628 
629     /**
630      * Reset the chunkList
631      */
632     resetChunkSimilar: function(){
633     	this.chunkSimilar=[];
634     	this.resultStore.removeAll();
635     },
636 
637     resetQueryParam: function(){
638     	this.queryParam=null;
639     	 this.resultStore.removeAll();
640     },
641 
642     /**
643      * Resets everything back to the initial values.
644      * @param {Boolean} resetProject True to reset the project as well.
645      */
646     reset : function(resetProject) {
647         if (resetProject) {
648             this.projectId = null;
649             this.projectData = null;
650             this.toolsetId = null;
651         }
652         this.currentChunk = null;
653         this.instanceId = null;
654         this.chunkType = null;
655         this.resetWorkset();
656         this.resetResults();
657         this.resetChunkSimilar();
658         this.resetQueryParam();
659         this.resultStore.removeAll();
660     },
661 
662 
663     /**
664      * Returns the workset to its initial state
665      */
666     resetWorkset : function() {
667         this.worksetId = null;
668         this.worklist = {};
669         this.worksetName = null;
670         this.itinerary = "";
671         this.feature = "";
672         this.unsavedWorksetData = false;
673         this.resultStore.removeAll();
674     },
675 
676     /**
677      * Returns the results to their initial state
678      */
679     resetResults : function() {
680         this.featureList = [];
681         this.decisionTree = "";
682         this.decisionTreeSummary = "";
683         this.resultSummary = "";
684     },
685 
686     /**
687      * Returns the project ID for this workset.
688      * @return {String} The project ID
689      */
690     getProjectId : function() {
691         return this.projectId;
692     },
693 
694     /**
695      * Sets the project ID for this workset.
696      * @param {String} projectId The project ID
697      */
698     setProjectId : function(projectId) {
699         this.projectId = projectId;
700     },
701 
702     /**
703      * Returns the workset ID for this workset.
704      * @return {String} The workset ID
705      */
706     getWorksetId : function() {
707         return this.worksetId;
708     },
709 
710     /**
711      * Sets the workset ID for this workset.
712      * @param {String} worksetId The workset ID
713      */
714     setWorksetId : function(worksetId) {
715         this.worksetId = worksetId;
716     },
717 
718     /**
719      * Returns the workset label (longer form) for this workset.
720      * @return {String} The workset label
721      */
722     getWorksetLabel : function() {
723         return "Workset: "+ (this.worksetName ? this.worksetName + " (id: " + this.worksetId + ")" : "[undetermined]");
724     },
725 
726     /**
727      * Returns true if there is unsaved workset data.
728      * @return {Boolean} Is there unsaved workset data.
729      */
730     isWorksetUnsaved : function() {
731         return this.unsavedWorksetData;
732     },
733 
734 	/**
735 	 * Returns the timestamp from the last load of workset
736 	 * @return {Number} The last timestamp
737 	 */
738 	getLastWorksetLoadedTimestamp : function() {
739 		return this.lastWorksetLoadedTimestamp;
740 	},
741 
742     /**
743      * Returns the toolset ID for this toolset.
744      * @return {String} The toolset ID
745      */
746     getToolsetId : function() {
747         return this.toolsetId;
748     },
749 
750     /**
751      * Sets the toolset ID for this toolset.
752      * @param {String} toolsetId The toolset ID
753      */
754     setToolsetId : function(toolsetId) {
755         this.toolsetId = toolsetId;
756     },
757 
758     /**
759      * Returns the instance ID for the most recent analysis result.
760      * @return {String} The instance ID
761      */
762     getInstanceId : function() {
763         return this.instanceId;
764     },
765 
766     /**
767      * Sets the instance ID for the most recent analysis result.
768      * @param {String} instanceId The instance ID
769      */
770     setInstanceId : function(instanceId) {
771         this.instanceId = instanceId;
772     },
773 
774     /**
775      * This is a legacy method to adapt to the Nora services.
776      * It tallies up the chunkTypes and sets the workset's chunkType
777      * to whichever is the most prevalent.
778      * @return {String} The chunk type
779      */
780     getChunkType : function() {
781         // TODO: chunkType will eventually be set on a per chunk basis.
782 //        var chunkTypeArray = [];
783 //        for (var chunkId in this.worklist) {
784 //            var chunkType = this.worklist[chunkId].chunkType;
785 //            if (chunkTypeArray.length == 0) {
786 //                chunkTypeArray.push([chunkType]);
787 //            } else {
788 //                var chunkAdded = false;
789 //                for (var i = 0; i < chunkTypeArray.length; i++) {
790 //                    var type = chunkTypeArray[i][0];
791 //                    if (chunkType == type) {
792 //                        chunkTypeArray[i].push(chunkType);
793 //                        chunkAdded = true;
794 //                    }
795 //                }
796 //                if (!chunkAdded) {
797 //                    chunkTypeArray.push([chunkType]);
798 //                }
799 //            }
800 //        }
801 //
802 //        chunkTypeArray.sort(function(a, b) {
803 //            if (a.length > b.length) return -1;
804 //            if (a.length < b.length) return 1;
805 //            return 0;
806 //        });
807 //
808 //        this.chunkType = chunkTypeArray[0][0];
809 
810         this.chunkType = 'work';
811 
812         return this.chunkType;
813     },
814 
815     /**
816      * Returns the chunk currently being viewed.
817      * @returns {Object} The current chunk.
818      */
819     getCurrentChunk : function() {
820         return this.currentChunk;
821     },
822 
823     /**
824      * Sets the chunk currently being viewed.
825      * @params {Object} chunk The chunk object.
826      * @params {String} chunk.id The id of the chunk.
827      * @params {String} chunk.corpus The corpus that the chunk belongs to.
828      * @params {String} chunk.text The label of the chunk.
829      */
830     setCurrentChunk : function(chunk) {
831         this.currentChunk = chunk;
832     },
833 
834     /**
835      * Returns the worklist for this workset.
836      * @return {Object} The worklist
837      */
838     getWorklist : function() {
839         return this.worklist;
840     },
841 
842     /**
843      * Sets the worklist for this workset.
844      * It accepts 3 arrays (chunk IDs, system ratings, and rating confidence) whose items should have a 1 to 1 relation
845      * and be in the same order.
846      * @param {Array} worklist The chunk IDs
847      * @param {Array} [worklistRating] The ratings for each chunk
848      * @param {Array} [confidence] The confidence for each predicted rating
849      */
850     setWorklist : function(worklistArray, worklistRatingArray, confidenceArray) {
851         worklistRatingArray = worklistRatingArray || [];
852         confidenceArray = confidenceArray || [];
853         for (var i = 0; i < worklistArray.length; i++) {
854             var chunkId = worklistArray[i];
855             var rating = worklistRatingArray[i];
856             var confidence = confidenceArray[i];
857             if (this.worklist[chunkId] == null) {
858                 this.worklist[chunkId] = (rating != null) ? {systemRating: rating} : {};
859             } else {
860                 if (rating != null) this.worklist[chunkId].systemRating = rating;
861             }
862             if (confidence != null) this.worklist[chunkId].confidence = confidence;
863         }
864     },
865     
866     /**
867      * Clears the worklist for the current workset.
868      */
869     clearWorklist : function() {
870         this.worklist = {};
871     },
872 
873     /**
874      * Sets the training list for this workset.
875      * It accepts 2 comma-separated strings (chunk IDs and user ratings) whose items should have a 1 to 1 relation
876      * and be in the same order.
877      * Currently we're storing trainingList values in the worklist as userRating property
878      * @param {String} trainingList The chunk IDs
879      * @param {String} trainingListRating The ratings for each chunk
880      */
881     setUserRatings : function(trainingList, trainingListRating) {
882         var trainingListArray = trainingList.split(',');
883         if(trainingListRating!=null){
884         var trainingListRatingArray = trainingListRating.split(',');
885         for (var i = 0; i < trainingListArray.length; i++) {
886             if (trainingListArray[i] != 'null') {
887                 var chunkId = trainingListArray[i];
888                 var rating = trainingListRatingArray[i];
889                 if (this.worklist[chunkId] == null) {
890                     this.worklist[chunkId] = (rating != 'null') ? {userRating: rating} : {};
891                 } else {
892                     if (rating != 'null') this.worklist[chunkId].userRating = rating;
893                 }
894             }
895         }//end of for
896         }else{
897         	//trainingListRating==null
898         	for (var i = 0; i < trainingListArray.length; i++) {
899 
900                     var chunkId = trainingListArray[i];
901                     var rating = "Training set"
902                     if (this.worklist[chunkId] == null) {
903                         this.worklist[chunkId] = (rating != 'null') ? {userRating: rating} : {};
904                     } else {
905                         if (rating != 'null') this.worklist[chunkId].userRating = rating;
906                     }
907 
908             }//end of for
909 
910         }
911     },
912 
913     /**
914      * Returns the feature list.
915      * @return {Array} The feature list
916      */
917     getFeatureList : function() {
918         return this.featureList;
919     },
920 
921     /**
922      * Set the feature list for this workset.
923      * @param {Array} featureList An array of features
924      */
925     setFeatureList : function(featureList) {
926         this.featureList = featureList;
927     },
928 
929     /**
930      * Returns the decision tree
931      * @return {String} The decision tree
932      */
933     getDecisionTree : function() {
934         return this.decisionTree;
935     },
936     
937      /**
938      * Set the decision tree summary.
939      * @param {String} decisionTree A decision tree string
940      */
941     getDecisionTreeImage : function() {
942         return this.decisionTreeImage;
943     },
944     
945      /**
946      * Set the decision tree summary.
947      * @param {String} decisionTree A decision tree string
948      */
949     setDecisionTreeImage : function(decisionTreeImage) {
950         this.decisionTreeImage = decisionTreeImage;
951     },
952     
953 
954     /**
955      * Set the decision tree.
956      * @param {String} decisionTree A decision tree string
957      */
958     setDecisionTree : function(decisionTree) {
959         this.decisionTree = decisionTree;
960     },
961 
962     /**
963      * Returns the decision tree summary
964      * @return {String} The decision tree
965      */
966     getDecisionTreeSummary : function() {
967         return this.decisionTreeSummary;
968     },
969 
970     /**
971      * Set the decision tree summary.
972      * @param {String} decisionTree A decision tree string
973      */
974     setDecisionTreeSummary : function(decisionTreeSummary) {
975         this.decisionTreeSummary = decisionTreeSummary;
976     },
977 
978     /**
979      * Returns the name of this workset.
980      * @return {String} The workset name
981      */
982     getWorksetName : function() {
983         return this.worksetName;
984     },
985 
986     /**
987      * Sets the name of this workset.
988      * @param {String} worksetName The name of the workset
989      */
990     setWorksetName : function(worksetName) {
991         this.worksetName = worksetName;
992     },
993 
994     /**
995      * Returns the itinerary for this workset.
996      * @return {String} The itinerary
997      */
998     getItinerary : function() {
999         return this.itinerary;
1000     },
1001 
1002     /**
1003      * Sets the itinerary for this workset.
1004      * Possible values are: 'MonkNaiveBayes', and 'MonkDTree'.
1005      * @param {String} itinerary The itinerary
1006      */
1007     setItinerary : function(itinerary) {
1008         this.itinerary = itinerary;
1009     },
1010 
1011     /**
1012      * Returns the feature for this workset.
1013      * @return {String} The feature
1014      */
1015     getFeature : function() {
1016         return this.feature;
1017     },
1018 
1019     /**
1020      * Sets the feature for this workset.
1021      * Possible values are: 'contents', 'twogram_contents' and 'threegram_contents'.
1022      * @param {String} feature The feature
1023      */
1024     setFeature : function(feature) {
1025         this.feature = feature;
1026     },
1027 
1028     /**
1029      * Returns the terms/features found in a specific chunk.
1030      * @param {String} chunkId The chunk ID
1031      * @return {Array} An array of terms
1032      */
1033     getTermsForChunk : function(chunkId) {
1034         var chunk = this.getWorklist()[chunkId];
1035         if (chunk != null) {
1036             return chunk.terms;
1037         } else {
1038             return null;
1039         }
1040     },
1041 
1042     /**
1043      * Associates a number of terms/features with a specific chunk.
1044      * @param {String} chunkId The chunk ID
1045      * @param {Array} terms An array of terms to add
1046      */
1047     addTermsToChunk : function(chunkId, terms) {
1048         if (this.getTermsForChunk(chunkId) == null) {
1049             this.getWorklist()[chunkId].terms = terms;
1050         } else {
1051             for (var i = 0; i < terms.length; i++) {
1052                 var term = terms[i];
1053                 if (this.getWorklist()[chunkId].terms.indexOf(term) == -1) {
1054                     this.getWorklist()[chunkId].terms.push(term);
1055                 }
1056             }
1057         }
1058     },
1059 
1060     /**
1061      * Removes the terms/features associated with a specific chunk.
1062      */
1063     clearTermsForChunks : function() {
1064         var worklist = this.getWorklist();
1065         for (chunkId in worklist) {
1066             delete worklist[chunkId].terms;
1067         }
1068     },
1069 
1070     /**
1071      * Returns the current workset, including all the relevant properties.
1072      * Currently some properties are being adapted for use with Nora services:
1073      * e.g. chunk user ratings are returned as the trainingListArray/trainingListRatingArray
1074      * @return {Object} The workset object
1075      */
1076     getWorkset : function() {
1077         // here we're making changes to adapt the workset for using old Nora services
1078 
1079         var worklist = this.getWorklist();
1080         var chunkType = this.getChunkType();
1081         var worklistArray = [];
1082         var worklistRatingArray = [];
1083         var trainingListArray = [];
1084         var trainingListRatingArray = [];
1085 
1086         for (var chunkId in worklist) {
1087             var chunk = worklist[chunkId];
1088 
1089             worklistArray.push(chunkId);
1090             if (chunk.systemRating) {
1091                 worklistRatingArray.push(chunk.systemRating);
1092             }
1093 
1094 
1095             if (chunk.userRating){
1096                 trainingListArray.push(chunkId);
1097                 trainingListRatingArray.push(chunk.userRating);
1098             }
1099         }
1100 
1101         var workset = {
1102             projectId: this.getProjectId(),
1103             worksetId: this.getWorksetId(),
1104             chunkType: chunkType,
1105             itinerary: this.getItinerary(),
1106             worksetName: this.getWorksetName(),
1107             feature: this.getFeature(),
1108             trainingList: trainingListArray.join(),
1109             trainingListRating: trainingListRatingArray.join(),
1110             workList: worklistArray.join(),
1111             workListRating: worklistRatingArray.join()
1112         };
1113         return workset;
1114     },
1115 
1116     /**
1117      * Loads a workset into the data manager.  Then gets the labels from the server.
1118      * @param {Object} workset
1119      * @config {String} label
1120      * @config {Integer} id
1121      * @config {Integer} projectId
1122      * @config {String} trainingList
1123      * @config {String} trainingListRating
1124      * @config {String} workList
1125      * @config {String} workListRating
1126      * @config {String} itinerary
1127      */
1128     setWorkset : function(workset) {
1129         this.resetWorkset();
1130 
1131         if (workset.label) this.setWorksetName(workset.label);
1132         if (workset.projectId) this.setProjectId(workset.projectId);
1133         if (workset.id) this.setWorksetId(workset.id);
1134         if (workset.feature) this.setFeature(workset.feature);
1135         if (workset.trainingList) this.setUserRatings(workset.trainingList, workset.trainingListRating);
1136         // ignore worklistRating here, only set it from processResults method below
1137         if (workset.workList) this.setWorklist(workset.workList.split(','), null);
1138         if (workset.itinerary) this.setItinerary(workset.itinerary);
1139 
1140         for (var nodeId in this.worklist) {
1141             this.worklist[nodeId].chunkType = 'work';
1142         }
1143 
1144         Monk.data.workset.getWorkpartLabels(workset.id, 'worklist');
1145     },
1146 
1147 
1148     /**
1149      * Checks for a minimum of 2 ratings in the workset, (before running an analysis).
1150      * @returns {Boolean} True if the workset is valid.
1151      */
1152     isWorksetValid : function () {
1153         var ratings = {};
1154         var tlr = this.getWorkset().trainingListRating.split(',');
1155         for (var i=0;i<tlr.length;i++) {
1156             if (tlr[i]) {
1157                 if (!ratings[tlr[i]]) {ratings[tlr[i]]=0}
1158                 ratings[tlr[i]]++;
1159             }
1160         }
1161         var ks = 0;
1162         for (var r in ratings) {
1163             ks++;
1164         }
1165         if (ks<2) {
1166             return false;
1167         }
1168         return true;
1169     },
1170 
1171     /**
1172      * @return {Object} The data associated with the project for this session
1173      * @config {String} created
1174      * @config {String} label
1175      * @config {Integer} projectId
1176      * @config {Object} toolsets
1177      * @config {Object} worksets
1178      */
1179     getProjectData : function() {
1180         return this.projectData;
1181     },
1182 
1183     /**
1184      * Set the project data for this session
1185      * @param {Object} projectData
1186      * @config {String} created
1187      * @config {String} label
1188      * @config {Integer} projectId
1189      * @config {Object} toolsets
1190      * @config {Object} worksets
1191      */
1192     setProjectData : function(projectData) {
1193         this.projectData = projectData;
1194     },
1195 
1196     /**
1197      * Update the workset in projectData with the values from the currently loaded workset.
1198      */
1199     updateProjectDataWorkset : function() {
1200         var newWorkset = this.getWorkset();
1201         var oldWorkset = this.getProjectData().worksets.get(newWorkset.worksetId);
1202         for (var property in oldWorkset) {
1203             var newProperty = newWorkset[property];
1204             if (newProperty != null) oldWorkset[property] = newProperty;
1205         }
1206         this.getProjectData().worksets.replace(newWorkset.worksetId, oldWorkset);
1207     },
1208 
1209     /**
1210      * Returns the result summary.
1211      * @return {String} The result summary
1212      */
1213     getResultSummary : function() {
1214         return this.resultSummary;
1215     },
1216 
1217     /**
1218      * Set the result summary.
1219      * @param {String} A string describing the result.
1220      */
1221     setResultSummary : function(result) {
1222         this.resultSummary = result;
1223     },
1224 
1225     /**
1226      * Gets results of a particular type.
1227      * @param {String} type Can be either: 'feature', 'tree', 'prediction'
1228      * @return {Array} The filtered results
1229      */
1230     getResults : function(type) {
1231         var filteredResults = [];
1232         var results = Monk.component.dataManager.getProjectData().results;
1233         var filter = "";
1234 
1235         switch (type) {
1236             case 'feature':
1237                 filter = 'org.monkproject.meandre.components.beans.features.FeatureList';
1238                 break;
1239             case 'tree':
1240                 filter = 'org.monkproject.meandre.components.beans.C45TreeBean';
1241                 break;
1242             case 'prediction':
1243                 filter = 'org.monkproject.meandre.components.beans.PredictionFlowResult';
1244                 break;
1245             default:
1246                 throw "wrong type";
1247         }
1248 
1249         for (var i = 0, length = results.length; i < length; i++) {
1250             var result = results[i];
1251             if (results.dataType == filter) {
1252                 filteredResults.push(result);
1253             }
1254         }
1255 
1256         return filteredResults;
1257     },
1258 
1259     /**
1260      * Takes an associative array and returns two arrays: keys and values.
1261      * If innerValue is passed, then the method looks for a property of value
1262      * instead of the value itself e.g. value = object[key][innerValue].
1263      * @param {Object} associativeArray
1264      * @param {String} innerValue
1265      * @return {Array} An array containing two arrays of keys and values
1266      */
1267     associativeArray2Arrays : function(associativeArray, innerValue) {
1268         var keys = "";
1269         var values = "";
1270         if (associativeArray == null) {
1271             keys = null;
1272             values = null;
1273         } else {
1274             for (var key in associativeArray) {
1275                 keys += key + ',';
1276                 if (innerValue != null) {
1277                     values += associativeArray[key][innerValue] + ',';
1278                 } else {
1279                     values += associativeArray[key] + ',';
1280                 }
1281             }
1282             keys = keys.substr(0, keys.length - 1); // trim last comma
1283             values = values.substr(0, values.length - 1);
1284         }
1285         return [keys, values];
1286     },
1287 
1288 
1289 /**
1290  * Helper methods used primarily by ProjectSelector and feature.initializeParameters.
1291  */
1292 
1293     /**
1294      * Creates a new project object, suitable for addition to projectData.
1295      * @param {Element} projectElement An element containing project info.
1296      * @return {Object} A project object
1297      */
1298     createNewProject : function(projectElement) {
1299 		if (projectElement==undefined) {
1300 			Ext.Msg.show({
1301 				   title:'Project Error',
1302 				   msg: 'An attempt was made to load an inexistent project. Continuing will likely cause further errors. Would you like to start over at the welcome screen?',
1303 				   buttons: Ext.Msg.OKCANCEL,
1304 				   fn: function(btnId) {
1305 				   		if (btnId == 'ok') {
1306 							document.location = document.location.pathname;
1307 						}
1308 				   },
1309 				   icon: Ext.MessageBox.ERROR
1310 				})
1311 		}
1312         var label = projectElement.getElementsByTagName('label')[0].firstChild.data;
1313         var commentsElement = projectElement.getElementsByTagName('comments')[0];
1314         var comments = null;
1315         if (commentsElement) {
1316             if (commentsElement.firstChild != null) comments = commentsElement.firstChild.data;
1317         }
1318         var created = projectElement.getElementsByTagName('datecreated')[0].firstChild.data;
1319         var projectId = projectElement.getAttribute('id');
1320         projectData = {
1321             projectId: projectId, created: created, label: label, comments: comments,
1322             worksets: new Ext.util.MixedCollection(),
1323             toolsets: new Ext.util.MixedCollection(),
1324             results: new Ext.util.MixedCollection()
1325         };
1326 
1327         return projectData;
1328     },
1329 
1330     /**
1331      * Adds results to the project data.
1332      * @param {Element} resultsElement An element containing results info.
1333      * @param {Object} projectData The project data to add to.
1334      */
1335     addResultsToProject : function(resultsElement, projectData) {
1336         if (resultsElement.getAttribute('num') != null) {
1337             var jsonString = Monk.utils.xml2json(resultsElement, " ");
1338             var json = "";
1339             (eval('json='+jsonString));
1340 
1341             if (json.results.result.length == null) {
1342                 json.results.result = [json.results.result]; // json array fix
1343             }
1344 
1345             for (var i = 0, length = json.results.result.length; i < length; i++) {
1346                 var result = json.results.result[i];
1347 
1348                 var instanceId = result.instanceId ? result.instanceId : json.results.instanceId;
1349                 var sameInstance = projectData.results.get(instanceId);
1350                 if (sameInstance == null) {
1351                     projectData.results.add(instanceId, [result]);
1352                 } else {
1353                     var addedValue = false;
1354                     for (var j = 0, length2 = sameInstance.length; j < length2; j++) {
1355                         var oldResult = sameInstance[j];
1356                         if (oldResult.value == null) {
1357                             if (oldResult.dataType == result.dataType) {
1358                                 oldResult.value = result.value;
1359                                 addedValue = true;
1360                             }
1361                         }
1362                     }
1363                     if (!addedValue) sameInstance.push(result);
1364                 }
1365             }
1366         }
1367     },
1368 
1369     /**
1370      * Processes results data and sets it in this DataManager.
1371      * @param {String} instanceId The instance ID for the analysis which produced these results.
1372      * @param {Array} resultsArray The array of results to process.
1373      * @return {Object}
1374      * @config {Array} tempResults An array of processed temp results (for saving later).
1375      * @config {String} resultsProcessed A string describing the types of results processed.
1376      */
1377     processResults : function(instanceId, resultsArray) {
1378         var resultsInfo = {tempResults: [], resultsProcessed: []};
1379 
1380         for (var i = 0; i < resultsArray.length; i++) {
1381             var result = resultsArray[i];
1382 
1383             var dataType = result.dataType;
1384             if (dataType == "org.monkproject.meandre.components.beans.PredictionFlowResult") {
1385                 var worklist = [];
1386                 var worklistRating = [];
1387                 var confidence = [];
1388                 var predictionArray = result.value.PredictionFlowResult.result["org.monkproject.meandre.components.beans.PredictionResult"];
1389                 for (var j = 0; j < predictionArray.length; j++) {
1390                     var prediction = predictionArray[j];
1391                     worklist.push(prediction.docId);
1392                     worklistRating.push(prediction.value);
1393                     confidence.push(prediction.probabilityRatio['double']);
1394                 }
1395 
1396                 this.setWorklist(worklist, worklistRating, confidence);
1397 
1398                 var traininglist = [];
1399                 var traininglistRating = [];
1400                 //debugger;
1401                 var trainingArray = result.value.PredictionFlowResult.trainingList.entry;
1402 
1403                 for (var j = 0; j < trainingArray.length; j++) {
1404                     var training = trainingArray[j].string;
1405                     traininglist.push(training[0]);
1406                     traininglistRating.push(training[1]);
1407                 }
1408                 this.setUserRatings(traininglist.join(), traininglistRating.join());
1409 
1410                 var summary = result.value.PredictionFlowResult.resultSummary;
1411                 if (summary != null) {
1412                     this.setResultSummary(summary);
1413                 }
1414 
1415                 var tempResult = {
1416                     dataType: dataType,
1417                     instanceId: instanceId,
1418                     value: result.value
1419                 };
1420                 resultsInfo.tempResults.push(tempResult);
1421                 resultsInfo.resultsProcessed.push('predictions');
1422             } else if (dataType == "org.monkproject.meandre.components.beans.features.FeatureList") {
1423                 var featureType = result.value.FeatureList.featureType;
1424                 this.setFeature(featureType);
1425 
1426                 var features = result.value.FeatureList.feature["org.monkproject.meandre.components.beans.features.Feature"];
1427                 this.setFeatureList(features);
1428 
1429                 var tempResult = {
1430                     dataType: dataType,
1431                     instanceId: instanceId,
1432                     value: result.value
1433                 };
1434                 resultsInfo.tempResults.push(tempResult);
1435                 resultsInfo.resultsProcessed.push('features');
1436             } else if (dataType == "java.lang.String") {
1437                 var treeString = escape(result.value.String);
1438                 this.setDecisionTree(treeString);
1439 
1440                 var tempResult = {
1441                     dataType: dataType,
1442                     instanceId: instanceId,
1443                     value: result.value
1444                 };
1445                 resultsInfo.tempResults.push(tempResult);
1446                 resultsInfo.resultsProcessed.push('decision tree');
1447             } else if (dataType == "org.monkproject.meandre.components.beans.C45TreeBean") {
1448             	//debugger;
1449                 var treeSummary = result.value.C45TreeBean.resultSummary;
1450                 var treeString = escape(result.value.C45TreeBean.tree);
1451                 var treeImage = result.image;
1452                 this.setDecisionTreeSummary(treeSummary);
1453                 this.setDecisionTree(treeString);
1454                 this.setDecisionTreeImage(treeImage);
1455 
1456                 var tempResult = {
1457                     dataType: dataType,
1458                     instanceId: instanceId,
1459                     value: result.value
1460                 };
1461                 resultsInfo.tempResults.push(tempResult);
1462                 resultsInfo.resultsProcessed.push('decision tree summary');
1463 
1464             }else {
1465             }
1466         }
1467 
1468         return resultsInfo;
1469     },
1470 
1471     /**
1472      * Creates a new toolset config object.
1473      * @param {String} toolsetId The toolset ID to use
1474      */
1475     createToolsetConfig : function(toolsetId) {
1476         var config = {};
1477         var toolset = this.getProjectData().toolsets.get(toolsetId);
1478         if (toolset == null) {
1479 			// is it a default toolset?
1480 			toolset = feature.toolsets.get(toolsetId);
1481 
1482 			if (toolset == undefined) { // bad toolset id given?
1483 				Ext.Msg.show({
1484 				   title:'Toolset Error',
1485 				   msg: 'An attempt was made to load an inexistent toolset. Continuing will likely cause further errors. Would you like to start over at the welcome screen?',
1486 				   buttons: Ext.Msg.OKCANCEL,
1487 				   fn: function(btnId) {
1488 				   		if (btnId == 'ok') {
1489 							document.location = document.location.pathname;
1490 						}
1491 				   },
1492 				   icon: Ext.MessageBox.ERROR
1493 				})
1494 			}
1495 		}
1496         config.id = toolset.id;
1497         config.label = toolset.label;
1498         config.pathToIcon = toolset.pathToIcon;
1499         config.shareable = toolset.shareable;
1500         config.description = toolset.description;
1501         config.worksetId = toolset.worksetId; // will be null if the toolset is a default
1502 
1503         // convert the tools array into a MixedCollection
1504         config.tools = new Ext.util.MixedCollection();
1505         for (var i = 0; i < toolset.tools.length; i++) {
1506             var tool = toolset.tools[i];
1507             var processedTool = {
1508                 id: tool.id,
1509                 label: tool.label,
1510                 components: tool.components,
1511                 layouts: tool.layouts,
1512                 helpUrl: tool.helpUrl
1513             };
1514             config.tools.add(tool.id, processedTool);
1515         }
1516 
1517         return config;
1518     },
1519 
1520 /**
1521  * Methods for running analyses
1522  */
1523     initializeProgressDialog : function(cachedData) {
1524         this.performingAnalysis = true;
1525         this.cachedData = cachedData;
1526 
1527         this.progressDialog = new Ext.Window({
1528             title: 'Analysis Tool',
1529             height: 90,
1530             width: 300,
1531             modal: false,
1532             shadow: true,
1533             plain: true,
1534             border: false,
1535             collapsible: true,
1536             closable: true,
1537             layout: 'fit',
1538             items: {
1539                 xtype: 'panel',
1540                 items: {
1541                     xtype: 'progress',
1542                     id: 'runAnalysisProgressBar'
1543                 }
1544             },
1545             buttons: [{
1546                 text: 'Show Results',
1547                 disabled: true,
1548                 handler: function() {
1549                     var lastStep = null;
1550                     if (cachedData.toolsetId != feature.toolFlowManager.toolset.id) {
1551                         // TODO doesn't work yet
1552                         var toolsetConfig = Monk.component.dataManager.createToolsetConfig(cachedData.toolsetId);
1553                         var toolsetObject = new Monk.component.Toolset(toolsetConfig);
1554                         lastStep = toolsetObject.tools.last().id;
1555 
1556                         Monk.component.dataManager.setToolsetId(toolsetObject.id);
1557                         feature.toolFlowManager.setToolset(toolsetObject);
1558 
1559                         if (feature.flowManager.currentStep != 'tool-flow-manager') {
1560                             feature.flowManager.addStep(feature.toolFlowManager, false);
1561                         }
1562                         feature.flowManager.goToStep(feature.toolFlowManager.id, true);
1563                     } else {
1564                         var tools = feature.toolFlowManager.getToolsetTools();
1565                         lastStep = tools[tools.length - 2].id;
1566                         if (feature.flowManager.currentStep != 'tool-flow-manager') {
1567                             feature.flowManager.goToStep(feature.toolFlowManager.id, true);
1568                         }
1569                     }
1570                     var deferredStep = function(lastStep) {
1571                         feature.toolFlowManager.getStep(lastStep);
1572                     }
1573                     deferredStep.defer(50, this, [lastStep]);
1574                     this.progressDialog.close();
1575                 },
1576                 scope: this
1577             },{
1578                 text: 'Show Log',
1579                 handler: function() {
1580                     var conn = new Ext.data.Connection();
1581                     conn.request({
1582                         url: Monk.data.PROXY_URL + 'get/SchedulerManager.log',
1583                         method: 'GET',
1584                         params: {token : Monk.component.dataManager.token},
1585                         success: function(responseObject) {
1586                             var log = responseObject.responseText;
1587                             log = log.replace(/</g, '<');
1588                             log = log.replace(/>/g, '>');
1589                             log = log.replace(/\s{2,10}/g, '<br/>');
1590                             var oldWindow = Ext.getCmp('logWindow');
1591                             if (oldWindow != null) oldWindow.close();
1592                             var logWindow = new Ext.Window({
1593                                 id: 'logWindow',
1594                                 title: 'Analysis Log',
1595                                 height: 400,
1596                                 width: 400,
1597                                 modal: false,
1598                                 shadow: true,
1599                                 plain: true,
1600                                 border: false,
1601                                 collapsible: false,
1602                                 closable: true,
1603                                 layout: 'fit',
1604                                 items: {
1605                                     xtype: 'panel',
1606                                     html: '<div style="overflow: auto; height: 100%; width: 100%;">'+log+'</div>'
1607                                 }
1608                             });
1609                             logWindow.show();
1610                         },
1611                         failure: function(response, options) {
1612                             Ext.Msg.alert('Analysis Tool', 'Error getting log.<br/><b>Error</b>: '+response.statusText);
1613                         },
1614                         scope: this
1615                     });
1616                 },
1617                 scope: this
1618             },{
1619                 text: 'Cancel',
1620                 handler: function(button) {
1621                     // TODO check to see if we're already running the analysis (we could be saving the workset)
1622                     button.disable();
1623                     this.performingAnalysis = false;
1624                     Ext.getCmp('runAnalysisProgressBar').updateText('Aborting analysis...');
1625                     // TODO abort call sent twice as a temp fix
1626                     Monk.data.seasr.abort(this.token);
1627                     Monk.data.seasr.abort.defer(10, this, [this.token]);
1628                 },
1629                 scope: this
1630             }],
1631             listeners: {
1632                 hide: {
1633                     fn: function() {
1634                         this.cancelAnalysis();
1635                     }, scope: this
1636                 }
1637             }
1638         });
1639         this.progressDialog.show();
1640         Ext.getCmp('runAnalysisProgressBar').wait();
1641         Ext.getCmp('runAnalysisProgressBar').updateText('Saving workset...');
1642     },
1643 
1644     runAnalysis : function() {
1645         Ext.getCmp('runAnalysisProgressBar').updateText('Contacting server...');
1646         var flowId = Monk.component.dataManager.getItinerary();
1647         var projectId = Monk.component.dataManager.getProjectId();
1648         var worksetId = Monk.component.dataManager.getWorksetId();
1649         var toolsetId = Monk.component.dataManager.getToolsetId();
1650         var featureValue = Monk.component.dataManager.getFeature();
1651         Monk.data.seasr.runAnalysis({
1652             projectId: projectId,
1653             worksetId: worksetId,
1654             flowId: flowId,
1655             resultName: this.cachedData.name,
1656             resultDescription: this.cachedData.description,
1657             emailAddress: this.cachedData.email,
1658             feature: featureValue,
1659             majorWordClasses: this.cachedData.wordClass,
1660             cutoff: this.cachedData.numfeature,
1661             toolsetId: toolsetId,
1662             share: this.cachedData.share,
1663             async: this.cachedData.async
1664         });
1665     },
1666 
1667     updateProgress : function(data) {
1668         if (this.performingAnalysis) {
1669             if (this.cachedData.async == false) {
1670                 Ext.getCmp('runAnalysisProgressBar').updateText('Running analysis...');
1671                 this.token = data.token;
1672                 this.setTimer(this.token);
1673             } else if (this.cachedData.async == true) {
1674                 this.token = data.token;
1675                 this.progressDialog.close();
1676                 Monk.component.messenger.alert('Analysis Tool', 'The server is analyzing your workset.  You will receive an email upon completion.');
1677                 //this.getFeaturesButton.enable();
1678             }
1679         }
1680     },
1681 
1682     processStatus : function(data) {
1683         this.instanceId = data.instanceId;
1684         if (data.status == 'FINISH') {
1685             this.jobStatusTimer.stop();
1686             Ext.getCmp('runAnalysisProgressBar').updateText('Getting results...');
1687             Monk.data.seasr.getAnalysisResults(this.instanceId, true);
1688         } else if (data.status == 'ABORT') {
1689             if (this.performingAnalysis) {
1690                 // server error
1691                 Monk.component.messenger.alert('Analysis Tool','An error happened at the analytics server.  Close this window and click on Show Log to see the error message.');
1692                 Workbench.component.manager.notify(new Monk.event.analysis.Aborted({
1693                     label: 'Analysis aborted for token ' + this.token + ' Click on Show Log to display the log message'
1694                 }), {status: data.status});
1695             } else {
1696                 // user aborted
1697                 Monk.component.messenger.alert('Analysis Tool','Analysis call has been aborted.');
1698             }
1699             this.cancelAnalysis();
1700         } else if (data.status == 'ENQUEUED') {
1701             Ext.getCmp('runAnalysisProgressBar').updateText('In queue. Your position is: '+data.queuePos);
1702         }
1703     },
1704 
1705     setTimer : function(token) {
1706         // complicated timer object to preserve scope with setInterval
1707         function StatusRequester(token, time) {
1708             this.ref = null;
1709             this.time = time;
1710             this.token = token;
1711         }
1712         StatusRequester.prototype = {
1713             // TODO getAnalysisResults is getting called twice
1714             getIntervalFn: function(token) {
1715                 return function() {
1716                     Monk.data.seasr.getStatus(token);
1717                 }
1718             },
1719             start: function() {
1720                 this.ref = setInterval(this.getIntervalFn(this.token), this.time);
1721             },
1722             stop: function() {
1723                 clearInterval(this.ref);
1724             }
1725         };
1726         this.jobStatusTimer = new StatusRequester(token, this.timerInterval);
1727         this.jobStatusTimer.start();
1728     },
1729 
1730     cancelAnalysis : function() {
1731         this.performingAnalysis = false;
1732         this.cachedData = null;
1733         // keep token as it's used by the call to get the log
1734         // this.token = null;
1735         if (this.jobStatusTimer != null) {
1736             this.jobStatusTimer.stop();
1737             this.jobStatusTimer = null;
1738         }
1739         this.progressDialog.buttons[2].disable(); // cancel button
1740         
1741         if( Ext.getCmp('runAnalysisProgressBar')!=null){
1742          Ext.getCmp('runAnalysisProgressBar').reset();
1743          Ext.getCmp('runAnalysisProgressBar').updateText('Analysis aborted.');
1744         }
1745     }
1746 
1747 });
1748 
1749 /**
1750  * A static instance of the {@link Monk.component.DataManager} class.
1751  */
1752 Monk.component.dataManager = new Monk.component.DataManager();
1753