Ext.namespace("Ext.ux");

ServiceDefs = function() {
	this.tree_base_url = 'http://repository.library.northwestern.edu/fedora/get/inu:inu-ead-afri-wc00/inu:sdef-ead/getComponentChildrenAsJSON?';
	this.solr_url = 'http://repository.library.northwestern.edu/winterton-solr/select?';
	this.metadata_base_url= 'http://repository.library.northwestern.edu/fedora/get/inu:inu-ead-afri-wc00/inu:sdef-ead/getComponentAsEmbeddedHTML?pid_prefix=inu-wint-&unitid=';
	this.fedora_base_url= 'http://repository.library.northwestern.edu/fedora/get/';
}

ServiceDefs.prototype.tree_base_url;
ServiceDefs.prototype.solr_url;
ServiceDefs.prototype.metadata_base_url;
ServiceDefs.prototype.fedora_base_url;
/**
 * 
 * @author Bill Parod
 */

/** 
 * @name Ext.ux
 * @namespace The Ext.ux namespace is for extensions to Ext.
 */

/**
 */

// Apply custom namespace
Ext.namespace('Ext.ux');

Ext.ux.HistoryManager = function(config) {
	Ext.ux.HistoryManager.superclass.constructor.call(this, config);
	this.solr=config.solr;
	this.lastEvent='';
	this.addEvents('replaySearch');
	this.addEvents('newItem');
	
	Ext.History.on('change', function(token){
		var tokenDelimiter = '|';
		var dtoken = decodeURIComponent(token);

		if(dtoken != this.lastEvent){
	
			var parts = dtoken.split(tokenDelimiter);
			var tokens = new Object();
			for(i=0;i< parts.length;i++) {
				var wa = parts[i].split('\\t');
				var key = wa[0];
				var value = wa[1];
				tokens[key]=value;
			}
	
			if(tokens['action'] == 'newSearch') {
				this.solr.replayQuery(tokens);
			} else if(tokens['action']=='getAllPhotos') {
					this.solr.getAllPhotos();
			} else if(tokens['action']=='newItem') {
				this.fireEvent('newItem',{id:tokens['item'],offset:tokens['offset'],item_type:tokens['item_type'],event_type:'new'});
			} else if(tokens['action']=='selectItem') {
					this.fireEvent('newItem',{id:tokens['item'],offset:tokens['offset'],item_type:tokens['item_type'],event_type:'select'});
			}
	
		}
	}, this);

} // end of constructor

Ext.extend(Ext.ux.HistoryManager, Ext.util.Observable, {

	noteHistory: function(token) {

		this.lastEvent=token;
		Ext.History.add(token);
	}

}); // end of extend
Ext.namespace("Ext.ux");

Facet = function(name, label) {
	this.name = name;
	this.label = label;
	this.store = new Ext.data.SimpleStore({
        fields: ['id','field_name', 'field_key', 'field_value', 'facet_count', 'facet_style'],
        id: id,
        storeId: this.name
    });
}

Facet.prototype.name;
Facet.prototype.label;
Facet.prototype.store;
var FacetRecordDef = Ext.data.Record.create([
	{name:'id'},
	{name:'field_name'},
	{name:'field_key'},
	{name:'field_value'},
	{name:'item_label'},
	{name:'facet_count'}
], id);
var SolrMODSRecordDef = Ext.data.Record.create([
	{name:'id'},
	{name:'title'},
	{name:'shortTitle'},
	{name:'thumb_url'},
	{name:'full_url'},
	{name:'url'},
	{name:'item_type'},
	{name:'item_label'}
], id);

//]);

/*
var SolrMODSRecordDef = Ext.data.Record.create([
	{name:'collection_name'},
	{name:'collection_id'},
	{name:'full_url'},
	{name:'id'},
	{name:'name'},
	{name:'note'},
	{name:'physical_description'},
	{name:'source'},
	{name:'text'},
	{name:'thumb_url'},
	{name:'title'},
	{name:'type'},
	{name:'url'}
	*/
var SolrDocRecordDef = Ext.data.Record.create([
	{name:'id', name:'thumb'}
], id);

/**
 * 
 * @author Bill Parod
 */

/** 
 * @name Ext.ux
 * @namespace The Ext.ux namespace is for extensions to Ext.
 */
Ext.namespace("Ext.ux");

/**
 * @class A custom JSON reader that handles results from a SOLR query.
 * @see The <a href="http://lucene.apache.org/solr/">SOLR</a> page.
 * @see <a href="http://extjs.com/deploy/ext-2.0/docs/?class=Ext.data.JsonReader">Ext.data.JsonReader</a>
 * @extends Ext.data.JsonReader
 * @param {Object} meta Metadata configuration options.
 * @param {Array|Function} Either an Array of field definition objects as passed to Ext.data.Record.create, or a Record constructor created using Ext.data.Record.create.
 */
Ext.ux.SolrDocReader = function(meta, recordType){
    meta = meta || {};
    Ext.ux.SolrDocReader.superclass.constructor.call(this, meta);
};



Ext.extend(Ext.ux.SolrDocReader, Ext.data.JsonReader, {

    /**
     * Converts the JSON data to Ext.data.Records.
     * @param {Object} o The JSON data.
     * @returns {Object} The return object contains a success property, the total number records, and the records themselves.
     */

   readRecords : function(o){
        /**
         * After any data loads, the raw JSON data is available for further custom processing.  If no data is
         * loaded or there is a load exception this property will be undefined.
         * @property jsonData
         * @type Object
         */

		
		this.jsonData = o;
        var s = this.meta, Record = this.recordType;

		var success = true;
        
		var totalFacets = 0;
		var totalRecords = 0;
		var records = [];
		var data = [];

		var totalDocs = 0;
		var docs = [];
		var doc = {};

		var doc_count=o['response'].docs.length;
		for( i=0;i < doc_count;i++) {
			doc=o['response'].docs[i];
			var id = (doc.id!='undefined') ? doc.id : '**********UNDEFINED***********';

            var values = {};
			values['id']=id;
			docs[i] = new SolrDocRecordDef(values, id);
		}

        return {
            success : success,
            records : docs,
        //    totalRecords : o['response'].numFound
            totalRecords : doc_count
        };
    } 

});
/**
 * 
 * @author Bill Parod
 */

/** 
 * @name Ext.ux
 * @namespace The Ext.ux namespace is for extensions to Ext.
 */
Ext.namespace("Ext.ux");

/**
 * @class A custom JSON reader that handles results from a SOLR query.
 * @see The <a href="http://lucene.apache.org/solr/">SOLR</a> page.
 * @see <a href="http://extjs.com/deploy/ext-2.0/docs/?class=Ext.data.JsonReader">Ext.data.JsonReader</a>
 * @extends Ext.data.JsonReader
 * @param {Object} meta Metadata configuration options.
 * @param {Array|Function} Either an Array of field definition objects as passed to Ext.data.Record.create, or a Record constructor created using Ext.data.Record.create.
 */
Ext.ux.SolrFacetReader = function(meta, recordType){
    meta = meta || {};
    Ext.ux.SolrFacetReader.superclass.constructor.call(this, meta);
};



