Ext
/**
 * @class Voyeur.Tool.DocumentTypeFrequenciesGrid 
 * @description A panel for displaying type frequencies for individual documents in a tabular format.
 * @extends Ext.grid.Panel
 * @extends Voyeur.Tool
 * @author Stéfan Sinclair
 * @since 0.1.1
 */
Voyeur.Tool.DocumentTypeFrequenciesGrid = Ext.extend(Ext.grid.GridPanel, {
	constructor : function(config) {
		Ext.apply(this, new Voyeur.Tool(config, Voyeur.Tool.DocumentTypeFrequenciesGrid.prototype.i18n))

		var xtypePrefix = config.xtype+'.';

		var store = new Ext.data.GroupingStore({
			reader: new Ext.data.JsonReader(
				{
					root : 'documentTypes.types'
					,totalProperty : 'documentTypes["@totalTypes"]'
				},
				Ext.data.Record.create(Voyeur.data.DocumentTypes.fields))
			,proxy: new Ext.data.HttpProxy({url:this.getTromboneUrl()})
			,listeners : {
				'loadexception' : {
					fn: function(conn, proxy, response, error){
						var alert = Ext.MessageBox.alert("Error", "An error occurred while loading data:<pre style='overflow: auto; clear: both'>\n" + response.responseText+"</pre>");
						alert.setIcon(Ext.MessageBox.ERROR);
					}
					,scope : this
				}
			}
			,remoteSort: true
			,baseParams : {
				tool : 'DocumentTypeFrequencies'
				,bins : 10
				,extendedSortZscoreMinimum : 1
			}
			,sortInfo : {field : 'rawFreq', direction : 'DESC'}
			,groupField:'type'
			,groupOnSort : false
		});
		store.paramNames.sort='sortBy';
		store.paramNames.dir='sortDirection'

		this.pagingToolBar = new Ext.PagingToolbar({
				store : store
		        ,pageSize: 30
				,displayInfo: false
				,displayMsg : "{0} - {1} of {2}"
				,listeners : {
					'render' : function(tb) {
						tb.first.hide();
						tb.last.hide();
						tb.refresh.hide();
						seps = tb.findByType('tbseparator');
						for (var i=0;i<seps.length;i++) {seps[i].hide();}
					}
				}
			});

		config.viewConfig = config.viewConfig ? config.viewConfig : {};
		Ext.applyIf(config.viewConfig, {
//			forceFit:true,
			emptyText : this.localize('noResults','tool'),
			deferEmptyText: false
			,hideGroupedColumn : true			
		})

		if (!config.plugins) {config.plugins=[]}
		config.plugins.push(new Ext.ux.grid.Favs({
			exporter: function(records) {
				var vals = [];
				for (var i=0;i<records.length;i++) {
					vals.push(records[i].get('docId')+':'+records[i].get('type'))
				}
				return {docIdType: vals}
			}
		}))
		
		var sm = new Ext.grid.CheckboxSelectionModel()

		var panel = this;
		Ext.applyIf(config, {
			view :  new Ext.grid.GroupingView(config.viewConfig)
			,iconCls : 'table'
//			viewConfig :  config.viewConfig
			,store : store
			,stripeRows : true
			,loadMask : true
			,bbar : [this.pagingToolBar]
			,autoExpandColumn : this.getId()+'-column-docLabel'
			,sm : new Ext.grid.CheckboxSelectionModel()
			,colModel : new Ext.grid.ColumnModel([sm
				,{header : this.localize('docLabel'), dataIndex : 'docIndex', id : this.getId()+'-column-docLabel', toolTip : Voyeur.localization.get('tool.frequencies_document.term'), renderer : function(val) {return panel.getCorpus().getDocument(val).getShortLabel()}}
  				,{header : this.localize('docTitle'), dataIndex : 'docIndex', id : this.getId()+'-column-docTitle', hidden: true, toolTip : Voyeur.localization.get('tool.frequencies_document.term'), renderer : function(val) {return panel.getCorpus().getDocument(val).get('title')}}
  				,{header : this.localize('docAuthor'), dataIndex : 'docIndex', id : this.getId()+'-column-Author', hidden: true, toolTip : Voyeur.localization.get('tool.frequencies_document.term'), renderer : function(val) {return panel.getCorpus().getDocument(val).get('author')}}
  				,{header : this.localize('docTime'), dataIndex : 'docIndex', id : this.getId()+'-column-Time', hidden: true, toolTip : Voyeur.localization.get('tool.frequencies_document.term'), renderer : function(val) {return panel.getCorpus().getDocument(val).getDate()}}
				,{header : 'Type', dataIndex : 'type', sortable : true, toolTip : Voyeur.localization.get('tool.frequencies_document.term'), renderer : function(val,cell,record) {return "<span class='keyword'>"+val+"</span>"}}
				,{header : Voyeur.localization.get(xtypePrefix+'rawFreq'), dataIndex : 'rawFreq', sortable : true, tooltip : Voyeur.localization.get(xtypePrefix+'rawFreqTip'), renderer : Ext.util.Format.numberRenderer('0,000'), width: 60}
				,{header : this.localize('rawZscore'), dataIndex : 'rawZscore', sortable : true, hidden: true, tooltip : this.localize('rawZscoreTip'), renderer : function(val) {return isNaN(val) ? '–' : "<span class='"+ (val < 0 ? 'negative' : 'positive') + "'>"+ Ext.util.Format.number(val,'0,000.00') + '</span>'}}
				,{header : this.localize('rawZscoreCorpusDelta'), dataIndex : 'rawZscoreCorpusDelta', sortable : true, hidden: false, tooltip : this.localize('rawZscoreCorpusDeltaTip'), renderer : function(val) {return isNaN(val) ? '–' : "<span class='"+ (val < 0 ? 'negative' : 'positive') + "'>"+ Ext.util.Format.number(val,'0,000.00') + '</span>'}}
				,{header : Voyeur.localization.get(xtypePrefix+'relativeFreq'), dataIndex : 'relativeFreq', sortable: true, tooltip : Voyeur.localization.get(xtypePrefix+'relativeFreqTip'), renderer : function(val) {return Ext.util.Format.number(val * 10000, '0,000.00')}, width: 60}
				
				// TODO: fix distribution mean in document frequencies ,{header : Voyeur.localization.get(xtypePrefix+'distributionMean'), dataIndex : 'distributionMean', hidden : true, tooltip : Voyeur.localization.get(xtypePrefix+'distributionMeanTip'), renderer : function(val) {return Ext.util.Format.number(val,'0,000.0')}, width: 60}
				,{header : Voyeur.localization.get(xtypePrefix+'distributionStdDev'), dataIndex : 'distributionStdDev', sortable: true, hidden : true, tooltip : Voyeur.localization.get(xtypePrefix+'distributionStdDevTip'), renderer : function(val) {return isNaN(val) ? '–' : Ext.util.Format.number(val,'0,000.000')}, width: 60}
				,{header : Voyeur.localization.get(xtypePrefix+'distributionKurtosis'), dataIndex : 'distributionKurtosis', sortable: true, hidden : true, tooltip : Voyeur.localization.get(xtypePrefix+'distributionKurtosisTip'), renderer : function(val) {return isNaN(val) ? '–' : "<span class='"+ (val < 0 ? 'negative' : 'positive') + "'>"+ Ext.util.Format.number(val,'0,000.00') + '</span>'}, width: 60}
				,{header : Voyeur.localization.get(xtypePrefix+'distributionSkewness'), dataIndex : 'distributionSkewness', sortable: true, hidden: true, tooltip : Voyeur.localization.get(xtypePrefix+'distributionSkewnessTip'), renderer : function(val) {return isNaN(val) ? '–' : "<span class='"+ (val < 0 ? 'negative' : 'positive') + "'>"+ Ext.util.Format.number(val,'0,000.00') + '</span>'}, width: 60}
				,{header : Voyeur.localization.get(xtypePrefix+'distributionFreqs'), dataIndex : 'distributionFreqs', tooltip : Voyeur.localization.get(xtypePrefix+'distributionFreqsTip'), renderer: function(val,cell,record,rowIndex,colIndex) {
						return panel.getSparkLine(val, panel.getColumnModel().getColumnWidth(colIndex))
					}, width : 100}
			])
		});
		
		Voyeur.Tool.DocumentTypeFrequenciesGrid.superclass.constructor.apply(this, arguments);

		this.addListener('CorpusSummaryResultLoaded', function(src, data) {
			this.getStore().baseParams.corpus=data.corpus['@id'];
			var size = data.corpus.documents.length;
			this.adjustForDocumentsSize(size);
			var cm = this.getColumnModel();
			cm.setHidden(cm.findColumnIndex('rawZscoreCorpusDelta'), size==1);
		}, this);

		this.addListener('rowclick', function(src, grid, rowIndex, e) {
			this.fireSelectionChange();
		}, this);
		
		this.addListener('corpusTypeSelected', function(src, data, records, panel) {
			delete this.store.baseParams.docId; // in case it's set
			this.store.load({params : {type : data.type}})
		}, this)
		this.addListener('corpusTypesSelected', function(src, data, records, panel) {
			delete this.store.baseParams.docId; // in case it's set
			this.store.load({params : {type : data.type}})
		}, this);
		this.addListener('DocumentTypeFrequenciesResultLoaded', function(src, data) {
			this.getStore().baseParams.corpus=data.corpus['@id'];	
			if (data.corpus.documents.length==1) {this.getStore().clearGrouping();}
			this.getStore().loadData(data);
		}, this);
		this.addListener('DocumentTypeFrequenciesGridBootstrap', function(src, params) {
			if (params && params.docId) {this.adjustForDocumentsSize(1);}
			if (params.sortBy) {
				store.setDefaultSort(params.sortBy, params.direction ? params.direction : store.getSortState().direction);
			}
			Ext.applyIf(params,{
				start: 0, limit: this.pagingToolBar.pageSize, sortBy: this.store.getSortState().field, sortDirection: this.store.getSortState().direction
			})
			this.update({params : params, tool : ['CorpusSummary','DocumentTypeFrequencies']});
		}, this);
		
		this.addListener('corpusDocumentSelected', function(src, params) {
			this.adjustForDocumentsSize(1);
			var store = this.getStore();
			delete store.baseParams.type;
			store.baseParams.docId = params.docId;
			if (params.sortBy) {
				store.setDefaultSort(params.sortBy, params.direction ? params.direction : store.getSortState().direction);
			}
			store.load({params : {docId : params.docId, start: 0, limit: this.pagingToolBar.pageSize, sortBy : store.getSortState().field, sortDirection : store.getSortState().direction}});
		}, this);
		this.addListener('corpusDocumentsSelected', function(ids) {
			this.adjustForDocumentsSize(ids.length);
			var store = this.getStore();
			delete store.baseParams.type;
			store.baseParams.docId = ids;
			store.load({params : {docId : ids, start: 0, limit: this.pagingToolBar.pageSize, sortBy : store.getSortState().field, sortDirection : store.getSortState().direction}});
		}, this);
	}
	,adjustForDocumentsSize : function(size) {
		var store = this.getStore();
		var cm = this.getColumnModel();
		var isMultiple = size>1;
		cm.setHidden(cm.findColumnIndex('docIndex'), !isMultiple);
		if (isMultiple) {store.groupBy('type');}
		else {store.clearGrouping();}		
	}
	,fireSelectionChange : function() {
		var time = new Date().getMilliseconds();
		this.lastSelectionTime=time;
		var me = this;
		setTimeout(function() {if (me.lastSelectionTime == time) {
			records = me.getSelectionModel().getSelections();
			docIdType = []
			for (var i=0;i<records.length;i++) {
				docIdType.push(records[i].get('docId')+':'+records[i].get('type'));
			}
			if (docIdType.length==1) {
				Voyeur.application.dispatchEvent('documentTypeSelected', this, {docIdType : docIdType[0]}, records[0], me.getStore(), me);
			}
			else if (docIdType.length>1) {
				Voyeur.application.dispatchEvent('documentTypesSelected', this, {docIdType : docIdType}, records, me.getStore(), me);
			}
		}}, 1000);
	}
	,lastSelectionTime : 0
	,handleCorpusTermRowClick : function(sm) {
	}

	,showOptions : function() {
		this.showOptionsWindow({
			items : [{
				xtype : 'form',
				labelWidth : 150,
				labelAlign : 'right',
				border : false,
				items : [{
					xtype : 'combo',
					id : 'stopList',
					value : this.getStore().baseParams.stopList,
					fieldLabel : '<span ext:qtip="'
							+ this.localize('stopListTip','tool') + '">'
							+ this.localize('stopList','tool') + '</span>',
					loadingText : this.localize('loading', 'tool'),
					width : 300,
					store : this.getApplication().getStopListsStore()
				    ,selectOnFocus : true
				    ,displayField: 'label'
				    ,valueField: 'id'
				    ,mode: 'local'
				    ,emptyText: this.localize('none','tool')
				},{
					xtype : 'numberfield',
					id : 'extendedSortZscoreMinimum',
					value : this.getStore().baseParams.extendedSortZscoreMinimum,
					fieldLabel : '<span ext:qtip="'
							+ this.localize('extendedSortZscoreMinimumTip','tool')
							+ '">'
							+ this.localize('extendedSortZscoreMinimum','tool')
							+ '</span>'
				}],
				buttons : [{
					text : this.localize('ok', 'tool'),
					iconCls : 'icon-accept',
					listeners : {
						click : {
							fn : function(btn) {
								var formPanel = btn.findParentByType('form');
								var form = formPanel.getForm();
								var stopList = form.findField('stopList');

								if (stopList.getValue() && !stopList.getRawValue()) stopList.setValue('');
								else if (stopList.lastQuery && stopList.lastQuery!=stopList.getValue()) {
									stopList.getStore().loadData({stopLists: {lists: [{id: stopList.lastQuery, label: stopList.lastQuery, description: ''}]}}, true);
									stopList.setValue(stopList.lastQuery)
								}
									
								if (form.isDirty()) {
									var store = this.getStore();
									var baseParams = store.baseParams;
									baseParams.extendedSortZscoreMinimum = form.findField('extendedSortZscoreMinimum').getValue();
									baseParams.stopList = stopList.getValue();
									if (store.lastOptions) {Ext.apply(store.lastOptions.params, baseParams)}
									store.reload();
								}
								formPanel.findParentByType('window').destroy();
								
							},
							scope : this
						}
					}
				}, {
					text : this.localize('cancel', 'tool'),
					handler : function(btn) {
						btn.findParentByType('window').destroy();
					}
				}, {
					text : this.localize('restore', 'tool'),
					listeners : {
						click : {
							fn : function(btn) {
								var form = btn.findParentByType('form').getForm();
								form.findField('extendedSortZscoreMinimum').setValue(this.defaultExtendedSortZscoreMinimum);
							},
							scope : this
						}
					}
	
				}]
			}]
		})

	}
	// private localization variables
	,i18n : {
		title : {en: "Words within each Document"}
		,help : {en: "This table shows word frequencies for each document in the corpus. Hover over the column headers or toolbar buttons for more information."}
		,docLabel : {en : 'Document'}
		,docTitle : {en : 'Title'}
		,docAuthor : {en : 'Author'}
		,docTime : {en : 'Time'}
		,type : {en: "Type"}
		,typeTip : {en: "The type from the document for which data is being provided."}
		,rawFreq : {en: "Count"}
		,rawFreqTip : {en: "The raw count of this term in the document."}
		,rawZscore : {en: "Z-Score"}
		,rawZscoreTip : {en: "This is the z-score – or <a href='http://en.wikipedia.org/wiki/Standard_score' target='_blank'>standard score</a> – of the total raw frequencies for the type in the document, compared to other types; it is a normalized version of the raw frequency, showing the number of standard deviations a value is above or below the mean of type frequencies."}
		,rawZscoreCorpusDelta : {en: "Difference"}
		,rawZscoreCorpusDeltaTip : {en: "This is the difference between the z-score of the word in the document and the z-score of the word in the corpus (positive values mean the word is more frequent in the document than in the corpus as a whole). The z-score – <a href='http://en.wikipedia.org/wiki/Standard_score' target='_blank'>standard score</a> is a normalized version of the raw frequency, showing the number of standard deviations a value is above or below the mean of type frequencies."}
		,relativeFreq : {en: "Relative"}
		,relativeFreqTip : {en: "The relative count of this type in the document (per 10,000 words)."}
		,distributionMean : {en: "Mean"}
		,distributionMeanTip : {en: "This is the mean of distribution values for the document."}
		,distributionStdDev : {en: "Std. Dev."}
		,distributionKurtosis : {en: "Peakedness"}
		,distributionSkewness : {en: "Skew"}
		,distributionFreqs : {en: "Trend"}
		,distributionFreqsTip : {en: "This graph represents the values of the mean relative counts across the corpus (every document has a represented value)."}
		,bins : {en: "Distribution"}
		,binsTip : {en: "This graph represents the distribution of the term across the document."}
		,add_terms : {en: "Add terms"}
		,add_termsMsg : {en: "You can add new search terms below, one per line."}
		,selectRowsForResults : {en: "Generate results by selecting rows from the <i>Document Types</i> tool"}
	}
});

Ext.reg('voyeurDocumentTypeFrequenciesGrid', Voyeur.Tool.DocumentTypeFrequenciesGrid);
