/**
 * @class Voyeur.Tool.DocumentTypeFrequenciesGrid A panel for displaying type frequencies for individual documents in a tabular format.
 * @extends_ext Ext.grid.GridPanel
 * @extends Voyeur.Tool
 * @namespace 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, this))

		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 : {
				'beforeload' : {
					fn : function(store, options) {
						if (this.hidden || this.getCorpus().isEmpty() || (!this.getApiParamValue('docIdType') && !this.getApiParamValue('docIndex') && !this.getApiParamValue('type') && !this.getApiParamValue('docId'))) {return false;}
						Ext.applyIf(options.params, this.getApiParams());
						var clean = ['docId', 'docIdType','type','query'];
						for (var i=0; i<clean.length;i++) {if (!options.params[clean[i]]) {delete options.params[clean[i]]}}
						Ext.apply(options.params, {tool: 'DocumentTypeFrequencies'});
					},
					scope : this
				},
				load: {
					fn: function(store, records, options) {
						if (options && options.params) {
							if ((options.params.docId && typeof options.params.docId == 'string') || (options.params.docIndex && typeof options.params.docIndex == 'string')) {
								this.getStore().clearGrouping();
							}
						}
							
					}
					,scope : this
				},
				'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 : this.getApiParamValue('sortBy'), direction: this.getApiParamValue('sortDirection')}
			,groupField: this.getApiParamValue('groupBy')
			,groupOnSort : false
		});
		store.paramNames.sort='sortBy';
		store.paramNames.dir='sortDirection'

		this.pagingToolBar = new Ext.PagingToolbar({
			store : store
            ,enableOverflow: true
	        ,pageSize: 30
			,displayInfo: true
			,displayMsg : "{0}-{1} of {2}"
			,listeners : {
				'render' : function(tb) {
					tb.first.hide();
					tb.last.hide();
					tb.refresh.hide();
					var seps = tb.findByType('tbseparator');
					for (var i=0;i<3;i++) {
						seps[i].hide();
					}
				}
			}
			,items: ['-',{
            	xtype: 'button',
            	text: this.localize('reset'),
            	tooltip: this.localize('resetTip'),
            	handler: function() {
            		var docId = this.getApiParamValue('docId') || this.getCorpus().getDocument(0).getId();
            		this.adjustForDocumentsSize(1);
        			this.resetFilteringApiParams();
        			this.setApiParams({docId: docId});
        			this.getStore().load();
            	},
            	scope: this
            },'-',{
                xtype: 'typeSearch',
                width: 100,
                parentTool: this,
                listeners: {
            	    typeSelected: function(combo, type, record) {
            	    	var types = this.getApiParamValue('type') || [];
            	    	if (typeof types == 'string') types = [types];
                		types.push(type);
                		this.setApiParams({type: types});
						this.store.load({params: {type: type}});
            	    },
            	    scope: this
                }
            }]
		});

		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({
			listeners: {
				selectionchange: {
					fn: function() {this.fireSelectionChange();}
					,scope: this
				}
			}

		})

		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 : sm
			,colModel : new Ext.grid.ColumnModel([sm
				,{header : this.localize('docLabel'), dataIndex : 'docIndex', id : this.getId()+'-column-docLabel', sortable: true, 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: true, 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 : this.localize('relativeFreqCorpusDelta'), dataIndex : 'relativeFreqCorpusDelta', sortable : true, hidden: true, tooltip : this.localize('relativeFreqCorpusDeltaTip'), renderer : function(val) {return isNaN(val) ? '–' : "<span class='"+ (val < 0 ? 'negative' : 'positive') + "'>"+ Ext.util.Format.number(val,'0,000.0000') + '</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+'rawDistributionStdDev'), dataIndex : 'rawDistributionStdDev', sortable: true, hidden : true, tooltip : Voyeur.localization.get(xtypePrefix+'rawDistributionStdDevTip'), renderer : function(val) {return isNaN(val) ? '–' : Ext.util.Format.number(val,'0,000.000')}, width: 60}
				,{header : Voyeur.localization.get(xtypePrefix+'rawDistributionKurtosis'), dataIndex : 'rawDistributionKurtosis', sortable: true, hidden : true, tooltip : Voyeur.localization.get(xtypePrefix+'rawDistributionKurtosisTip'), 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+'rawDistributionSkewness'), dataIndex : 'distributionSkewness', sortable: true, hidden: true, tooltip : Voyeur.localization.get(xtypePrefix+'rawDistributionSkewnessTip'), 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+'rawFreqs'), dataIndex : 'rawFreqs', tooltip : Voyeur.localization.get(xtypePrefix+'rawFreqsTip'), 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);

		/**
		 * @event CorpusSummaryResultLoaded
		 * @type listener
		 */
		this.addListener('CorpusSummaryResultLoaded', function(src, data) {
			this.getStore().load();
		}, this);
		
		/**
		 * @event DocumentTypeFrequenciesResultLoaded
		 * @type listener
		 */
		this.addListener('DocumentTypeFrequenciesResultLoaded', function(src, data) {
			this.getStore().loadData(data);
		}, this);

		/**
		 * @event documentTypeSelected
		 * @type listener
		 */
		this.addListener('documentTypeSelected', function(src, data) {
			if (src != this) {
				this.adjustForDocumentsSize(1);
				this.resetFilteringApiParams();
				var docId = data.docIdType.split(':')[0];
				this.setApiParams({docId: docId, docIdType: data.docIdType});
				this.getStore().load();
			}
			else {return false;} // make sure we didn't respond
		}, this);

		/**
		 * @event documentTypesSelected
		 * @type listener
		 */
		this.addListener('documentTypesSelected', function(src, data) {
			if (src != this) {
				var docIdTypes = data.docIdType;
				var docs = {};
				var counter = 0;
				for (var i=0;i<docIdTypes.length;i++) {
					var parts = docIdTypes[i].split(":");
					if (!docs[parts[0]]) {
						counter++;
						docs[parts[0]] = true;
					}
				}
				this.adjustForDocumentsSize(counter);
				this.resetFilteringApiParams();
				this.setApiParams({docIdType: data.docIdType});
				this.getStore().load();
			}
		}, this);

		this.addListener('rowclick', function(src, grid, rowIndex, e) {
			this.fireSelectionChange();
		}, this);
		
		/**
		 * @event corpusTypeSelected
		 * @type listener
		 */
		this.addListener('corpusTypeSelected', function(src, data, record) {
			this.adjustForDocumentsSize(this.getCorpus().getSize());
			this.resetFilteringApiParams();
			this.setApiParams({type: data.type});
			this.getStore().load();
		}, this);
		
		/**
		 * @event corpusTypesSelected
		 * @type listener
		 */
		this.addListener('corpusTypesSelected', function(src, data, records) {
			this.adjustForDocumentsSize(this.getCorpus().getSize());
			this.resetFilteringApiParams();
			this.setApiParams({type: data.type});
			this.getStore().load();
		}, this);
		
		/**
		 * @event corpusDocumentSelected
		 * @type listener
		 */
		this.addListener('corpusDocumentSelected', function(src, params) {
			this.adjustForDocumentsSize(1);
			this.resetFilteringApiParams();
			this.setApiParams({docId: params.docId});
			this.getStore().load();
		}, this);
		
		/**
		 * @event corpusDocumentsSelected
		 * @type listener
		 */
		this.addListener('corpusDocumentsSelected', function(src, params) {
			var ids = params.docId;
			this.adjustForDocumentsSize(ids.length);
			this.resetFilteringApiParams();
			this.setApiParams({docId: ids});
			this.getStore().load();
		}, this);
	}

	,resetFilteringApiParams : function(query) {
		this.setApiParams({type: undefined, docId: undefined, docIdType: undefined, query: undefined});
	}
	,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) {
				/**
				 * @event documentTypeSelected
				 * @param {Voyeur.Tool.DocumentTypeFrequenciesGrid} tool
				 * @param {Object} params <ul>
				 * <li><b>docIdType</b> : String</li>
				 * <li><b>type</b> : String</li>
				 * <li><b>record</b> : Ext.data.Record</li>
				 * </ul>
				 * @type dispatcher
				 */
				Voyeur.application.dispatchEvent('documentTypeSelected', me, {docIdType : docIdType[0], type: records[0].get('type'), record: records[0]});
			}
			else if (docIdType.length>1) {
				/**
				 * @event documentTypesSelected
				 * @param {Voyeur.Tool.DocumentTypeFrequenciesGrid} tool
				 * @param {Object} params <ul>
				 * <li><b>docIdType</b> : Array</li>
				 * <li><b>record</b> : Array</li>
				 * </ul>
				 * @type dispatcher
				 */
				Voyeur.application.dispatchEvent('documentTypesSelected', me, {docIdType : docIdType, record: records});
			}
		}}, 1000);
	}
	,lastSelectionTime : 0
	,handleCorpusTermRowClick : function(sm) {
	}

	,showOptions : function() {
		this.showOptionsWindow({
			items : [{
				xtype : 'form',
				labelWidth : 150,
				labelAlign : 'right',
				border : false,
				items : [{
					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');
								var global = form.findField('globalStopWords').getValue();

								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()) {
									this.setApiParams({
										extendedSortZscoreMinimum: form.findField('extendedSortZscoreMinimum').getValue()
										,stopList: stopList.getValue()
									});
									if (global) {
										this.getApplication().applyParamsGlobally({
											stopList: this.getApiParamValue('stopList')
										}, true);
									}
									else {
										this.getStore().load();
									}
								}
								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('stopList').setValue(this.getApiParamDefaultValue('stopList'));
								form.findField('extendedSortZscoreMinimum').setValue(this.getApiParamDefaultValue('extendedSortZscoreMinimum'));
							},
							scope : this
						}
					}
	
				}]
			}]
		}, true);

	}

	,api: {
		/**
		 * @property stopList The stop list to use to filter results.
		 * Choose from a pre-defined list, or enter a comma separated list of words, or enter an URL to a list of stop words in plain text (one per line).
		 * @type String
		 * @default null
		 * @choices stop.en.taporware.txt, stop.fr.veronis.txt
		 */
		stopList: {
			'default': null,
			'choices': ['stop.en.taporware.txt', 'stop.fr.veronis.txt']
		}
		/**
		 * @property start The index in the results to start at.
		 * @type Integer
		 * @default 0
		 */
		,start: {'default': 0}
		/**
		 * @property limit The number of words to return in each call.
		 * @type Integer
		 * @default 50
		 */
		,limit: {'default': 50}
		/**
		 * @property sortBy The property to sort results by.
		 * @type String
		 * @default rawFreq
		 * @choices docIndex, type, rawZscore, rawZscoreCorpusDelta, relativeFreq, rawDistributionStdDev, rawDistributionKurtosis, distributionSkewness, rawFreqs
		 */
		,sortBy: {'default': 'rawFreq'}
		/**
		 * @property sortDirection The direction to sort results in.
		 * @type String
		 * @default ASC
		 * @choices ASC, DESC
		 */
		,sortDirection: {'default': 'DESC'}
		/**
		 * @property groupBy The property to group results by.
		 * @type String
		 * @default type
		 * @choices docIndex, type, rawZscore, rawZscoreCorpusDelta, relativeFreq, rawDistributionStdDev, rawDistributionKurtosis, distributionSkewness, rawFreqs
		 */
		,groupBy: {'default': 'type'}
		/**
		 * @property docIdType The document type(s) to restrict results to.
		 * @type String|Array
		 * @default undefined
		 */
		,docIdType: {'default': undefined}
		/**
		 * @property type The corpus type(s) to restrict results to.
		 * @type String|Array
		 * @default undefined
		 */
		,type: {'default': undefined}
		/**
		 * @property docId The document ID to restrict results to.
		 * @type String
		 * @default undefined
		 */
		,docId: {'default': undefined}
		/**
		 * @property docIndex The document index to restrict results to.
		 * @type Integer
		 * @default undefined
		 */
		,docIndex: {'default': undefined}
		/**
		 * @property extendedSortZscoreMinimum The minimum extended sort Z score that each result should have.
		 * @type Number
		 * @default 1
		 */
		,extendedSortZscoreMinimum: {'default': null}
		,toolType: ['Table', 'Document']
//		,visibleColumn: {'default': ['type', 'rawCollocateFreq', 'relativelCollocateFreq', 'relativeRatio']}
		,listeners: ['CorpusSummaryResultLoaded', 'DocumentTypeFrequenciesResultLoaded', 'corpusDocumentSelected', 'corpusDocumentsSelected', 'corpusTypeSelected', 'corpusTypesSelected', 'documentTypeSelected', 'documentTypesSelected']
		,dispatchers: ['documentTypeSelected', 'documentTypesSelected']
	}
	
	,thumb: {
		large: 'DocumentTypeFrequenciesGrid.png'
	}
	
	// private localization variables
	,i18n : {
		title : {en: "Words in Documents"}
		,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 : "Frequencies"}
		,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: "Z-Score Difference"}
		,relativeFreqCorpusDeltaTip : {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."}
		,relativeFreqCorpusDelta : {en: "Relative Difference"}
		,rawZscoreCorpusDeltaTip : {en: "This is the difference between the relative frequency of the term in the document and its relative frequency in the corpus."}
		,relativeFreq : {en: "Relative"}
		,relativeFreqTip : {en: "The relative count of this type in the document (per 10,000 words)."}
		,rawDistributionMean : {en: "Mean"}
		,rawDistributionMeanTip : {en: "This is the mean of distribution values for the document."}
		,rawDistributionStdDev : {en: "Std. Dev."}
		,rawDistributionKurtosis : {en: "Peakedness"}
		,rawDistributionSkewness : {en: "Skew"}
		,rawFreqs : {en: "Trend"}
		,rawFreqsTip : {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"}
		,reset : {en: 'Reset'}
		,resetTip : {en: 'Resets the grid, fetching the top frequency words for the current document.'}
	}
});

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