Ext.extend(Ext.ux.SolrFacetReader, Ext.data.JsonReader, {

    /**
     * Converts the JSON data to Ext.data.Records.
     * @param {Object} o The JSON data.
     * @returns {Object} The return object contains a success property, the total number records, and the records themselves.
     */

	getQuantizedCount: function (params){   
		var min_font=7;
		var max_font=20;
		var weight = (Math.log(params.count) - Math.log(params.mincount)) / (Math.log(params.maxcount) - Math.log(params.mincount));   
		var fontSize = min_font + Math.round((max_font - min_font) * weight);   
		return fontSize + "pt";   
	} ,
   readRecords : function(o){
        /**
         * After any data loads, the raw JSON data is available for further custom processing.  If no data is
         * loaded or there is a load exception this property will be undefined.
         * @property jsonData
         * @type Object
         */

		this.jsonData = o;
        var s = this.meta, Record = this.recordType;
        
		var totalFacets = 0;
		var totalRecords = 0;
		var records = [];
		var data = [];
		
		if(o['facet_counts']!=undefined) {
			var min_count=1;
			var max_count=1;

			for (property in o['facet_counts'].facet_fields) {
				var record_index=0;
				var data_index=0;
				records=[]
				data=[]
				var success = true;
				var stripe = false; // used to visually group items with same count
				
				var recordCount = o['facet_counts'].facet_fields[property].length / 2;
		
				for( i=0;i < recordCount;i++) {
				
					var field_index= i * 2;
					var value = o['facet_counts'].facet_fields[property][field_index].replace(/_/gi,' ');
					var count = o['facet_counts'].facet_fields[property][field_index+1];
					if(count < min_count) {min_count=count;}
					if(count > max_count) {max_count=count;}
					
					// For key from combining the facet name with the facet value
					var id = property + '-' + value;
					data[data_index++] = [id, property, id, value, count];
				}
				totalRecords += recordCount;
				
				// KLUDGE HERE - ABSTRACT OUT
				if(property.match(/keyword/)) {
					for (f=0; f <  data.length; f++) {
						var cc = data[f][4];
						var cloud_font = this.getQuantizedCount({count:cc, mincount:min_count, maxcount:max_count});
						data[f][5]=cloud_font;
					}
				} else {
					for (f=0; f <  data.length; f++) {
						data[f][5] = (f != 0 && data[f][4]!=data[f-1][4]) ? true : false;
					}
				}
				var currentFacet = this.meta.facets[property];
				if(currentFacet != null) {
					currentFacet.store.loadData(data,false);
				}
			}
		}

		var totalDocs = 0;
		var docs = [];
		var doc = {};

		var doc_count=o['response'].docs.length;
		for( i=0;i < doc_count;i++) {
			doc=o['response'].docs[i];
//			var collection_name = (doc.collection_t!='undefined') ? doc.collection_t : '**********UNDEFINED***********';
//			var collection_id = (doc.collectionid_t!='undefined') ? doc.collectionid_t : '**********UNDEFINED***********';
			var full_url = (doc.fullurl_t!='undefined') ? doc.fullurl_t : '**********UNDEFINED***********';
			var id = (doc.id!='undefined') ? doc.id : '**********UNDEFINED***********';
//			var name = (doc.name_t!='undefined') ? doc.name_t : '**********UNDEFINED***********';
//			var note = (doc.note_t!='undefined') ? doc.note_t : '**********UNDEFINED***********';
//			var physical_description = (doc.physical_description_t!='undefined') ? doc.physical_description_t : '**********UNDEFINED***********';
//			var source = (doc.source_t!='undefined') ? doc.source_t : '**********UNDEFINED***********';
//			var text = (doc.text_t!='undefined') ? doc.text_t : '**********UNDEFINED***********';
			var thumb_url = (doc.thumburl_t!='undefined') ? doc.thumburl_t : '**********UNDEFINED***********';
			var item_type = (doc.item_type!='undefined') ? doc.item_type : 'item';
			var item_label = (doc.label_t!='undefined' &&  doc.label_t!='') ? doc.label_t : 'item';
			var title = (doc.title_t!=undefined) ? doc.title_t : doc.alt_title_t;
//			var shortTitle = Ext.util.Format.substr(title, 0, 25) == title ? title : Ext.util.Format.substr(title, 0, 25) + '...';
//			var type = (doc.type_of_resource_t!='undefined') ? doc.type_of_resource_t : '**********UNDEFINED***********';
			var url = (doc.url_t!='undefined') ? doc.url_t : '**********UNDEFINED***********';

            var values = {};
			values['id']=id;
			values['title']=title;
//			values['shortTitle']=Ext.util.Format.substr(title, 0, 24) + '...';
			values['shortTitle']=Ext.util.Format.substr(title, 0, 23) == title ? title : Ext.util.Format.substr(title, 0, 23) + '...';
			values['thumb_url']=thumb_url;
			values['full_url']=full_url;
			values['url']=url;
			values['item_type']=item_type;
			values['item_label']=item_label; 
			docs[i] = new SolrMODSRecordDef(values);
		}

        return {
            success : success,
            records : docs,
            totalRecords : o['response'].numFound
//            totalRecords : totalDocs
        };
    } 

});
/**
 * 
 * @author Bill Parod
 */

/** 
 * @name Ext.ux
 * @namespace The Ext.ux namespace is for extensions to Ext.
 */

/**
 */

// Apply custom namespace
Ext.namespace('Ext.ux');

	function displayConstraints(params) {

		for(var i=0;i< params.store.getCount();i++) {
			var id=params.store.getAt(i).data.id;
			var key=params.store.getAt(i).data.field_key;
			var value=params.store.getAt(i).data.field_value;
			var name=params.store.getAt(i).data.field_name;
		}
	}



