/**
 * @class Voyeur.Tool.CorpusSummary A panel that provides an overview of the current corpus, intended to suggest preliminary aspects to study.
 * @namespace Voyeur.Tool
 * @extends_ext Ext.Panel
 * @extends Voyeur.Tool
 * @author Stéfan Sinclair
 * @since 0.1.1
 */
Voyeur.Tool.CorpusSummary = Ext.extend(Ext.Panel, {
	
	loading: false,
	
	constructor : function(config) {
		
		Ext.apply(this, new Voyeur.Tool(config, this));

		Ext.applyIf(config, {
			bodyStyle: {'background-color': 'white', 'padding-top': '12px'},
			frame: true,
			border: false,
			autoScroll: true
		})
		Voyeur.Tool.CorpusSummary.superclass.constructor.call(this, config);
		
		/**
		 * @event CorpusSummaryResultLoaded
		 * @type listener
		 */
		this.addListener('CorpusSummaryResultLoaded', function(src, data) {
			if (this.rendered && !this.loading) {
				this.loadData();
			}
		}, this);
	}

	,loadData: function() {
		this.loading = true;
		this.body.update(""); // clear page
		if (this.getCorpus().getSize()==0) {return;}
		this.showCorpusDocsAndWordsCount();
		this.body.addListener('click', function(e) {
			var target = e.getTarget(null,null,true);
			if (target && target.dom.tagName=='A') {
				var app = this.getApplication();
				params = {};
				if (target.hasClass('corpus-documents')) {
					if (target.hasClass('corpus-documents-length')) {
						params.sortBy =  'totalWordTokens';
					}
					else if (target.hasClass('corpus-documents-density')) {
						params.sortBy =  'wordDensity';
					}
					params.sortDirection='DESC';
					/**
					 * @event CorpusGridBootstrap
					 * @param {Voyeur.Tool.CorpusSummary} tool
					 * @param {Object} params <ul>
					 * <li><b>sortBy</b> : String</li>
					 * <li><b>sortDirection</b> : String</li>
					 * </ul>
					 * @type dispatcher
					 */
					app.dispatchEvent.call(app, 'CorpusGridBootstrap', this, params);
				}
				else if (target.hasClass('document-id')) {
					if (target.hasClass('document-id-distinctive')) {
						Ext.apply(params, {sortBy: 'relativeFreqCorpusDelta', sortDirection: 'DESC'});
					}
					if (target.hasClass('document-id-density')) {
						Ext.apply(params, {sortBy: 'wordDensity', sortDirection: 'DESC'});
					}
					params.docId = target.getAttributeNS('voyeur', 'val');
					/**
					 * @event corpusDocumentSelected
					 * @param {Voyeur.Tool.CorpusSummary} tool
					 * @param {Object} params <ul>
					 * <li><b>docId</b> : String</li>
					 * </ul>
					 * @type dispatcher
					 */
					app.dispatchEvent.call(app, 'corpusDocumentSelected', this, params);
				}
				else if (target.hasClass('corpus-type')) {
					/**
					 * @event corpusTypeSelected
					 * @param {Voyeur.Tool.CorpusSummary} tool
					 * @param {Object} params <ul>
					 * <li><b>type</b> : String</li>
					 * </ul>
					 * @type dispatcher
					 */
					app.dispatchEvent.call(app, 'corpusTypeSelected', this, {type: target.dom.innerHTML});
				}
				else if (target.hasClass('corpus-types')) {
					if (target.hasClass('corpus-types-peaks')) {
						Ext.apply(params, {sortBy: 'RELATIVEDISTRIBUTIONKURTOSIS', sortDirection: 'DESC', extendedSortZscoreMinimum: 1});
					}
					else {
						Ext.apply(params, {sortBy: 'rawFreq', sortDirection: 'DESC', extendedSortZscoreMinimum: null});
					}
					/**
					 * @event CorpusTypeFrequenciesRequest
					 * @param {Voyeur.Tool.CorpusSummary} tool
					 * @param {Object} params <ul>
					 * <li><b>sortBy</b> : String</li>
					 * <li><b>sortDirection</b> : String</li>
					 * <li><b>extendedSortZscoreMinimum</b> : Number</li>
					 * </ul>
					 * @type dispatcher
					 */
					app.dispatchEvent.call(app, 'CorpusTypeFrequenciesRequest', this, params, {type: 'whitelist', tools: 'voyeurCorpusTypeFrequenciesGrid'});
				}
				else if (target.hasClass('document-type')) {
					/**
					 * @event documentTypeSelected
					 * @param {Voyeur.Tool.CorpusSummary} tool
					 * @param {Object} params <ul>
					 * <li><b>docIdType</b> : String</li>
					 * </ul>
					 * @type dispatcher
					 */
					app.dispatchEvent.call(app, 'documentTypeSelected', this, {docIdType: target.getAttributeNS('voyeur', 'val')});
				}
			}
		}, this);
	}

	,showCorpusDocsAndWordsCount: function() {
		var corpus = this.getCorpus();
		new Ext.XTemplate(this.localize('corpusDocsAndWordsCount')).append(this.body, {
			docsCount: Ext.util.Format.number(corpus.get('docsCount'),'0,000')
			,totalWordTokens: Ext.util.Format.number(corpus.get('totalWordTokens'),'0,000')
			,totalWordTypes: Ext.util.Format.number(corpus.get('totalWordTypes'),'0,000')
		});
		this.showDocLengthsAndDensity();
	}
	
	,showDocLengthsAndDensity : function() {
		var docs = this.getCorpus().getDocuments().clone();
		var count = docs.getCount();
		if (count>1) {
			
			var lengths = [];
			var densities = [];
			docs.each(function(item) {
				lengths.push(item.get('totalWordTokens'))
				densities.push(item.get('wordDensity'))
			})

			// sort items
			docs.sort(null, function(a,b) {
				return a.get('totalWordTokens') >  b.get('totalWordTokens') ? -1 : 1;
			});
			
			var data = {};
			var data = count>5 ? {shortest: docs.getRange(count-2).reverse(), longest: docs.getRange(0,1)} : {all: docs.getRange()}
			var obj;
			for (var k in data) {
				if (k) {
					var items = data[k];
					for (var i=0;i<items.length;i++) {
						data[k][i] = {
							title: items[i].getShortTitle(),
							id: items[i].get('id'),
							totalWordTokens: Ext.util.Format.number(items[i].get('totalWordTokens'),'0,000'),
							docsLen: items.length
						}
					}
				}
			}
			
			var tpl = new Ext.XTemplate(this.localize('docsLength'));
			var out = '';
			if (count>5) {
				out += new Ext.Template(this.localize('docsLengthLongest')).applyTemplate([this.getSparkLine(lengths)]) + this.localize('colon', 'app') + tpl.apply({docs: data.longest})+'. ';
				out += this.localize('docsLengthShortest') + this.localize('colon', 'app') + tpl.apply({docs: data.shortest})+'. ';
				out += "<a href='#' onclick='return false' class='corpus-documents corpus-documents-length'>"+this.localize('seeAll')+'</a>'
			}
			else {
				out += new Ext.Template(this.localize('docsLengthAll')).applyTemplate([this.getSparkLine(lengths)]) + this.localize('colon', 'app') + tpl.apply({docs: data.all});
			}
			
			Ext.DomHelper.append(this.body, {tag: 'div', cls: 'corpus-summary-item', html: out});

			// sort items
			docs.sort(null, function(a,b) {
				return a.get('wordDensity') >  b.get('wordDensity') ? -1 : 1;
			});
			
			var data = {};
			var data = count>5 ? {lowest: docs.getRange(count-2).reverse(), highest: docs.getRange(0,1)} : {all: docs.getRange()}
			var obj;
			
			for (var k in data) {
				if (k) {
					var items = data[k];
					for (var i=0;i<items.length;i++) {
						data[k][i] = {
							title: items[i].getShortTitle(),
							id: items[i].get('id'),
							wordDensity: Ext.util.Format.number(items[i].get('wordDensity'),'0,000.0'),
							docsLen: items.length
						}
					}
				}
			}
			var tpl = new Ext.XTemplate(this.localize('docsDensity'));
			var out = '';
			if (count>5) {
				out += new Ext.Template(this.localize('docsDensityHighest')).applyTemplate([this.getSparkLine(densities)]) + this.localize('colon', 'app') + tpl.apply({docs: data.highest})+'. ';
				out += this.localize('docsDensityLowest') + this.localize('colon', 'app') + tpl.apply({docs: data.lowest})+'. '
				out += "<a href='#' onclick='return false' class='corpus-documents corpus-documents-density'>"+this.localize('seeAll')+'</a>'
			}
			else {
				out += new Ext.Template(this.localize('docsDensityAll')).applyTemplate([this.getSparkLine(densities)])  + this.localize('colon', 'app') + tpl.apply({docs: data.all}) +'.';
			}

			Ext.DomHelper.append(this.body, {tag: 'div', cls: 'corpus-summary-item', html: out})
		}
		
		this.showCorpusTypesTop();
	}
	
	,showCorpusTypesTop: function() {
		var el = Ext.DomHelper.append(this.body, {tag: 'div', cls: 'corpus-summary-item', html: this.localize('corpusTypesTop')}, true);
		var mask = new Ext.LoadMask(el, {msg: this.localize('loading'), removeMask: true});
		mask.show();
		var params = this.getApiParams();
		params.tool = 'CorpusTypeFrequencies';
		Ext.Ajax.request({
			url: this.getTromboneUrl()
			,params: params
			,callback: function(options, success, response) {
				if (success) {
					var json = Ext.decode(response.responseText);
					var store = new Ext.data.JsonStore({
						fields: Voyeur.data.CorpusTypes.fields
						,data: json.corpusTypes.types
					})
					var data = [];
					var len = store.getCount();
					store.each(function(item) {
						data.push({
							type: item.get('type'),
							val: Ext.util.Format.number(item.get('rawFreq'),'000,0'),
							len: len});
					})
					mask.hide();
					new Ext.DomHelper.overwrite(el, {
						tag: 'p'
						,html: this.localize('corpusTypesTop')+this.localize('colon','app')+
							new Ext.XTemplate(this.localize('corpusType')).applyTemplate({types: data})+
							'. <a href="#" onclick="return false;" class="corpus-types corpus-types-freqs">'+this.localize('more')+'</a>'
					})
				}
				else {
					this.alertError(response.responseText);
				}
				this.showCorpusTypesPeaks();
			}
			,scope: this
		});
		
	}
	
	,showCorpusTypesPeaks: function() {
		if (this.getCorpus().getSize()>1) {
			var el = Ext.DomHelper.append(this.body, {tag: 'div', cls: 'corpus-summary-item',  html: this.localize('corpusTypesPeaks')}, true);
			var mask = new Ext.LoadMask(el, {msg: this.localize('loading'), removeMask: true});
			mask.show();
			var params = this.getApiParams();
			params.tool = 'CorpusTypeFrequencies';
			params.sortBy = 'RELATIVEDISTRIBUTIONKURTOSIS';
			params.extendedSortZscoreMinimum = 1; // try to make them more significant
			Ext.Ajax.request({
				url: this.getTromboneUrl()
				,params: params
				,callback: function(options, success, response) {
					if (success) {
						var json = Ext.decode(response.responseText);
						var store = new Ext.data.JsonStore({
							fields: Voyeur.data.CorpusTypes.fields
							,data: json.corpusTypes.types
						})
						var data = [];
						var len = store.getCount();
						store.each(function(record) {
							var val = record.get('relativeFreqs');
							data.push({
								type: record.get('type'),
								val: Ext.util.Format.number(record.get('rawFreq'),'0,000')+' '+this.getSparkLine(val, 20),
								len: len
							});
						}, this)
						mask.hide();
						new Ext.DomHelper.overwrite(el, {
							tag: 'p'
							,html: this.localize('corpusTypesPeaks')+this.localize('colon','app')+
								new Ext.XTemplate(this.localize('corpusType')).applyTemplate({types: data}) +
								'. <a href="#" onclick="return false;" class="corpus-types corpus-types-peaks">'+this.localize('more')+'</a>'
						})
					}
					this.showDocumentDistinctiveWords();
				}
				,scope: this
			})
		} else {
			this.showDocumentDistinctiveWords();
		}
	}
	
	/**
	 * Show the distinctive words in the document.
	 * @private
	 */
	,showDocumentDistinctiveWords : function() {
		if (this.getCorpus().getSize()>1) {
			var docs = this.getCorpus().getDocuments();
			if (docs.getCount()>1) {
				Ext.DomHelper.append(this.body, {tag: 'div', cls: 'corpus-summary-item',  html: this.localize('distinctiveWords')});
				var list = Ext.DomHelper.append(this.body, {tag: 'ol', cls: 'normal-list', html: ''}, true);
				var item;
				var len = this.getApiParamValue('numberOfDocumentsForDistinctiveWords');
				docs.each(function(item,index,length) {
					Ext.DomHelper.append(list, {tag: 'li', 'voyeur:index': String(index), cls: (index>len-1 ? 'x-hidden' : ''), html: '<a href="#" onclick="return false" class="document-id document-id-distinctive" voyeur:val="'+item.get('id')+'">'+item.getShortTitle()+'</a>'});
				});
				if (docs.getCount()>len) {
					var tpl = new Ext.Template(this.localize('moreDistinctiveWords'));
					var remaining = docs.getCount()-len;
					var more = Ext.DomHelper.append(this.body, {tag: 'div', style: 'display: block; margin-left: 40px;', html: tpl.apply([len>remaining ? remaining : len,remaining])}, true);
					more.addListener('click', function() {
						var hidden = list.select("li[@class=x-hidden]");
						var item;
						for (i=0;i<hidden.getCount();i++) {
							if (i==len) {break;}
							item = hidden.item(i).removeClass('x-hidden');
						}
						this.showDocumentDistinctiveWordsStep(hidden.item(0));
						var remaining = hidden.getCount()-len;
						if (remaining>0) {
							more.update(tpl.apply([len>remaining ? remaining : len,remaining]))
						}
						else {more.remove();}
					}, this);
				}
	//			docs.each(function(item,index,length) {
	//				Ext.DomHelper.append(list, {tag: 'li', html: '<a href="#" onclick="return false" class="document-id document-id-distinctive" voyeur:val="'+item.get('id')+'">'+item.getShortLabel()+'</a>'});
	//			});
				this.showDocumentDistinctiveWordsStep(list.first());
			}
		} else {
			this.showCirrus();
		}
	}
	
	,showDocumentDistinctiveWordsStep : function(el) {
		var mask = new Ext.LoadMask(el, {msg: this.localize('loading'), removeMask: true});
		mask.show();
		var index = Number(el.getAttributeNS('voyeur','index'));
		var params = this.getApiParams();
		Ext.apply(params, {
			tool: 'DocumentTypeFrequencies',
			docIndex: String(index),
			sortBy: 'relativeFreqCorpusDelta',
			sortDirection: 'DESC'
		})
		Ext.Ajax.request({
			url: this.getTromboneUrl()
			,params: params
			,callback: function(options, success, response) {
				if (success) {
					var data = Ext.decode(response.responseText);
					var store = new Ext.data.JsonStore({
						fields: Voyeur.data.DocumentTypes.fields
						,data: data.documentTypes.types
					})
					var data = [];
					var len = store.getCount();
					store.each(function(item) {
						data.push({
							type: item.get('type'),
							val: Ext.util.Format.number(item.get('rawFreq'),'000,0'),
							docId: item.get('docId'),
							len: len})
					})
					mask.hide();
					new Ext.DomHelper.append(el,
							this.localize('colon','app')+new Ext.XTemplate(this.localize('documentType')).applyTemplate({types: data})+
							'. <a href="#" onclick="return false;" class="document-id document-id-distinctive" voyeur:val="'+this.getCorpus().getDocument(index).get('id')+'">'+this.localize('more')+'</a>'
					)
					var nextel = el.next();
					if (nextel && !nextel.hasClass('x-hidden')) {
						this.showDocumentDistinctiveWordsStep(nextel, index+1)
					} else {
						this.showCirrus();
					}
				}
			}
			,scope: this
		})
	}
	
	,showCirrus : function() {
		this.loading = false;
		
		return; // disabled for now
		
		var width = this.getWidth() - 12;
		var height = width / 2.5;
		this.add({
			xtype: 'voyeurCirrus',
			width: width,
			height: height,
			style: 'padding: 0 12px 12px;'
		});
		this.doLayout();
	}
	
	,showOptions : function() {
		this.showOptionsWindow({
			items : [{
				xtype : 'form',
				labelWidth : 150,
				labelAlign : 'right',
				border : false,
				items : [],
				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();
								
								// make sure we don't have any queries
								if (stopList.getValue() && !stopList.getRawValue()) {stopList.setValue('');}
								this.setApiParams({stopList: stopList.getValue()});

								formPanel.findParentByType('window').destroy();
								
								if (global) {
									this.getApplication().applyParamsGlobally({
										stopList: this.getApiParamValue('stopList')
									}, true);
								}
								else {
									this.loadData();
								}
						    	
							},
							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'));
							},
							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 numberOfDocumentsForDistinctiveWords The maximum number of documents to show distinctive words for.
		 * @type Integer
		 * @default 5
		 */
		,'numberOfDocumentsForDistinctiveWords': {
			'default': 5
		}
		/**
		 * @property limit The number of words to return in each call.
		 * @type Integer
		 * @default 5
		 */
		,'limit': {
			'default': 5
		}
		,toolType: ['Corpus']
		,listeners: ['CorpusSummaryResultLoaded']
		,dispatchers: ['CorpusGridBootstrap', 'corpusDocumentSelected', 'corpusTypeSelected', 'CorpusTypeFrequenciesRequest', 'documentTypeSelected']
	}
	
	,thumb: {
		large: 'CorpusSummary.png'
	}
	
	// private localization variables
	,i18n : {
		title : {en: "Summary"}
	    ,type : {en: "Summary"}	
		,corpusDocsAndWordsCount: {en: '<div class="corpus-summary-item">There <tpl if="docsCount == 1">is <a href="#" onclick="return false" class="corpus-documents" ext:qtip="Click to see a table of documents">1 document</a></tpl><tpl if="docsCount &gt; 1">are <a href="#" onclick="return false" class="corpus-documents" ext:qtip="Click to see a table of documents">{docsCount} documents</a></tpl> in this corpus with a total of <b>{totalWordTokens} words</b> and <b>{totalWordTypes} unique words</b>.</div>'}
		,docsLength: {en: '<tpl for="docs"><a href="#" onclick="return false" class="document-id" voyeur:val="{id}">{title}</a> ({totalWordTokens})<tpl if="xindex &lt; docsLen">, </tpl></tpl>'}
		,docsLengthLongest: {en: '<b>Longest documents</b> (by words {0})'}
		,docsLengthShortest: {en: 'Shortest documents'}
		,docsLengthAll: {en: 'Documents ordered by number of words ({0})'}
		,docsDensity: {en: '<tpl for="docs"><a href="#" onclick="return false" class="document-id" voyeur:val="{id}">{title}</a> ({wordDensity})<tpl if="xindex &lt; docsLen">, </tpl></tpl>'}
		,docsDensityHighest: {en: 'Highest <b>vocabulary density</b> ({0})'}
		,docsDensityLowest: {en: 'Lowest density'}
		,docsDensityAll: {en: 'Documents ordered by vocabulary density ({0})'}
		,help : {en : "<p>This tool shows an overview of the corpus and tries to suggest characteristics worthy of further exploration.</p>"}
		,corpusTypesTop: {en: 'Most <b>frequent words</b> in the corpus'}
		,corpusTypesPeaks: {en: 'Words with <b>notable peaks in frequency</b> across the corpus'}
		,corpusType: {en: '<tpl for="types"><a href="#" onclick="return false" class="corpus-type keyword">{type}</a> ({val})<tpl if="xindex &lt; len">, </tpl></tpl>'}
		,documentType: {en: '<tpl for="types"><a href="#" onclick="return false" class="document-type keyword" voyeur:val="{docId}:{type}">{type}</a> ({val})<tpl if="xindex &lt; len">, </tpl></tpl>'}
		,distinctiveWords: {en: '<b>Distinctive words</b> (compared to the rest of the corpus)'}
		,moreDistinctiveWords: {en: '<a href="#" onclick="return false">Next {0} of {1} remaining</a>'}
		,loading: {en: 'Loading&hellip;'}
		,seeAll: {en: 'All&hellip;'}
		,more: {en: 'More&hellip;'}
	}
});

Ext.reg('voyeurCorpusSummary', Voyeur.Tool.CorpusSummary);


