FilterSet = function(config){
	return {
		filterList: config.filterList
		,container: config.container
		,header: config.header || 'Filter By:'
		,values: config.filter || {}
		,onChange: config.change
		,init: function(){
			this.filters = {};
			
			var hdr = '<span>'+this.header+'</span>';
			
			for(var i=0; i<this.filterList.length; i++){
				var f = this.filterList[i];
				f.filterSet = this;
				f.ct = this.container;
				if(this.values[f.param] != undefined){
					f.autoRender = true;
					f.value = this.values[f.param];
				}
				this.filters[f.name] = new Filter(f);
				this.filters[f.name].init();
				
				hdr += '<a id="'+'link-'+f.name+'" href="#" class="'+(f.autoRender ? ' on' : '')+'">'+f.label+'</a>';
			}
			
			$('#'+this.container+' .filter-fields').html(hdr);
			
			var that = this;
			$('#'+this.container+' .filter-fields a').click(function(){
				var id = this.id.replace(/link-/,'');
				if($(this).hasClass('on')){
					$(this).removeClass('on');
					that.hide(id);	
				} else {
					$(this).addClass('on');
					that.show(id);
				}
			});
		}
		,setFilter: function(vals){
			this.values = vals;
		}
		,getFilter: function(){
			return this.values;
		}
		,set: function(name, value){
			this.values[name] = value;
			this.onChange(this.getFilter());
		}
		,show: function(name){
			if(this.filters[name] && this.filters[name].rendered)
				this.filters[name].show();
			else if(this.filters[name])
				this.filters[name].render();
		}
		,hide: function(name){
			this.filters[name].hide();
			delete this.values[this.filters[name].param];
		}
	};
}

Filter = function(config){
	var f = {
		name: config.name
		,param: config.param || config.name
		,baseParams: config.baseParams || {}
		,url : config.url || '/rest/'+config.name+'.php'
		,ct : config.ct
		,data : config.data
		,expandData: config.expandData
		,value : config.value
		,closable : config.closable || false
		,idField : config.idField || 'id'
		,index : config.index
		,displayField  : config.displayField || 'name'
		,renderValue : config.renderValue || function (o){ return o[this.displayField]; }
		,any : config.any !== undefined ? config.any : true
		,label : config.label !== undefined ? config.label : config.name
		,labelSeparator: config.labelSeparator !== undefined ? config.labelSeparator : ":"
		,emptyText : config.emptyText || 'Select a '+(config.label ? config.label.toLowerCase() : config.name)+':'
		,filterSet : config.filterSet
		,renderDetails : config.renderDetails
		,autoRender : config.autoRender
		,onRender : config.onRender || function(){}
		,init : function(){
			var that = this;
			if(this.data){
				if(this.expandData){
					var newData = [];
					for(var i=0; i<this.data.length; i++){
						var o = {};
						o[this.idField] = typeof this.data[i] == 'object' ? this.data[i][0] : this.data[i];
						o[this.displayField] = typeof this.data[i] == 'object' ? this.data[i][1] : this.data[i];
						newData.push(o);
					}
					this.data = newData;
				}
				this.createIdMap();
				if(this.autoRender) this.render();
			} else if(!this.data) {
				$.get(this.url, this.baseParams, function(data){
					that.data = data[that.name];
					that.createIdMap();
					if(that.autoRender) that.render();
				}, "json");
			}
		}
		,createIdMap:function(){
			// create a map of id keys -> array indices (to be used when rendering details)
			this.idMap = {};
			for(var i=0; i<this.data.length; i++){
				this.idMap[this.data[i][this.idField]] = i;
			}
		}
		,render : function(){
			var index = this.index !== undefined ? '_'+this.index : '';
			var html = '<div id="wrap-'+this.name+'" class="filter-wrap">';
			if(this.closable){
				html += '<span class="edit">';
				html += '<input type="button" class="filter-button" value="+"/> ';
				html += '<input type="button" class="filter-button" value="-"/> ';
				html += '</span>';
			}
			html += '<label for="'+this.name+'Filter">'+this.label+this.labelSeparator+'</label>';
			html += '<select name="'+this.name+'Filter">';
			html += '<option value="">'+this.emptyText+'</option>';
			html += '<option value="">-------------</option>';
			if(this.any) html += '<option value="">ANY</option>';
			for(var i=0; i<this.data.length; i++){
				html += '<option value="'+this.data[i][this.idField]+'"'
				+(this.data[i][this.idField] == this.value ? ' selected' : '')
				+'>'+this.renderValue(this.data[i])+'</option>';
			}
			html += '</select>';
			html += '<div class="details"></div>';
			html += '</div>'
			$('#'+this.ct).append(html);
			this.rendered = true;
			
			var that = this;
			this.el = $('#'+this.ct).children('.filter-wrap:last').children('select');
			this.wrap = this.el.parent('.filter-wrap');
			this.el.prevAll('.edit').children('.filter-button').click(function(){
				switch($(this).val()){
					case '-':
						that.filterSet.values.splice(that.wrap.prevAll('.filter-wrap').length,1);
						that.wrap.remove();
					break;
					case '+':
						that.filterSet.newFilter();
					break;
				}
			});
			this.el.change(function(){
				that.filterSet.set(that.index !== undefined ? that.index : that.param, $(this).val());
				if(that.renderDetails) that.showDetails();
			});
			this.onRender();
		}
		,show : function(){
			this.wrap.show();
		}
		,showDetails : function(){
			if(this.renderDetails && this.el)
				this.el.next('.details').html(this.renderDetails(this.data[this.idMap[this.el.val()]]));
		}
		,hide : function(){
			this.wrap.hide();
		}
	};
	
	return f;
}

