Ext.namespace('Voyeur');

Ext.BLANK_IMAGE_URL = 'resources/lib/extjs/resources/images/default/s.gif';


/**
 * @class Voyeur.Application
 * @extends Ext.util.Observable
 * @param {Object} config configuration object
 * @constructor
 */
Voyeur.Application = Ext.extend(Ext.util.Observable, {
	constructor : function(config) {
		this.query = Ext.urlDecode(window.location.search.substring(1));
		this.version = config.version ? config.version : '1.0';
		this.build = config.build ? config.build : '?';
		this.setBaseUrl(document.location.protocol+'//'+document.location.host+document.location.pathname);
		this.corpus = new Voyeur.Corpus(this.query.corpus ? {'@id': this.query.corpus} : null);
		this.tools = new Ext.util.MixedCollection();
		Voyeur.Application.superclass.constructor.call(this, config);
		this.events = [];
		this.addListener('appReady', function(src, data) {
			// make sure to load corpus
			var query = Ext.urlDecode(window.location.search.substring(1));
			if (this.query.corpus || this.query.input) {
				if (query.input) {
					Ext.applyIf(query, {corpusCreateIfNotExists: true})
				}
				this.update({
					title : this.localize('app.loading')
					,params : query
					,tool : 'CorpusSummary'
				})
			}
			
		});
		
		this.addListener('resultLoaded', function(src, data) {
			if (data.corpus && data.corpus['@lastModified'] > this.corpus.get('lastModified')) {
				this.corpus = new Voyeur.Corpus(data.corpus)
				var id = this.corpus.getId();
				this.tools.each(function(tool) {
					tool.setApiParams({corpus: id});
				})
				/*
				var corpus = data.corpus;
				this.corpus = new Voyeur.Corpus({
					id: corpus['@id']
					,lastModified : corpus['@lastModified']
				});
				for (var i=0;i<corpus.documents.length;i++) {
					var doc = new Ext.util.MixedCollection();
					doc.addAll({
						index : parseInt(corpus.documents[i]['@index'])
						,id : corpus.documents[i]['@id']
						,title : corpus.documents[i]['@title']
						,author : corpus.documents[i]['@author']
						,timeInMillis : parseInt(corpus.documents[i]['@time'])
					})
					this.corpus.add(doc)
				}
				*/				
			}
		},this);

		this.addListener('toolLoaded', function(src, data) {
			this.tools.each(function(tool) {
				if (src.xtype==tool.xtype) {
					this.setApiParams({corpus: this.getCorpus().getId()});
				}
			})
		}, this)

	},
    init: function(){
        this.initTips();

		this.stopListsStore = new Ext.data.JsonStore({
			root : 'stopLists.lists',
			fields : ['id','label','description'],
			url: this.getTromboneUrl(),
			baseParams: {tool: 'StopLists'}
			,autoLoad: true
		}) 
		
		var fn = function(store) {
			store.removeListener('load', fn)
			store.loadData({corpora: {corpora: [
			                                    {id: 'humanist',label: 'Humanist Listserv Archives',description: ''}
			                                    ,{id: 'shakespeare',label: "Shakespeare's Plays (Moby)",description: ''}]}}, true)
		}
		
		this.corporaStore = new Ext.data.JsonStore({
			root : 'corpora.corpora'
			,fields : ['id','label','description']
			,url: this.getTromboneUrl()
			,baseParams: {tool: 'CorporaLister'}
			,autoLoad: true
			,listeners: {load: {fn: fn}}
		})

		var corpus = this.getQueryParam('corpus');
        this.initPage();
		this.dispatchEvent('appReady', this)
    },
    initTips: function(){
        Ext.QuickTips.init();
        // Apply a set of config properties to the singleton
        Ext.apply(Ext.QuickTips.getQuickTip(), {
            minWidth: 1000,
            dismissDelay: 0,
            qclass: 'qtip'
        });
        
    },
    
	/*
    initPage: function(){
        var params = window.location.search.split(/\?|&/);
		var query = {}
        if (params.length > 0) {
            for (var i = 0, length = params.length; i < length; i++) {
                var param = params[i].split('=');
                if (param[1] != null) {query[param[0]] = param[1];}
            }
        }
		
		// if a corpus has been specified, load it
		if (query.corpus) {
			this.corpus = new Voyeur.Corpus({id : query.corpus});
			this.corpusRetrievedHandler();
//			this.update({
//				title : this.localization.get('progress.initializing_corpus'),
//				tool : 'CorpusTool',
//				handler : this.corpusRetrievedHandler,
//				scope : this
//			});
		}        
    },*/
	
    /**
     * Initiates an Ajax call with progress bar.
     * @param {Object} args configuration options that may contain the following properties:<ul>
     * <li><b>progressWin</b> : Ext.ProgressBar<div class="sub-desc">(Optional) A {@link Ext.ProgressBar} to show progress (if no progressWin is specified, one will be created).</div></li>
     * <li><b>renderTo</b>: Mixed<div class="sub-desc">(Optional) A DOM id, DOM node or {@link Ext.Element} (same arguments as {@link Ext.get}. If this property is not provided then the document body will be used.</div></li>
     * <li><b>title</b>: String<div class="sub-desc">(Optional) The progress bar's title.</div></li>
     * <li><b>params</b>: Mixed<div class="sub-desc">(Optional) Parameters to be passed to the Ajax request, either as an object or as a URL encoded string (name=value&amp;name=value...)</div></li>
     * </ul>
     */
	update : function(args) {

		var progressWin = args.progressWin;
		if (!progressWin) {
			var renderTo = args && args.renderTo ? Ext.get(args.renderTo) : Ext.getBody();
			var wid = renderTo.getWidth(true)-40;
			wid = wid>600 ? 600 : wid;
			var progressBar = new Ext.ProgressBar({
				width: wid
			});
			progressWin = new Ext.Window({
	            title: args.title,
	            layout: 'fit',
	            autoWidth: true,
	            autoHeight: true,
	            closeAction: 'close',
	            modal: true,
	            plain: true,
				renderTo : args && args.renderTo ? args.renderTo : document.body,
	            items: [progressBar]
	            ,listeners: {
					beforedestroy: {
						fn: function(win) {
							// IE isn't happy unless the bar is reset
							var bar = win.items.get(0).reset();
						}
					}
				}
        	});
			progressWin.show();
			progressBar.wait({
				interval : 200,
				text: this.localize('app.loading')
			});
		}

		if (!args.params) {args.params = {};}
		if (typeof args.params == 'string') {
			args.params = Ext.urlDecode(args.params);
		}
		args.params.tool = args.tool;

		if (!args.params.corpus && !this.getCorpus().isEmpty()) {args.params.corpus=this.getCorpus().getId();}
		Ext.Ajax.request({
			url : this.getBaseUrl()+"trombone/",
			method : 'post',
			params : args.params,
			form : args.form,
			callback : function(options,success,response) {
				var msg = response.statusText;
				if (success) {
					var r = Ext.util.JSON.decode(response.responseText);
					if (r.error) {
						msg = Voyeur.localization.get(r.code ? r.code : r.error);
						if (msg==r.code) {msg=r.error;}
					}
					else {
						if (r.message) {
							msg = Voyeur.localization.get(r.code ? r.code : r.message);
							if (msg==r.code) {msg=r.message;}
							progressWin.items.get(0).updateText(msg);
						}
						else if (r.result) {
							progressWin.items.get(0).updateText(this.localize('app.retrieving'))
						}
						if (r.process || r.result) {
				            var me = this;
				            setTimeout(function(){
				                me.update({
									params : r,
									progressWin : progressWin,
									handler : args.handler,
									scope : args.scope,
									tool: args.tool,
									title : args.title,
									event : args.event
								})
				            }, 500);
						}
						else {
							progressWin.destroy();
							if (typeof args.tool == "string") {args.tool = [args.tool]}
							for (var i=0;i<args.tool.length;i++) {
								this.dispatchEvent(args.event ? args.event : args.tool[i] + 'ResultLoaded', this, r);
							}	
						}
						return;
					}
				}
				else {
					msg += response.responseText;
				}
				
				progressWin.destroy();
				Ext.Msg.show({
					title : this.localize('app.error'),
					msg : msg,
					buttons : Ext.Msg.OK,
					icon : Ext.Msg.ERROR
				});
			},
			scope : this
		});
	},
	
	getCorpus : function() {return this.corpus;},
	
	addTool : function(tool) {
		this.tools.add(tool.id, tool);
		this.dispatchEvent('toolLoaded', tool, tool);
	},
	
	dispatchEvent : function () {
		var ev = arguments[0];
		var args = arguments;
		if (window.console && console.info) {console.info(arguments[0],arguments[1],arguments);}
		if (ev.indexOf("ResultLoaded")>0) {this.fireEvent('resultLoaded', arguments[1], arguments[2])}
		this.fireEvent.apply(this,arguments);
		var hasListener = false;
		var evLower = ev.toLowerCase();
		this.tools.each(function(tool) {
			if (tool != args[1] && !tool.disabled && tool.hasListener(evLower)) {
				tool.fireEvent.apply(tool, args);
				hasListener=true;
			}
		});
		if (!hasListener && ev!='toolLoaded' && ev!='appReady' && ev!='unhandledEvent') {
			if (window.console && console.info) {console.info('Unhandled event: ', arguments[0],arguments[1],arguments);}
			args = ['unhandledevent', arguments[1]];
			for (var i=0;i<arguments.length;i++) {args.push(arguments[i])}
			this.fireEvent.apply(this, args);
		}
			
	},

	
	/**
	 * The following two methods are called from Mandala when the user
	 * drags a dot outside the confines of the Mandala workspace to show
	 * that the cursor is holding a Mandala dot and may drop it on to another
	 * tool for some purpose.
	 */
	changeCursorToDrag : function() {
		document.body.style.cursor = 'crosshair';
	},
	
	changeCursorToDefault : function() {
		document.body.style.cursor = 'default';
	},
		
    growl : function(title, msg, renderTo) {
		renderTo = renderTo ? renderTo : document.body;
        var msgCt;
    
        function createBox(t, s){
            return ['<div class="msg">',
                    '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
                    '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc"><h3>', t, '</h3>', s, '</div></div></div>',
                    '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
                    '</div>'].join('');
        }
        
        if(!msgCt){
            msgCt = Ext.DomHelper.append(renderTo, {id:'msg-div'}, true);
        }
        msgCt.alignTo(renderTo, 'c-c', [-10,-10]);        /*<-- pos in bottom-right corner*/
        var msg = String.format.apply(String, Array.prototype.slice.call(arguments, 1));
        var m = Ext.DomHelper.append(msgCt, {html:createBox(title, msg)}, true);
        m.slideIn('b').pause(2).ghost("b", {remove:true});  /*<--move from bottom*/
    },
	createBox : function(t, s){
        return ['<div class="msg">',
                '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
                '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc"><h3>', t, '</h3>', s, '</div></div></div>',
                '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
                '</div>'].join('');
    }
	
	,localize : function(key) {return Voyeur.localization.get(key)}
	,loadLocalization : function(loc, prefix) {
		if (prefix) {
			var prefixedLocalization = {}
			for (key in loc) {
				prefixedLocalization[prefix+key] = loc[key]
			}
			this.getLocalization().load(prefixedLocalization);
		}
		else {this.getLocalization().load(loc);}
	}
	,getLocalization : function() {return Voyeur.localization;}
	
	,setBaseUrl : function(baseUrl) {
		this.baseUrl=baseUrl;
		Ext.BLANK_IMAGE_URL = this.baseUrl + 'resources/lib/extjs/resources/images/default/s.gif';
	}
	,getBaseUrl : function() {return this.baseUrl;}
	,getTromboneUrl : function() {return this.getBaseUrl()+"trombone";}
	,getVersion : function() {return this.version;}
	,getBuild : function() {return this.build;}
	,getStopListsStore : function() {return this.stopListsStore;}
	,getCorporaStore : function() {return this.corporaStore;}
	,getQueryParam: function(name) {return this.query[name];}
	

});

Voyeur.localization.load({
	'app.title' : {en : 'Voyeur'}
	,'app.colon' : {en : ': '}
	,'app.loading' : {en : 'Loading'}
	,'app.error' : {en : 'Error'}
	,'app.information' : {en : 'Information'}
	,'app.retrieving' : {en : 'Retrieving Results'}
})