Ext.ux.Solr = function(config) {/* This is for solr searching */								

	Ext.ux.Solr.superclass.constructor.call(this, config);

<!-- ****************************************************** -->
<!-- Initialization											-->
<!-- ****************************************************** -->

	var self = this;
	var tokenDelimiter = '|';
	var pageSize = '50';


	// We fire this event on in 'reload' when a new search is performed
	this.addEvents('newSearch');
	this.addEvents('noteHistory');

	// The base URL for this Solr instance
	this.solr_url=config.solr_url;

	// The facet parameters are handcoded here. They will be added in parsing a datastream on the Searchable object
	this.solr_facet_url=this.solr_url + 'wt=json&version=2.2&sort=sortkey_i+asc&facet.field=decade_facet&facet.field=people_facet&facet.field=place_facet&facet.field=subject_facet&facet.field=keyword_facet&f.keyword_facet.facet.sort=false&facet=true&facet.limit=4000&facet.mincount=1&';
	this.query='q=winterton';

	// Define simple data store to keep the Facet objects for this Solr instance
	this.facets = new Object;
	this.getFacets = function() {
		return this.facets;
	}

	// These are handcoded here. They will be loaded from a datastream on the Searchable object
	this.facets['keyword_facet'] = new Facet('keyword_facet','Keywords');
	this.facets['subject_facet'] = new Facet('subject_facet','Subjects');
	this.facets['people_facet'] = new Facet('people_facet','People');
	this.facets['place_facet'] = new Facet('place_facet','Places');
	this.facets['decade_facet'] = new Facet('decade_facet','Decades');

<!-- Set up reader and store for main query operations -->

	var conn = new Ext.data.Connection({
 		url:this.solr_facet_url + this.query,
		method: 'GET'
	});

	var reader = new Ext.ux.SolrFacetReader({
		fields: ['id','title','shortTitle','thumb_url','full_url', 'url', 'item_type', 'item_label'],
		facets:this.facets
	}, SolrMODSRecordDef);

	this.store = new Ext.data.Store({
		proxy: new Ext.data.HttpProxy(conn),
		reader: reader,
		listeners: {
			datachanged: {
				fn: function(s) {
					this.start=s.lastOptions.params.start;
				}, scope: this
			}
		}
	});


<!-- Set up in memory reader and store for facet choices. This holds the main search constraints and exposses them in the DataView in the search panel.  -->

	var facetReader = new Ext.data.ArrayReader({id: 0}, FacetRecordDef);
	this.searchConstraintStore = new Ext.data.Store({reader:facetReader});
	this.searchConstraintStore.addListener('datachanged', displayConstraints, this.searchConstraintStore, {store:this.searchConstraintStore, msg:'datachanged'});


<!-- ****************************************************** -->
<!-- Search state management functions						-->
<!-- ****************************************************** -->

	// Clear out all constraints
	this.clear = function () {
		this.searchConstraintStore.removeAll();
	}

	// Clear out all constraints and reload
	this.reset = function () {
		this.clear();
		this.reload({});
	}

	// Clear out the full text search constraint
	this.resetText = function () {
		var text_index = this.searchConstraintStore.find('id','text');
		if(text_index != -1) {
			this.searchConstraintStore.remove(this.searchConstraintStore.getAt(text_index));
			self.reload({});
		}
	}


<!-- ****************************************************** -->
<!-- Search Functions										-->
<!-- ****************************************************** -->

	// This function excutes a new search, gathering search constraint state and forming a new search url. 
	this.reload = function (params) {
		var qparams='';		

//		displayConstraints({store:this.searchConstraintStore, msg:'reload start'}) ;// Debug

//		this.searchConstraintStore.suspendEvents();

		for(param in params) {
			var field_id = '';
			if(param == 'text') {	// allow only one text constraint
				field_id='text';
			} else if(param == 'isPartOf') { // allow only one isPartOf constraint
				field_id='isPartOf';
			} else {
				field_id=param + '-' + params[param];
			}

			var	field_key=param + '-' + params[param];

			var item_index = this.searchConstraintStore.find('id',field_id);
			if(item_index != -1) {
				this.searchConstraintStore.remove(this.searchConstraintStore.getAt(item_index));
			}
			
			if(params[param] != '') { // text  is empty if user clears form
				this.searchConstraintStore.add(new FacetRecordDef({id:field_id, field_name:param, field_key:field_key, field_value:params[param], item_label:params['item_label']}));
			}
		}

		for(i=0;i< this.searchConstraintStore.getCount();i++) {
		
			if(qparams !='') {qparams=qparams + ' AND ';}
			var field_value=this.searchConstraintStore.getAt(i).data.field_value;
			var field_name=this.searchConstraintStore.getAt(i).data.field_name;

			if(field_name=='isPartOf') {
				qparams = qparams + field_name + ':' + field_value;
			} else if(field_name=='subject_t') {
				qparams = qparams + field_name + ':' + field_value.replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\\'/g,'\\\'').replace(/-/g,'\\-').replace(/:/g,'\:').replace(/\:/g,'\\:');
			} else {
//				qparams = qparams + this.searchConstraintStore.getAt(i).data.field_name + ':' + escape(field_value.replace(/ /g,'_').replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\\'/g,'\\\'').replace(/-/g,'\\-'));
				var v = field_value.replace(/ /g,'_').replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\\'/g,'\\\'').replace(/-/g,'\\-').replace(/\:/g,'\\:');
				qparams = qparams + field_name + ':' + v;
			}
		}
		
		if(qparams=='') 
			{
			this.getAllPhotos();
		} else {
			conn.url=this.solr_facet_url + 'q=' + encodeURIComponent(qparams);
			// Save state for History for backbutton 
			var qConstraints = new Object();
			for(i=0;i< this.searchConstraintStore.getCount();i++) {
				qConstraints[this.searchConstraintStore.getAt(i).data.id] = this.searchConstraintStore.getAt(i).data.field_key;
			}
			
			var historyItem = 'action\\tnewSearch' 
					+ tokenDelimiter + 'query\\t' + qparams
					+ tokenDelimiter + 'start\\t0' 
					+ tokenDelimiter + 'rows\\t' + pageSize
					+ tokenDelimiter + 'searchConstraintStore\\t' + Ext.util.JSON.encode(qConstraints);

			if(!this.store.load({params:{start:0,rows:50}})) {
			}
			self.fireEvent('noteHistory', historyItem);
			self.fireEvent('newSearch');
		}
	}

	
	// replay requested query
	// This function is here to 'replay' previous searches in response to browser back/forward button History requests
	this.replayQuery = function (params) {
		this.clear();

		var query=params['query'];
		var start=params['start'];
		var rows=params['rows'];
		
		// Re init search constraint store
		var constraints = Ext.util.JSON.decode(params['searchConstraintStore']);
		for(c in constraints) {
			if(this.searchConstraintStore.find('id',c) == -1) {
				var field_name=constraints[c].split('-')[0];
				var field_value=constraints[c].substring(constraints[c].indexOf('-')+1);
				this.searchConstraintStore.add(new FacetRecordDef({id:c, field_name:field_name, field_key:constraints[c], field_value:field_value}));
			}
		}

//		conn.url=this.solr_facet_url + '&q='+query;
		conn.url=this.solr_facet_url + 'q=' + encodeURIComponent(query);

		if(!this.store.load({params:{start:start,rows:rows}})) {
		}
		self.fireEvent('newSearch');
	}


	// Perform requested query

	this.performSimpleQuery = function (params) {
		this.clear();

		var query = '';
		var qFacets = new Object();

		for (param in params) {
			if(query !='') {query=query + ' AND ';}
		//	query += param + ':' + escape(params[param].replace(/ /g,'_').replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\\'/g,'\\\'').replace(/-/g,'\\-'));
		//	query += param + ':' + escape(params[param].replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\\'/g,'\\\'').replace(/-/g,'\\-'));


//			query += param + ':' + params[param].replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\\'/g,'\\\'').replace(/-/g,'\\-').replace(/\:/g,'\\:');
			query += param + ':' + params[param].replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\\'/g,'\\\'');
			
			// WARNING : Need code for text/isPartOf which don't use this method currently, but should be able to
			var field_key=param + '-' + params[param];
			var field_id='';
			if(param == 'text') {	// allow only one text constraint
				field_id='text';
			} else if(param == 'isPartOf') { // allow only one isPartOf constraint
				field_id='isPartOf';
			} else {
				field_id=param + '-' + params[param];
			}

			qFacets[field_id]=field_key;
						
			this.searchConstraintStore.add(new FacetRecordDef({id:field_id, field_name:param, field_key:field_key, field_value:params[param]}));
		}

		var historyItem = 'action\\tnewSearch' 
				+ tokenDelimiter + 'query\\t' + query
				+ tokenDelimiter + 'start\\t0' 
				+ tokenDelimiter + 'rows\\t' + pageSize
				+ tokenDelimiter + 'searchConstraintStore\\t' + Ext.util.JSON.encode(qFacets);

		self.fireEvent('noteHistory', historyItem);

		
//		conn.url=this.solr_facet_url + '&q='+query;
		conn.url=this.solr_facet_url + 'q=' + encodeURIComponent(query);
		if(!this.store.load({params:{start:0,rows:50}})) {
		//	alert('TROUBLE:' + conn.url);
		}
		self.fireEvent('newSearch');

	}
	
	// This responds to an thumbnail selection within a container. It doesn't execute a new search, but focuses the store on that single item. This allows the user to step through the store, item by item.
	this.selectItem = function (params) {
		this.updateFacets(params);
		var index = this.start + this.store.find('id', params['id']);
		var historyItem = 'action\\tselectItem' + tokenDelimiter + 'item\\t' + params.id + tokenDelimiter + 'offset\\t' + index;
		self.fireEvent('noteHistory', historyItem);
		this.store.load({params:{start:index,rows:1}});
	}

	// This perfors a facet search for the requested item. This causes the facet panels to update. This is useful when stepping through a store, item but item.
	this.updateFacets = function (params) {
		this.clear();
		
		// Get facets for this item
		var field_key='isPartOf-' + params['id'];
		this.searchConstraintStore.add(new FacetRecordDef({id:'isPartOf', field_name:'isPartOf', field_key:field_key, field_value:params['id'], item_label:params['item_label']}));

		var itemReader = new Ext.ux.SolrFacetReader({
			fields: ['id','title','shortTitle','thumb_url','full_url', 'url', 'item_type', 'item_label'],
			facets:this.facets
		}, SolrMODSRecordDef);
	
		var furl = this.solr_facet_url + 'q=' + 'isPartOf:' + params['id'];
		var itemStore = new Ext.data.Store({
			url:furl,
			reader: itemReader//,
		});
		itemStore.load({params:{start:0,rows:0}});
		
		
	}


	// This is the initial query which show all photos in the collection. It performs separate facet and item searches so that the facets represent the entire collection, but only photo items are shown in the thumbnail panel
	this.getAllPhotos = function () {
		this.clear();

		self.fireEvent('noteHistory', 'action\\tgetAllPhotos');
		
		var itemReader = new Ext.ux.SolrFacetReader({
			fields: ['id','title','shortTitle','thumb_url','full_url', 'url', 'item_type', 'item_label'],
			facets:this.facets
		}, SolrMODSRecordDef);
	

		// Since we're asking for everything here, throttle back the keyword counts
		var furl = this.solr_facet_url + 'f.keyword_facet.facet.limit=4500&f.keyword_facet.facet.mincount=5&q=winterton';
		var itemStore = new Ext.data.Store({
			url:furl,
			reader: itemReader//,
		});
		itemStore.load({params:{start:0,rows:0}});
		
		var turl=this.solr_url + 'wt=json&sort=sortkey_i+asc&version=2.2&q=item_type:photo';

		conn.url=turl;
		this.store.load({params:{start:0,rows:50}});


		self.fireEvent('newSearch');
	}

