/**
 * @class Voyeur.Tool.TypeFrequenciesChart A panel for displaying graphs of the frequencies of types across the entire corpus.
 * @extends_ext Ext.Panel
 * @extends Voyeur.Tool
 * @namespace Voyeur.Tool
 * @author Stéfan Sinclair
 * @since 0.1.1
 */
 
Voyeur.Tool.TypeFrequenciesChart = Ext.extend(Ext.Panel, {
	constructor : function(config) {
		Ext.apply(this, new Voyeur.Tool(config, this))
		
		var bins = parseInt(this.getApiParamValue('bins'));
		this.bins = new Ext.Button({
			text: this.localize('bins')
			,tooltip : this.localize('binsTip')
			,menu: new Ext.menu.Menu({
				items : [
						new Ext.menu.CheckItem({text : '5',checked:bins==5,group:'bins'})
						,new Ext.menu.CheckItem({text : '10',checked:bins==10,group:'bins'})
						,new Ext.menu.CheckItem({text : '15',checked:bins==15,group:'bins'})
						,new Ext.menu.CheckItem({text : '20',checked:bins==20,group:'bins'})
						,new Ext.menu.CheckItem({text : '25',checked:bins==25,group:'bins'})
						,new Ext.menu.CheckItem({text : '30',checked:bins==30,group:'bins'})
						,new Ext.menu.CheckItem({text : '40',checked:bins==40,group:'bins'})
						,new Ext.menu.CheckItem({text : '50',checked:bins==50,group:'bins'})
						,new Ext.menu.CheckItem({text : '75',checked:bins==75,group:'bins'})
						,new Ext.menu.CheckItem({text : '100',checked:bins==100,group:'bins'})
					]
					,listeners : {
						'itemclick' : {
							fn : function(item) {
								this.setApiParams({bins: item.text});
								// this should only be visible for documents, so no need to check mode
								this.update({params: this.getApiParams(), tool: 'DocumentTypeFrequencies'});
							}
							,scope : this
						}
					}
			})
		});
		
		this.typeSearch = new Ext.ux.TypeSearch({
			width: 100,
            parentTool: this,
            listeners: {
        	    typeSelected: function(combo, type, record) {
    				var types = type.split(/,\s*/);
    				this.setApiParams({type: types});
    				var params = this.getApiParams();
    				this.update({params : params, tool : this.getCorpus().getSize()>1 ? 'CorpusTypeFrequencies' : 'DocumentTypeFrequencies'});
        	    },
        	    scope: this
            }
        });
		
		var freqsMode = this.getApiParamValue('freqsMode');
		Ext.applyIf(config, {
			iconCls : 'chart-line'
			,html : '<span class="x-grid-empty">'+this.localize('noResults')+'</span>'
			,bbar: [new Ext.Button({
				text: this.localize(freqsMode=='raw' ? 'raw' : 'relative'),
				menu: new Ext.menu.Menu({
					items: [
					        {
					        	text: this.localize('rawFrequencies'),
					        	checked: freqsMode=='raw',
					        	group: 'freqsMode',
					        	itemId: 'raw'
					        }
					        ,{
					        	text: this.localize('relativeFrequencies'),
					        	checked: freqsMode!='raw',
					        	group: 'freqsMode',
					        	itemId: 'relative'
					        }
					],
					listeners: {
						'itemclick': {
							fn: function(item) {
								this.setApiParams({freqsMode: item.itemId});
								var params = this.getApiParams();							
								this.update({params: params, tool: params.mode=='document' || this.getCorpus().getSize()<2 ? 'DocumentTypeFrequencies' : 'CorpusTypeFrequencies'});
							}
							,scope: this
						}
					}
				})
			}),'-',this.bins, '-', this.typeSearch]
		});
		Voyeur.Tool.TypeFrequenciesChart.superclass.constructor.apply(this, arguments);
		
		// add exporter for image
		this.exporters.png = this.localize('exportPNG');
		this.exporters.svg = this.localize('exportSVG');
		
		this.addListener('resize', function() {
			if (this.chart) {
				var size = this.body.getSize();
				this.chart.setSize(size.width, size.height);
			}
		}, this)

		/**
		 * @event corpusTypeSelected
		 * @type listener
		 */
		this.addListener('corpusTypeSelected', function(src, data) {
			if (src && src.xtype==this.xtype) {return;}
			if (data.record) {
				this.handleTypeSelection([data.record],'corpus');
			} else {
				this.typeSearch.setValue(data.type);
				this.setApiParams({type: data.type, docIdType: null});
				var params = this.getApiParams();
				this.update({params : params, tool : this.getCorpus().getSize()>1 ? 'CorpusTypeFrequencies' : 'DocumentTypeFrequencies'});
			}
		});
		
		/**
		 * @event corpusTypesSelected
		 * @type listener
		 */
		this.addListener('corpusTypesSelected', function(src, data){
			if (data.record) {
				this.handleTypeSelection(data.record,'corpus');
			} else {
				this.setApiParams({type: data.type, docIdType: null});
				var params = this.getApiParams();
				this.update({params : params, tool : this.getCorpus().getSize()>1 ? 'CorpusTypeFrequencies' : 'DocumentTypeFrequencies'});
			}
		});
		
		/**
		 * @event documentTypeSelected
		 * @type listener
		 */
		this.addListener('documentTypeSelected', function(src, data){
			if (src && src.xtype==this.xtype) {return false;}
			if (data.record) {
				this.handleTypeSelection([data.record],'document');
			} else {
				this.setApiParams({docIdType: data.docIdType, type: null});
				this.update({params: this.getApiParams(), tool: 'DocumentTypeFrequencies'});
			}
		});
		
		/**
		 * @event documentTypesSelected
		 * @type listener
		 */
		this.addListener('documentTypesSelected', function(src, data){
			if (data.record) {
				this.handleTypeSelection(data.record,'document');
			} else {
				this.setApiParams({docIdType: data.docIdType, type: null});
				this.update({params: this.getApiParams(), tool: 'DocumentTypeFrequencies'});
			}
		});
		
		/**
		 * @event CorpusTypeFrequenciesResultLoaded
		 * @type listener
		 */
		this.addListener('CorpusTypeFrequenciesResultLoaded', function(src, data) {
			if (src==this) {
				this.handleTypeSelection(this.corpusTypeReader.readRecords(data).records,'corpus');
			}
		}, this);
		
		/**
		 * @event DocumentTypeFrequenciesResultLoaded
		 * @type listener
		 */
		this.addListener('DocumentTypeFrequenciesResultLoaded', function(src, data) {
			if (src==this) {
				this.handleTypeSelection(this.documentTypeReader.readRecords(data).records,'document');
			}
		}, this);
		
		/**
		 * @event CorpusSummaryResultLoaded
		 * @type listener
		 */
		this.addListener('CorpusSummaryResultLoaded', function(src, params) {
			var params = this.getApiParams();
			if (params.type) {
				delete params.limit;
			}
			this.update({params : params, tool : params.mode=='document' ? 'DocumentTypeFrequencies' : 'CorpusTypeFrequencies'});
		}, this);
		this.addListener('export', function(exp) {
			if (exp=='png') {
				this.chart.exportChart();
			}
			else if (exp=='svg') {
				this.chart.exportChart({
					type: 'image/svg+xml'
				});
			}
		}, this);
		
		this.addListener('resize', function() {
			if (this.chart) {
				var size = this.body.getSize();
		        this.chart.setSize(size.width, size.height);
		    }
		}, this);
	}
	
	,handleTypeSelection: function(records, mode) {
		if (this.rendered && !this.hidden && !this.collapsed && (this.ownerCt && !this.ownerCt.collapsed)) {
			
			// disable bins button if we're in corpus mode
			this.bins.setDisabled(mode=='corpus');
			
			// bail if we have no records
			if (records.length==0) {
				return;
			}
			
			var freqsMode = this.getApiParamValue('freqsMode')

			// check if we have the right number of bins for document frequencies
			if (mode=='document') {
				var bins = this.getApiParamValue('bins');
				var freqs = records[0].get(freqsMode+'Freqs');
				if (bins!=freqs.length) { // refetch
					this.update({params: this.getApiParams(), tool: 'DocumentTypeFrequencies'});
					return;
				}
			}
	
			var lastParams = {mode: mode, docIdType: null, type: null}
			
			var categories = [];
			if (mode=='document') {
				lastParams.docIdType = []
			}
			else {
				lastParams.type = [];
				categories = Voyeur.application.getCorpus().getShortLabels();
			}
			
			var freqsModeField = freqsMode+'Freqs';
			var series = [];
			for (var i=0;i<records.length;i++) {
				var record = records[i];
				var counts = record.get(freqsModeField);
				var type = record.get('type');
				var extras = {};
				if (mode=='document') {
					lastParams.docIdType.push(record.get('docId')+':'+type);
					extras.docId = record.get('docId');
				}
				else {
					lastParams.type.push(type);
				}
				series.push({
					name: type
					,data: record.get(freqsModeField)
					,extras: extras
				});
			}
			
			this.setApiParams(lastParams);
	
			var tool = this;
			this.chart = new Highcharts.Chart({
				chart: {
					renderTo: this.body.dom.id,
					defaultSeriesType: 'spline',
					margin: [50,20,70,60],
					zoomType: 'x'
				},
				title: {
					text: null
				},
				xAxis: {
					categories: categories
					,labels: {
						rotation: 315
						,align: 'right'
						,formatter: function() {
							if (mode=='document') {return this.value+1;}
							else if (this.value.length>10) {
								return this.value.substring(0,10)+'…'
							}
							else {return this.value}
						}
					}
				},
				yAxis: {
					title: {
						text: this.localize(freqsMode+'Frequencies')
					}
					,labels: {
						formatter: function() {
							return freqsMode=='relative' ? Ext.util.Format.number(this.value*10000,'0,000.0') : this.value;
						}
					}
					,min: 0
				},
				tooltip: {
					enabled: true,
					formatter: function() {
						if (mode=='corpus') {
							return '<b>'+ this.series.name +'</b>: <b>'+ (freqsMode == 'relative' ? Ext.util.Format.number(this.y*10000,'0,000.00')+'</b> '+tool.localize('per10kwords') : this.y+'</b>')+"<br/>"+
							tool.localize('in') + '<i>'+this.x+"</i>"
						}
						else {
							return '<b>'+ this.series.name +'</b>: <b>'+this.y+ '</b><br/>'+
								tool.localize('inSegment')+' #'+(this.x+1) +' '+tool.localize('of') + '<i>'+tool.getCorpus().getDocument(this.series.options.extras.docId).getShortLabel()+"</i>"
							
						}
					}
				},
				legend: {
					verticalAlign: 'top',
					symbolPadding: 3,
					borderRadius: 5,
					y: 10,
					symbolWidth: 10
				},
				plotOptions: {
					spline: {
						lineWidth: 1,
						marker: {
							radius: 4
						},
						cursor: 'pointer',
						point: {
							events: {
								click: function(event) {
									var type = this.series.name;
									var params = {};
									var docId;
									if (mode == 'document') { // set position
										docId = this.series.options.extras.docId;
										var totalTokens = tool.getCorpus().getDocument(docId).get('totalTokens') - 1;
										params.tokenIdStart = parseInt(this.category * totalTokens / this.series.data.length);
									} else {
										docId = tool.getCorpus().getDocument(event.point.x).getId();
									}
									params.docIdType = docId+':'+type;
									// NB only sending documentTypeSelected now, for use with ScatterPlot skin
									/**
									 * @event documentTypeSelected
									 * @param {Voyeur.Tool.TypeFrequenciesChart} tool
									 * @param {Object} params <ul>
									 * <li><b>docIdType</b> : String</li>
									 * <li><b>tokenIdStart</b> : Integer</li>
									 * </ul>
									 * @type dispatcher
									 */
									tool.getApplication().dispatchEvent('documentTypeSelected', tool, params);
								}
							}
						}
					}
				},
				series: series,
				credits: {enabled: false},
				exporting: {
					enabled: false // hide buttons
				}
				
			});
			
			if (mode=='corpus' && this.getCorpus().getSize()==1) {
				this.getApplication().growl(this.localize(mode=='corpus'  ? 'relativeFrequencies' : 'rawFrequencies'), this.localize('onlyOneDocumentInCorpus'), this.body);
			}
		}
	}

	,corpusTypeReader : new Ext.data.JsonReader({
			root : 'corpusTypes.types'
			,totalProperty : 'corpusTypes["@totalTypes"]'
		}, Ext.data.Record.create(Voyeur.data.CorpusTypes.fields)) 

	,documentTypeReader : new Ext.data.JsonReader({
			root : 'documentTypes.types'
			,totalProperty : 'documentTypes["@totalTypes"]'
		}, Ext.data.Record.create(Voyeur.data.DocumentTypes.fields))
	
	,api: {
		/**
		 * @property docIdType The document type(s) to restrict results to.
		 * @type String|Array
		 * @default null
		 */
		docIdType: {'default': null}
		/**
		 * @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 type The corpus type(s) to restrict results to.
		 * @type String|Array
		 * @default null
		 */
		,type: {'default': null}
		/**
    	 * @property mode What mode to operate at, either document or corpus.
    	 * @choices document, corpus
    	 */
		,mode: {'default': null}
		/**
		 * @property bins How many "bins" to separate a document into.
		 * @type Integer
		 * @default 50
		 */
		,bins: {'default': 10}
		/**
		 * @property limit The number of words to return in each call.
		 * @type Integer
		 * @default 50
		 */
		,limit: {'default': 5}
		,toolType: ['Visualization']
		,listeners: ['CorpusSummaryResultLoaded', 'CorpusTypeFrequenciesResultLoaded', 'DocumentTypeFrequenciesResultLoaded', 'corpusTypeSelected', 'corpusTypesSelected', 'documentTypeSelected', 'documentTypesSelected']
		,dispatchers: ['documentTypeSelected']
		
		/**
		 * @property freqsMode Determine if raw or relative frequencies are shown.
		 * @type String
		 * @default relative
		 */
		,freqsMode: {'default': 'relative'}
    }
	
	,thumb: {
		large: 'TypeFrequenciesChart.png'
	}

	,i18n : {
		title : {en: "Word Trends"}
	    ,type : {en : "Frequencies"}
	    ,relativeFrequencies : {en: 'Relative Frequencies'}
	    ,raw : {en: 'Raw'}
	    ,relative : {en: 'Relative'}
	    ,rawFrequencies : {en: 'Raw Frequencies'}
	    ,relfreq : {en: 'relative frequencies'}
	    ,rawfreq : {en: 'raw frequencies'}
	    ,'per10kwords' : {en: 'per 10,000 words'}
	    ,'in' : {en: 'in'}
	    ,'inSegment' : {en: 'in segment'}
	    ,'of' : {en: 'of'}
	    ,noResults: {en: 'No results to display.'}
		,help : {en: "This chart shows how terms are distributed across documents in a corpus (documents are shown in the order in which they were added)."}
		,corpusTitle : {en : 'Distribution of Types across Corpus'}
		,documentTitle: {en : 'Distribution of Types across Document'}
		,exportPNG: {en : 'a static PNG image in a new window'}
		,exportSVG: {en : 'a static SVG image in a new window'}
		,bins: {en: 'Segments'}
		,binsTip: {en: 'This option allows you to define how many segments should be represented in the graph (note that this option only applies to distribution within a document, not distribution across a corpus).'}
		,onlyOneDocumentInCorpus: {en: 'This tool shows distribution across documents in a corpus but you only have one document in this corpus.'}
	}
});

Ext.reg('voyeurTypeFrequenciesChart', Voyeur.Tool.TypeFrequenciesChart);