FilterList = function(config){
	return {
		container: config.container
		,header: config.header || 'Filter By:'
		,name: config.name
		,renderLabel : config.renderLabel || function(){ return ""; }
		,url:  config.url || '/rest/'+config.name+'.php'
		,baseparams: config.params || {}
		,renderValue: config.renderValue || function(){}
		,renderDetails: config.renderDetails || function(){}
		,values: config.values || []
		,onChange: config.change || function(){}
		,init: function(){
			this.filters = [];
			
			var self = this;
			$.get(this.url, this.baseParams, function(data){
				self.data = data[self.name];
				for(var i=0; i<self.values.length; i++){
					self.renderFilter(i);
				}
			}, "json");
			
			$('#'+this.container+' .filter-fields').html(this.header);
		}
		,renderFilter: function(ct){
			var f = {};
			f.name = this.name;
			f.label = this.renderLabel(ct);
			f.labelSeparator = "";
			f.filterSet = this;
			f.ct = this.container;
			f.renderValue = this.renderValue;
			f.data = this.data;
			f.any = false;
			f.index = ct;
			f.closable = true;
			f.autoRender = true;
			if(this.renderDetails){
				f.renderDetails = this.renderDetails;
			}
			
			if(this.values[ct] != undefined){
				f.value = this.values[ct];
			}
			this.filters[ct] = new Filter(f);
			this.filters[ct].init();
		}
		,newFilter: function(){
			this.renderFilter(this.values.length);
			this.values.push('');
		}
		,setFilter: function(vals){
			this.values = vals;
			this.repaint();
		}
		,getFilter: function(){
			return this.values;
		}
		,repaint: function(){
			$('#'+this.container+' .filter-wrap').remove();
			for(var i=0; i<this.values.length; i++){
				this.renderFilter(i);
			}
			for(var i=0; i<this.filters.length; i++){
				this.filters[i].showDetails();
			}
		}
		,set: function(name, value){
			this.values[name] = value;
			this.onChange(this.getFilter());
		}
		,show: function(name){
			if(this.filters[name] && this.filters[name].rendered)
				this.filters[name].show();
			else if(this.filters[name])
				this.filters[name].render();
		}
		,hide: function(name){
			this.filters[name].hide();
			delete this.values[this.filters[name].param];
		}
		,getValue: function(){
			return this.values;
		}
	};
}