this.getItem = function (params) {
		this.clear();
		
		// Get facets for this item
		var field_key='isPartOf-' + params['id'];
		this.searchConstraintStore.add(new FacetRecordDef({id:'isPartOf', field_name:'isPartOf', field_key:field_key, field_value:params['id'], item_label:params['item_label']}));

		var itemReader = new Ext.ux.SolrFacetReader({
			fields: ['id','title','shortTitle','thumb_url','full_url', 'url', 'item_type', 'item_label'],
			facets:this.facets
		}, SolrMODSRecordDef);

		var furl = this.solr_facet_url + 'q=' + 'isPartOf:' + params['id'];
		var itemStore = new Ext.data.Store({
			url:furl,
			reader: itemReader//,
		});
		itemStore.load({params:{start:0,rows:0}});
		
		var turl=this.solr_url + 'wt=json&sort=sortkey_i+asc&version=2.2&q=isPartOf:' + params['id'] + ' AND item_type:photo';
		conn.url=turl;

		var historyItem = 'action\\tnewItem' + tokenDelimiter + 'item\\t' + params.id;
		self.fireEvent('noteHistory', historyItem);
		this.store.load({params:{start:0,rows:50}});
}


<!-- ****************************************************** -->
<!-- Event handlers											-->
<!-- ****************************************************** -->

// These are here to respond to events fired by other objects

	this.newItem = function (params) {

		if(params.event_type == 'select') {
			this.selectItem(params);
		} else {
			this.getItem(params);
		}
	}
	
	this.textChanged = function (params) {
		this.clear();
		this.reload({text:params.text});
	}
	
	this.onfacetChanged = function (a) {
		var sel_len = a.length;
		for ( var i = 0; i< sel_len;i++) {
			if(self.searchConstraintStore.find('id', a[i].data.id) == -1) {
				self.searchConstraintStore.add(a[i]);
			}
		}
		self.reload({});
	}

	this.searchRequest = function (params) {
		var parmObj = new Object();
		parmObj[params.desc_type]=params.desc_value;
		self.performSimpleQuery(parmObj);
	}
	
	this.removeFacetConstraint = function (field_id) {
		var facet_index = this.searchConstraintStore.find('id',field_id);
		if(facet_index != -1) {
			this.searchConstraintStore.remove(this.searchConstraintStore.getAt(facet_index));
			self.reload({});
		}
	}

} // end of constructor

Ext.extend(Ext.ux.Solr, Ext.util.Observable, {}); // end of extend
/*
 *******************************************************************************
 * CLASS
 * FacetPanel
 * 
 * PURPOSE
 * To format contact details of a data object
 *******************************************************************************
 */

// Apply custom namespace
Ext.namespace('Ext.ux');


Ext.ux.FacetPanel = Ext.extend(Ext.Panel,{
	facet: '',
	collapsible:true,
	collapsed:true,
	title:'No Title',
	autoScroll:false,
	autoHeight:true,
//	onRender: function(ct, position) {
//		Ext.ux.FacetPanel.superclass.onRender.call(this, ct, position);
//	},
	initComponent: function(){
		var self = this;
		Ext.ux.FacetPanel.superclass.initComponent.call(this);
		if (typeof this.facet === 'object') {
			this.name=this.facet.name;
			this.label=this.facet.label;
			this.store=this.facet.store;

			this.title=this.label;
		//	this.renderTo=this.name;
			this.addEvents('facetChange');

			this.add(new Ext.DataView({
				store: this.store,
				tpl: new Ext.XTemplate('<tpl for=".">',
				'<tpl if="facet_style">',
					'<div class="facet_item"><div class="facet_item_stripe"><span class="facet_item_value">{field_value}</span> <span class="facet_item_count">{facet_count}</span></div></div>',
				'</tpl>',
				'<tpl if="!facet_style">',
					'<div class="facet_item"><span class="facet_item_value">{field_value}</span> <span class="facet_item_count">{facet_count}</span></div>',
				'</tpl>',
				'</tpl>'),
				autoScroll:true,
				autoHeight:true,
				multiSelect: true,
				cls:'facet_item',
				baseCls:'facet_item',
				overClass:'facet_item-over',
				selectedClass:'facet_item-selected',
				itemSelector:'div.facet_item',
				loadingText: 'Loading...',
				emptyText: 'None',
				border:false,
				onClick: function(e) {
					var item = e.getTarget(this.itemSelector, this.el);
					if(item){
						var index = this.indexOf(item);
						if(this.onItemClick(item, index, e) !== false){
							this.fireEvent("click", this, index, item, e);
						} 
					} /*else{
						if(this.fireEvent("containerclick", this, e) !== false){
							this.clearSelections();
						}
					} */
					self.fireEvent('facetChange', this.getSelectedRecords());
				}, 
				listeners: {
					render: initializeFacetDragZone //,
					//'click': selectFacet
					}
				//}
			}));
		}
	}
});

/*
 * Here is where we "activate" the DataView.
 * We have decided that each node with the class "facet_item" encapsulates a single draggable
 * object.
 *
 * So we inject code into the DragZone which, when passed a mousedown event, interrogates
 * the event to see if it was within an element with the class "facet_item". If so, we
 * return non-null drag data.
 *
 * Returning non-null drag data indicates that the mousedown event has begun a dragging process.
 * The data must contain a property called "ddel" which is a DOM element which provides an image
 * of the data being dragged. The actual node clicked on is not dragged, a proxy element is dragged.
 * We can insert any other data into the data object, and this will be used by a cooperating DropZone
 * to perform the drop operation.
 */
function initializeFacetDragZone(v) {
    v.dragZone = new Ext.dd.DragZone(v.getEl(), {

//      On receipt of a mousedown event, see if it is within a draggable element.
//      Return a drag data object if so. The data object can contain arbitrary application
//      data, but it should also contain a DOM element in the ddel property to provide
//      a proxy to drag.

		ddGroup:'topics',
        getDragData: function(e) {
            var sourceEl = e.getTarget(v.itemSelector, 10);
           if (sourceEl) {
               d = sourceEl.cloneNode(true);
                d.id = Ext.id();
                a = new Array(1);
                a[0]=v.getRecord(sourceEl);
                return v.dragData = {
                    sourceEl: sourceEl,
                    repairXY: Ext.fly(sourceEl).getXY(),
                    ddel: d,
                    facetData: a
                }
            }
        },

//      Provide coordinates for the proxy to slide back to on failed drag.
//      This is the original XY coordinates of the draggable element.
        getRepairXY: function() {
            return this.dragData.repairXY;
        }
    });
}

function selectFacet(v,index,el,event) {
    v.dragZone = new Ext.dd.DragZone(v.getEl(), {


		ddGroup:'facetGroup',
        getDragData: function(e) {
            var sourceEl = e.getTarget(v.itemSelector, 10);
           if (sourceEl) {
                d = sourceEl.cloneNode(true);
                d.id = Ext.id();
                return v.dragData = {
                    sourceEl: sourceEl,
                    repairXY: Ext.fly(sourceEl).getXY(),
                    ddel: d,
                    facetData: v.getSelectedRecords()
                }
            }
        },

        getRepairXY: function() {
            return this.dragData.repairXY;
        }
    });
}
/*
 *******************************************************************************
 * CLASS
 * FacetCloudPanel
 * 
 * PURPOSE
 * To format facet values and count in tag cloud style
 *******************************************************************************
 */

// Apply custom namespace
Ext.namespace('Ext.ux');


/* Ext.ux.FacetCloudPanel = function(config) {
    Ext.ux.FacetCloudPanel.superclass.constructor.call(this, config);
	this.facet=config.facet; */

Ext.ux.FacetCloudPanel = Ext.extend(Ext.Panel,{
	facet: '',
	collapsible:true,
	collapsed:true,
	title:'No Title',
//	layout:'fit',
//	autoWidth:true,
//	autoScroll:true,
//	cls:'facet_cloud_container',
//	autoHeight:true,
//	onRender: function(ct, position) {
//		Ext.ux.FacetCloudPanel.superclass.onRender.call(this, ct, position);
//	},
	initComponent: function(){
		var self = this;
		Ext.ux.FacetCloudPanel.superclass.initComponent.call(this);
		if (typeof this.facet === 'object') {
			this.name=this.facet.name;
			this.label=this.facet.label;
			this.store=this.facet.store;

			this.title=this.label;
		//	this.renderTo=this.name;
			this.addEvents('facetChange');
			this.dataview = new Ext.DataView({
				store: this.store,
				tpl: new Ext.XTemplate('<tpl for=".">',
					'<div class="facet_cloud_item" title="{field_value} ({facet_count})"><span style="font-size:{facet_style}">{field_value}</span></div>',
				'</tpl>'),
				autoScroll:true,
				autoHeight:true,
				autoWidth:true,
				multiSelect: true,
				overClass:'facet_item-over',
				selectedClass:'facet_item-selected', 
			/*	cls:'facet_cloud_item',
				baseCls:'facet_cloud_item',*/
				ctCls:'facet_cloud_container',
				itemSelector:'div.facet_cloud_item',
				loadingText: 'Loading...',
				emptyText: 'None',
				border:false,
				onClick: function(e) {
					var item = e.getTarget(this.itemSelector, this.el);
					if(item){
						var index = this.indexOf(item);
						if(this.onItemClick(item, index, e) !== false){
							this.fireEvent("click", this, index, item, e);
						} 
					} /*else{
						if(this.fireEvent("containerclick", this, e) !== false){
							this.clearSelections();
						}
					} */
					self.fireEvent('facetChange', this.getSelectedRecords());
				}, 
				listeners: {
					render: initializeFacetDragZone //,
					//'click': selectFacet
					}
				//}
			});
			this.add(this.dataview);
		}
	}
});
/*
 *******************************************************************************
 * CLASS
 * FacetSearchPanel
 * 
 * PURPOSE
 * To mange form for faceted search
 *******************************************************************************
 */

// Apply custom namespace
Ext.namespace('Ext.ux');

Ext.ux.FacetSearchPanel = function(config) {
    // call parent constructor
    Ext.ux.FacetSearchPanel.superclass.constructor.call(this, config);
	this.facetStore=config.facetStore;
	this.pagingStore=config.pagingStore;
	this.maxPageSize=config.pageSize;
	this.pageSize=this.maxPageSize;
	var self = this;

	this.pagingStore.addListener('datachanged', this.datachanged,this);
	
//	this.bodyStyle='padding: 10px; margin: 0px 5px 0px 0px; background-color: #fff2e3';
	this.bodyStyle='padding: 10px; margin: 0px 0px 0px 0px; background-color: #fff2e3';
	this.pagingBar = new Ext.PagingToolbar({
		pageSize: this.pageSize,
		border:false,
		store: this.pagingStore,
		width:420,
		style: 'margin: 0px 1px 0px 25px;',
		displayInfo: true,
		displayMsg: 'Displaying items {0} - {1} of {2}',
		emptyMsg: "No images to display",
		setPageSize: function(size) {
			this.pageSize=size;
			if(this.pageSize==1) {
				this.beforePageText.toggle('Page','Image');
			} else {
				this.beforePageText.toggle('Image','Page');
			}
			var vp = this.findParentByType('viewport');
			vp.getLayout().north.panel.syncSize();
			vp.doLayout();

		},
		// WARNING: This is copied and modified from PagingToolbar.js source. It should be checked/updated on new releases
		onClick : function(which){
			var store = this.store;
			var current_curosr;
			
			switch(which){
				case "first":
					current_curosr=0;
					this.doLoad(0);
				break;
				case "prev":
					current_curosr=Math.max(0, this.cursor-this.pageSize);
					this.doLoad(Math.max(0, this.cursor-this.pageSize));
				break;
				case "next":
					current_curosr=this.cursor+this.pageSize;
					this.doLoad(this.cursor+this.pageSize);
				break;
				case "last":
					var total = store.getTotalCount();
					var extra = total % this.pageSize;
					var lastStart = extra ? (total - extra) : total-this.pageSize;
					current_curosr=lastStart;
					this.doLoad(lastStart);
				break;
				case "refresh":
					current_curosr=this.cursor;
					this.doLoad(this.cursor);
				break;
			}
			if(self.pagingBar.pageSize==1) {
				self.fireEvent('newItem',{id:store.getAt(0).data.id,offset:0,item_type:'photo',event_type:'select'});
			}
		},
   // private
    onRender : function(ct, position){
        Ext.PagingToolbar.superclass.onRender.call(this, ct, position);
        this.first = this.addButton({
            tooltip: this.firstText,
            iconCls: "x-tbar-page-first",
            disabled: true,
            handler: this.onClick.createDelegate(this, ["first"])
        });
        this.prev = this.addButton({
            tooltip: this.prevText,
            iconCls: "x-tbar-page-prev",
            disabled: true,
            handler: this.onClick.createDelegate(this, ["prev"])
        });
        this.addSeparator();
        
        // Want handle to beforePageText so that we can change it.
   //     this.beforePageTextItem = new Ext.Toolbar.TextItem(this.beforePageText);
    //    this.add(this.beforePageTextItem);
        this.add(this.beforePageText);
        this.field = Ext.get(this.addDom({
           tag: "input",
           type: "text",
           size: "3",
           value: "1",
           cls: "x-tbar-page-number"
        }).el);
        this.field.on("keydown", this.onPagingKeydown, this);
        this.field.on("focus", function(){this.dom.select();});
        this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
        this.field.setHeight(18);
        this.addSeparator();
        this.next = this.addButton({
            tooltip: this.nextText,
            iconCls: "x-tbar-page-next",
            disabled: true,
            handler: this.onClick.createDelegate(this, ["next"])
        });
        this.last = this.addButton({
            tooltip: this.lastText,
            iconCls: "x-tbar-page-last",
            disabled: true,
            handler: this.onClick.createDelegate(this, ["last"])
        });
        this.addSeparator();
        this.loading = this.addButton({
            tooltip: this.refreshText,
            iconCls: "x-tbar-loading",
            handler: this.onClick.createDelegate(this, ["refresh"])
        });

        if(this.displayInfo){
            this.displayEl = Ext.fly(this.el.dom).createChild({cls:'x-paging-info'});
        }
        if(this.dsLoaded){
            this.onLoad.apply(this, this.dsLoaded);
        }
    },

		paramNames:{start:'start',limit:'rows'}
	});


	this.addEvents('newItem');
	this.addEvents('removeFacet');
	this.addEvents('textChanged');

	this.constraintView =	new Ext.DataView({
			store: this.facetStore,
			prepareData: function(data) {
				if(data.field_name.match("isPartOf")) {
				//	data.display=Ext.util.Format.substr(data.field_value, 'inu-wint-'.length, 20);
					data.display=data.item_label;
				} else {
					data.display=data.field_value;
				}
				return data;
			},
			tpl: new Ext.XTemplate(
				'<tpl for=".">',
					'<tpl if="field_name != \'text\'">',
					'<div id="{id}" class="constraint_item" title="Click to remove this constraint."><img src="http://repository.library.northwestern.edu/winterton/images/facet-button.gif"/>{display}</div>',
					'</tpl>',
				'</tpl>'
			),
			autoHeight:true,
			multiSelect: true,
			overClass:'constraint_item-over',
			itemSelector:'div.constraint_item',
			loadingText: 'Loading...',
			border:false,
			listeners: {
				'click': function (v,index,el,event) {
					self.fireEvent('removeFacet',el.id);
				}
			}
		});


	this.add({
		layout: 'column',
		bodyStyle  : 'margin: 0px 0px 0px 0px; background-color: #fff2e3',
		border: false,
		items: [
		{
			bodyStyle  : 'background-color: #fff2e3',
			border: false,
			layout: 'form',
			labelWidth: 69,
			items: [{
				xtype: 'textfield',
				style: 'margin: 0px 9px 0px 0px',
				fieldLabel: 'Search term',
				id:'text',
				listeners: {
					specialkey: function(f,e) {
						if(e.getKey() == e.ENTER) {
							self.fireEvent('textChanged',{text:f.getValue()});
						}
						if(e.getKey() == e.DELETE) {
							self.fireEvent('textChanged',{text:f.getValue()});
						}
					}
				}
			}]
		} /*,{
			bodyStyle  : 'background-color: #fff2e3',
			border: false,
			layout: 'form',
			items: [{
				xtype: 'button',
				style: 'margin: 0px 1px 0px 0px;',
			   text: ' Search',
				handler: function() {
					self.fireEvent('textChanged',{text:formPanel.findById('text').getValue()});
				}                    
			} ]
		}*/ ,this.pagingBar]
	});
	
	
	// Add dataview for chosen contstraints
	this.add(this.constraintView);
	
}

Ext.extend(Ext.ux.FacetSearchPanel, Ext.Panel, {
	newItem: function(params) {
		this.findById('text').reset();
		if(params.event_type=='select') 
		{
			this.pagingBar.setPageSize(1);
		} else { 
			this.pagingBar.setPageSize(this.maxPageSize);
		}
	},
	newSearch: function(params) {
		this.pagingBar.setPageSize(this.maxPageSize);
	},
	initForm: function(params) {
		this.findById('text').reset();
	},
	// Data change seems to be the only way we know there's been a page advance
	datachanged: function(dataStore)
	{
		this.constraintView.refresh();
		var vp = this.constraintView.findParentByType('viewport');
		vp.getLayout().north.panel.syncSize();
		vp.doLayout();

		if(this.pagingBar.pageSize==1) {
			// this.fireEvent('newItem',{id:dataStore.getAt(0).data.id,offset:0,item_type:'photo',event_type:'select'});
			var item_label = dataStore.getAt(0).data.item_label;
			this.fireEvent('newItem',{id:dataStore.getAt(0).data.id,offset:0,item_type:'photo',event_type:'select', item_label:item_label});


		}
	}



}); // end of extend

﻿/*
 *******************************************************************************
 * CLASS
 * CollectionTree
 * 
 * PURPOSE
 * To manage collection heiararchy
 *******************************************************************************
 */

// Apply custom namespace
Ext.namespace('Ext.ux');

// Set up some of Tree config parameters before calling superclass constructer

Ext.ux.CollectionTree = function(config) {
	
    config.rootVisible=false;
    config.border=false;
	config.hideCollapseTool=true;
	config.autoScroll=false;
	config.loader=new Ext.tree.TreeLoader({dataUrl:config.tree_url, 
		 getParams: function(node){
			this.constructor.prototype.getParams.apply(this, arguments);
			var buf = [], bp = this.baseParams;
			for(var key in bp){
				if(typeof bp[key] != "function"){
					buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
				}
			} 
			if(node.id.match(/ynode/i)) {
				buf.push("unitid=0");
			} else {
				buf.push("unitid=", encodeURIComponent(node.id));
			}
			return buf.join("");
		}				  
	});

	 // set the root node
	config.root = new Ext.tree.AsyncTreeNode({
		text: 'Winterton',
		id: '0',
		leaf: false
	});

    Ext.ux.CollectionTree.superclass.constructor.call(this, config);

	// Initialize data for current selected item
	this.selectedItem='';

	// We're going to fire newItem to signal that a tree node has been selected
	this.addEvents('newItem');

	// Listen for the click of a tree node
	this.addListener('click', function( n , e ) {
	/*	if(n.attributes.dao != undefined) {
			window.open(n.attributes.dao,"WINTERTON_BOOK","resizable=yes,scrollbars=yes,status=yes");
		} else { */
			var itemID = 'inu-wint-' + n.id;
			var label = (n.attributes.label != '') ? n.attributes.label : 'item';

			var type = (n.leaf == true) ? 'photo' : 'container';
			this.fireEvent('newItem',{id:itemID, item_type:type, event_type:'new', item_label:label});
	//	}
	}, this);

}

Ext.extend(Ext.ux.CollectionTree, Ext.tree.TreePanel, {
	newSearch: function (params) {
		this.collapseAll();
	},
	showItem:function (id,label,leaf) {
		var nodeID=Ext.util.Format.substr(id, 'inu-wint-'.length, 20);
		var type = (leaf == true) ? 'photo' : 'container';
		this.fireEvent('newItem',{id:id, item_type:type, event_type:'new', item_label:label});
	},

	newItem: function (params) {
		nodeID=Ext.util.Format.substr(params.id, 'inu-wint-'.length, 20);
		
	//	if(nodeID != this.selectedItem) {
			this.selectedItem=nodeID;
	
			var id_array = nodeID.split('-');
			this.collapseAll();
		
			var nodeid = '/0';
			
			for (var i=0;i<id_array.length;i++) 
			{
				nodeid += '/';
				for (j=0;j<=i;j++) 
				{
					if(j!=0) {nodeid += '-';}
					nodeid += id_array[j];
				}
				
				this.expandPath(nodeid);
				this.selectPath(nodeid);
			}
		//}
	}

}); // end of extend

/*
 *******************************************************************************
 * CLASS
 * FacetSearchPanel
 * 
 * PURPOSE
 * To mange form for faceted search
 *******************************************************************************
 */

// Apply custom namespace
Ext.namespace('Ext.ux');

Ext.ux.MainPanel = function(config) {/* This is for the search results, displaying thumbnails of doc items. */								
    // call parent constructor
	this.store=config.store;
	this.autoScroll=true;
	this.metadata_base_url= config.metadata_base_url;
	this.solr_url= config.solr_url;
	this.fedora_base_url=config.fedora_base_url;
	
	this.fed_conn = new Ext.data.Connection();

	// We display search results and individual items. 
	this.display_mode='search'; // Can be 'search' or 'item'

	// Item type is 'container' or 'photo'. It refers to the last item being displayed
	this.itemType='photo';
	
	var self=this;
	
    Ext.ux.MainPanel.superclass.constructor.call(this, config);

	// We're going to fire newItem to signal that a thumbnail selected
	this.addEvents('newItem');
	this.addEvents('searchRequest');

	this.task = {
		node: '',
		record: '',
		run: function(){
			if(this.record != '' && this.record['istore'] != undefined) {
		  //  	Ext.fly('clock').update(new Date().format('g:i:s A') + ' wa');
	  
				var counter = this.record.data['counter'];
				var count = this.record['istore'].getCount();
				if(counter < count-1) {
					counter = counter + 1;
				} else {
					counter = 0;
				}
				this.record.data['counter']=counter;
				
				var turl = self.fedora_base_url + 'inu:' + this.record['istore'].getAt(counter).data['id'] + '/THUMBNAIL';
			//	var title = counter + ' of ' + count;
				var title = count + ' items';
	//			var img = this.node.getElementsByTagNameNS('','img')[0];
	//			var id = this.record['istore'].getAt(counter).data['id'];
	//			var el = Ext.get(id);
	//			el.ghost();
				var img = this.node.getElementsByTagName('img')[0];
				img.src = turl;
				img.title = title;
			}
		},
		interval: 333 //1/3 second
	}
	var runner = new Ext.util.TaskRunner();
	runner.start(this.task);

	this.itemViewer = new Ext.DataView({
			task:this.task,
			id: 'dv',
			store: this.store,
			//plugins: new Ext.DataView.DragSelector({dragSafe:true}),
			el: 'center-body',
			cls: 'item_view_dv',
			prepareData: function(data) {
		// last good		data.isAlone = (this.store.getCount()==1 && data.item_type.toString().match("photo")) ? true : false;
				data.isAlone = (this.store.getCount()==1 && self.display_mode.match("item")) ? true : false;
				data.isContainer = (data.item_type.toString().match("container")) ? true : false;
				data.isBook = (data.item_type.toString().match("book")) ? true : false;
			//	data.isAlone = (this.store.getCount()==1) ? true : false;
				data.unitid=Ext.util.Format.substr(data.id, 'inu-wint-'.length, 20);
				try {
                                        var pageTracker = _gat._getTracker("UA-797260-2");
                                        pageTracker._trackPageview('/winterton/' + data.id);
				} catch(err) {console.log('got GA error');}				
				
			/*	if(data.isAlone) {
					data.wrapped= new Ext.Resizable(data.unitid, {
						wrap:true,
						pinned:true,
						minWidth:50,
						minHeight: 50,
						preserveRatio: true
					});
				} */
				return data;
			},
			tpl: new Ext.XTemplate('<tpl for=".">',
				'<tpl if="isAlone">',
					'<tpl if="isBook">',
						'<div id="{unitid}" class="image_page_image">',
						'<a href="{full_url}" target="_blank">',
						'<img id="{id}" src="/fedora/get/inu:{id}/inu:sdef-addimage/getWithWidth?width=500" title="Link to Book"/></a>',
						'</div>',
					'</tpl>',
					'<tpl if="!isBook">',
						'<div id="{unitid}" class="image_page_image">',
						'<a href="/fedora/get/inu:{id}/inu:sdef-core/getEmbeddedContent" target="_blank">',
						'<tpl if="isContainer"><span>&#160;</span></tpl>',
						'<img id="{id}" src="/fedora/get/inu:{id}/inu:sdef-addimage/getWithWidth?width=500" title="{title}"/></a>',
						'</div>',
					'</tpl>',
				'</tpl>',
				'<tpl if="!isAlone">',
					'<div class="listing" id="{unitid}">',
					'<table width="162" height="162">',
					'<tr valign="center" width="162" height="150">',
					'<td><a>',
					'<tpl if="isContainer"><span></span></tpl>',
					'<img id="{id}" src="/fedora/get/inu:{id}/THUMBNAIL" title="{title}"/></a>',
					'</td></tr><tr width="162"><td class="listing_thumb_title">{shortTitle}',
					'</td>',
					'</tr>',
					'</table>',	
					'</div>',
				'</tpl>',
			'</tpl>'), 
	//		autoScroll:true,
			autoHeight:true,
			multiSelect: true,
			emptyText: 'No facets to display',
			overClass:'white-view-over',
			selectedClass:'x-view-selected',
			loadingText: 'Loading...',
			emptyText: 'No images to display',
			itemSelector:'div.listing',
			border:false,
				listeners: {
					'click': function(dv,i,n,e) {
						var id=dv.getSelectedRecords()[0].data.id;
						var label=dv.getSelectedRecords()[0].data.item_label;

						if(self.display_mode=='item') {
							this.fireEvent('newItem',{id:id,offset:i,item_type:'photo',event_type:'select',item_label:label});
						} else {
							self.display_mode='item'; // Can be 'search' or 'item'
							this.fireEvent('newItem',{id:id,offset:i,item_type:'photo',event_type:'new',item_label:label});
							self.showItemMetadata({id:id,offset:i,item_type:'photo',event_type:'select'});
						}
					},
					'mouseenter': function(d,i,n,e) {
						var view=this;
						var item_data = d.store.getAt(i).data;
						
						if(item_data.item_type.toString().match("container")) {
							if(item_data['counter'] == undefined) {
								// set up counter
								item_data['counter']=1;

								// form solr url for store
								var solr_url = self.solr_url;
								solr = solr_url + 'version=2.2&start=0&rows=1000&sort=sortkey_i+asc&wt=json&fl=id,thumburl_t&q=\(isPartOf:' + item_data['id'] + ' AND item_type:photo\) OR \(id:' + item_data['id'] + ' AND item_type:frame\)';
					// debug			solr = '/winterton2/photos.json?';

								var aReader = new Ext.ux.SolrDocReader({
									fields: ['id']
								}, SolrDocRecordDef);

								var istore = new Ext.data.Store({
									url: solr,
									reader: aReader
								});

								istore.load({
									options: {groupStore:d.store, itemIndex:i},
									callback: function(r,o,s) {
										if(r.length > 1) {
											o.options.groupStore.getAt(o.options.itemIndex)['istore']=this;
										}
									}
								});
							}	

							// Point timer at record and node
							this.task.record=d.store.getAt(i);
							this.task.node=n;
					}
							
					},
					'mouseleave': function(d,i,n,e) {
						if(this.task.record['istore']!=undefined) {
							var turl = this.fedora_base_url + 'inu:' + this.task.record['istore'].getAt(0).data['id'] + '/THUMBNAIL';

							var img = this.task.node.getElementsByTagName('img')[0];
							img.src = turl;

						}

						this.task.record='';
						this.task.node='';
						this.task.store='';
					}, 'render': function(dv) {
					
					
						dv.dragZone = new Ext.dd.DragZone(dv.getEl(), {
						ddGroup:'galleries',
						getDragData: function(e) {
							var sourceEl = e.getTarget(dv.itemSelector, 10);
						   if (sourceEl) {
							   d = sourceEl.cloneNode(true);
							   
								d.id = Ext.id();
								a = new Array(1);
								a[0]=dv.store.getAt(dv.store.find('id', sourceEl.id));
							   return dv.dragData = {
									sourceEl: sourceEl,
									repairXY: Ext.fly(sourceEl).getXY(),
									ddel: d,
									itemData: a
								} // return
							} // if
						}, // function
				
						getRepairXY: function() {
							return this.dragData.repairXY;
						}
					   }); // DragZone

						dv.findParentByType('viewport').doLayout();
					}, scope:this
				}
		});


	this.initializeItemDragZone = function (v) {
		v.dragZone = new Ext.dd.DragZone(v.getEl(), {
		ddGroup:'galleries',
        getDragData: function(e) {
            var sourceEl = e.getTarget(v.itemSelector, 10);
           if (sourceEl) {
               d = sourceEl.cloneNode(true);
               
                d.id = Ext.id();
                a = new Array(1);
                a[0]=scope.store.getAt(scope.store.find('id', sourceEl.id));
               return v.dragData = {
                    sourceEl: sourceEl,
                    repairXY: Ext.fly(sourceEl).getXY(),
                    ddel: d,
                    itemData: a
                } // return
            } // if
        }, // function

        getRepairXY: function() {
            return this.dragData.repairXY;
        }
       }); // DragZone
    };


	this.metadataPanel = new Ext.Panel({
		region:'south',
		id:'metadataPanel',
		border:false ,
		listeners: {
			'render': function(c) {
				if(!c.hasListener('click')) {
					c.getEl().on('click', function(e,n) {
					/*	var desc_type=n.getAttributeNS('','desc_type');
						if(desc_type != undefined && desc_type != '') {
							var desc_value=n.getAttributeNS('','desc_value');
							alert('desc_type:' + desc_type + ', desc_value:' + desc_value);
							self.fireEvent('searchRequest',{desc_type:desc_type,desc_value:desc_value});
						}
*/

						if(e.getTarget().href != undefined && e.getTarget().href.match("#")) { // empty href?
							if(Ext.isIE) {
								var desc_value=e.getTarget().innerText;
							} else {
								var desc_value=n.text;
							}
							self.fireEvent('searchRequest',{desc_type:'subject_t',desc_value:desc_value});
					//	} else {
					//		console.log(e.getTarget().href + ' : ' + document.URL);
						}


					}); 
				}
			}
		} 
	});
		
/*	this.metadataPanel.body.addListener(
		listeners: {
			'click': function(dv,i,n,e) {
				var id=dv.getSelectedRecords()[0].data.id;
				if(self.display_mode=='item') {
					this.fireEvent('newItem',{id:id,offset:i,item_type:'photo',event_type:'select'});
				} else {
					this.fireEvent('newItem',{id:id,offset:i,item_type:'photo',event_type:'new'});
				}
				self.display_mode='item'; // Can be 'search' or 'item'
				self.showItemMetadata({id:id,offset:i,item_type:'photo',event_type:'select'});
			},

	*/
	
	
	this.titlePanel = new Ext.Panel({
		region:'north',
	//	html:'titlePanel',
		border:false
	});

	this.add({region:'north',border:false, autoHeight:true, items: this.titlePanel});
	this.add({region:'center',border:false, autoHeight:true, items: this.itemViewer /*, listeners: {render: this.initializeItemDragZone, this.itemViewer} */});
	this.add({region:'south',border:false, autoHeight:true, items: this.metadataPanel});


}


Ext.extend(Ext.ux.MainPanel, Ext.Panel, {

	showItemMetadata: function(params) {
		var unitid=Ext.util.Format.substr(params.id, 'inu-wint-'.length, 20);
		var url=this.metadata_base_url + unitid;
		var scope=this; // save scope for use in success below

		this.fed_conn.request({
			url: url,
			method: 'POST',
			success: function(responseObject) {
				var stindex = responseObject.responseText.indexOf('<div id="titlebars"');
				var etindex = responseObject.responseText.indexOf('<a name="mdstart"/>');
				var title = responseObject.responseText.substring(stindex,etindex);
				
				scope.titlePanel.body.update(title);
	
				var smindex = responseObject.responseText.indexOf('<a name="mdstart"/>') + '<a name="mdstart"/>'.length;
				var emindex = responseObject.responseText.indexOf('<a name="mdend"/>');
				var md = responseObject.responseText.substring(smindex,emindex);
				scope.metadataPanel.body.update(md);
	/*			scope.metadataPanel.getEl().on('click', function(e,n) {
					var desc_type=n.getAttributeNS('','desc_type');
					if(desc_type != undefined && desc_type != '') {
						var desc_value=n.getAttributeNS('','desc_value');
						var desc_value=n.getAttributeNS('','desc_value');
						scope.fireEvent('searchRequest',{desc_type:desc_type,desc_value:desc_value});

					}
				}); */
			},
			failure: function() {
				Ext.Msg.alert('Status', 'Unable to get item metadata:' + url);
			}
		});
		this.atItemLevel=true;

		var vp = this.findParentByType('viewport');
		vp.getLayout().center.panel.syncSize();
		vp.doLayout();
	},
	newItem: function(params) {
		this.display_mode='item';
		this.itemType=params.item_type;
		this.showItemMetadata(params);
	},
	newSearch: function() {
		this.display_mode='search';
		this.clearPanels();
		
	},
	clearPanels: function() {
		this.titlePanel.body.update("");
		this.metadataPanel.body.update("");
		this.findParentByType('viewport').doLayout();
	}

}); // end of extend


/**
 * 
 * @author Bill Parod
 */

/** 
 * @name Ext.ux
 * @namespace The Ext.ux namespace is for extensions to Ext.
 */

/**
 */

// Apply custom namespace
Ext.namespace('Ext.ux');

Ext.ux.viewer = function(config) {							

	Ext.ux.viewer.superclass.constructor.call(this, config);


} // end of constructor

Ext.extend(Ext.ux.viewer, Ext.util.Observable, {



}); // end of extend


// Select a container from the thumbnails
function showItem(id,label,leaf)
{
	var nodeID = 'inu-wint-' + id;
//	tree.fireEvent('newItem',{id:nodeID});
	tree.showItem(nodeID,label,leaf);
}

Ext.onReady(function(){

	var service_defs = new ServiceDefs();

	this.solr = new Ext.ux.Solr({
		solr_url:service_defs.solr_url
	});

	var historyManager = new Ext.ux.HistoryManager({solr:solr});
	
    // The only requirement for this to work is that you must have a hidden field and
    // an iframe available in the page with ids corresponding to Ext.History.fieldId
    // and Ext.History.iframeId.  See history.html for an example.
    Ext.History.init();
    
	var facets = this.solr.getFacets();
	
	this.pageSize=50;
	
	/*
	var galleryPanel = 	new Ext.ux.GalleryPanel({
		renderTo: 'gallery',
		collapsible:true,
		collapsed:true,
		title:'Galleries',
		autoScroll:true,
		autoHeight:true,
		border:false
	});
	*/
	
	// Collection browser tree
	
	tree = new Ext.ux.CollectionTree({
		border:false,
		tree_url:service_defs.tree_base_url
	});
	
	// Search form and chosen facet panel
	this.formPanel =  new Ext.ux.FacetSearchPanel({
		facetStore:this.solr.searchConstraintStore,
		pagingStore:this.solr.store,
		pageSize:50
	});
	
	this.pagingBar = this.formPanel.pagingBar;
	
	this.itemPanel = new Ext.ux.MainPanel({
		store:this.solr.store,
		solr_url:service_defs.solr_url,
		metadata_base_url:service_defs.metadata_base_url,
		fedora_base_url:service_defs.fedora_base_url
	});
		
	
	tree.addListener('newItem',this.solr.newItem, this.solr );
	tree.addListener('newItem',this.itemPanel.newItem, this.itemPanel );
	tree.addListener('newItem', this.formPanel.newItem, this.formPanel);
	
	this.itemPanel.addListener('newItem',this.solr.newItem, this.solr );
	this.itemPanel.addListener('newItem',tree.newItem, tree );
	this.itemPanel.addListener('newItem',this.formPanel.newItem, this.formPanel );
	this.itemPanel.addListener('searchRequest',this.solr.searchRequest, this.solr );
	
	this.solr.addListener('newSearch',this.itemPanel.newSearch, this.itemPanel );
	//this.solr.addListener('newItem', this.formPanel.newItem, this.formPanel);
	this.solr.addListener('newSearch', this.formPanel.newSearch, this.formPanel);
	this.solr.addListener('newSearch', tree.newSearch, tree);
	this.solr.addListener('noteHistory', historyManager.noteHistory, historyManager);
	
	this.formPanel.addListener('removeFacet', this.solr.removeFacetConstraint, this.solr);
	this.formPanel.addListener('textChanged', this.solr.textChanged, this.solr);
	this.formPanel.addListener('newItem', this.itemPanel.newItem,this.itemPanel);
	this.formPanel.addListener('newItem', tree.newItem, tree);
	
	historyManager.addListener('newItem', tree.newItem, tree);
	historyManager.addListener('newItem', this.itemPanel.newItem, this.itemPanel);
	historyManager.addListener('newItem', this.formPanel.newItem, this.formPanel);
	historyManager.addListener('newItem',this.solr.newItem, this.solr );
	
	var self=this;
	
	/* This provides the Collection Browser tree of nodes */
	var navPanel = new Ext.Panel({
				contentEl: 'nav-browser',
				collapsible:true,
				collapsed:true,
				cls: 'nav-browse-ul-top',
				title:'Collection Browser',
				border:false,
				autoScroll:true,
				fitToFrame:false,
				boxWrap: false,
				items: [tree]
				});
	
	var viewport = new Ext.Viewport({
				layout:'border',
				items:[
					new Ext.BoxComponent({ // raw
						region:'north',
						el: 'north' ,
						height:90
					}),/*new Ext.BoxComponent({ 
						region:'south',
						el: 'south-panel',
						height:140
					}),*/{
						region:'west',
						id:'west-panel',
						title:'  ',
						split:true,
						boxWrap: true,
						minSize: 175,
						width: 200,
						collapsible: true,
						collapseFirst: true,
						margins:'0 0 0 5',
						autoScroll:true,
						fitToFrame:true,
						layoutConfig:{
							animate:true
						},items: [navPanel,new Ext.Panel({
									border:false,
									autoScroll:true,
									fitToFrame:true,
									deferredRender:false,
									initComponent:function() {
										for (facet_key in facets) {
												var facet = facets[facet_key];
												var f;
												if(facet.name.match(/keyword/)) {
													f = new Ext.ux.FacetCloudPanel({
														facet:facet 
													});
												} else {
													f = new Ext.ux.FacetPanel({
														facet:facet 
													});
												}
												f.addListener('facetChange', self.solr.onfacetChanged);
												this.add(f);
										}
									}
								}) /*, galleriesPanel */
						]},
						
	{
				layout: 'border',
				region:'center',
				border: false,
				split:true,
				items: [
					{region:'north', border:false, autoHeight:true, items: this.formPanel },
					{region:'center', autoScroll:true, border:false,  bodyStyle: 'margin: 0px 0px 0px 0px;', items:this.itemPanel}
				]
			}]
	
			});


		var argPos = location.href.indexOf('?');
		if (argPos > -1) 
			{
			var args = (location.href.indexOf('#') > -1) ? location.href.substring(argPos+1,location.href.indexOf('#')) : location.href.substring(argPos+1);
			var urlObj = Ext.urlDecode(args);
			if(urlObj.id) {
				tree.showItem(urlObj.id, itemID,false);
			} else if (itemID!=undefined && itemID!='') {
				tree.showItem(itemID, itemID,false);
			} else {
				this.solr.getAllPhotos();
			} 
		} else if (itemID!=undefined && itemID!='') {
			tree.showItem(itemID,itemLabel,itemIsLeaf);
		} else {
			this.solr.getAllPhotos();
		}
	
		viewport.getLayout().north.panel.syncSize();
		viewport.doLayout();

});

