function Browser()
{
	Actionable.call(this); // superclass(es)
	EventDispatcher.call(this);
	
	this.container = "Browser";
	this.page = 1;
	this.itemElement = "items";
	this.pager = new Pager(11);
	this.pager.selectors.scope = this.scope;
	
	this.filters = new Filters();
	this.ready = false;
	this.options = {"editwindow_scrollbars":1, "editwindow_resizable":"yes"};
	var self = this;

	if (this.controller)
	{
		this.url = this.controller+"/listing";
		this.actionURL = this.controller+"/action";
	}
	
	this.request = function(resetPage, onSuccess)
	{
		if (resetPage)
			this.page = 1;
			
		this.mainDiv
			.html('<img src="img/long_green.gif"/>');
			
		var _data = "pagenum=" + this.page;
		_data += this.filters.getQueryString();
		_data += this.getAdditionalData();
		this.ready = false;
		this.ajax.send
		(
			{
				url: this.url, 
				data: _data, 
				success: function(response)
				{
					var work;
					this.mainDiv.html('');
					if (this.ajax.dataType == "xml")
					{
						response = xml2json(response, "\t");
						response = eval('('+response+')');
						response = response.model;
					}
					
					var items;
					
					if (response.list)
						items = response.list[this.itemElement];
					
					var list = response.list;
					
					// Cool drawing of Filters
					if (response.filters)
					{
						var filters = response.filters.filter;
						this.filters.reset();
						for (var i = 0; i < filters.length; i++)
							this.filters.setValue(filters[i]['name'], filters[i]['value'], filters[i]['title']);
					}
					
					// Cool drawing of items
					if (items)
						if (items instanceof Array)
							for (var i = 0; i < items.length; i++)
								self.drawFromJSON(items[i]);
						else
							self.drawFromJSON(items);	
					
					// Draw pager
					var pager;
					if (list)
					{
						self.pager.load(list);
						self.pager.render();
					}
					
					this.setPositionById(getParams['selected'] ? getParams['selected'] : undefined);
					this.ready = true;
					if (onSuccess != undefined)
						onSuccess.call(this);
					this.fireEvent("items_loaded");
				},
	
				error: function(e)
				{
					this.mainDiv
					.html('Ajax request failed. ('+e+'))<a href="javascript:self.request()">Retry</a>');
				}
			}
		);
	}
	
	
	this.getAdditionalData = function() //A stub, if a browser needs to add some data
	{
		return "";
	}
	
	
	this.drawFromXML = function(entity, options)
	{
		var json = xml2json(entity.get(0), "\t");
		json = eval("("+json+")");
		var rendered = this.drawFromJSON(json[this.itemElement], options);
	}
	
	this.drawFromJSON = function(JSONEntity, options)
	{
		var id = this.getRecordIdentifier(JSONEntity);
		var block = $('<div rec-id="'+id+'" style="position: relative; width: 100%;"/>');
			
		var rendered = this.draw(JSONEntity);
		block.append(rendered);
		block.append("\r\n");
		block.get(0).entity = JSONEntity;
	
		this.attachActions(block);
		options = options || {};
		var xpend = (options.method == 'prepend') ? this.mainDiv.prepend : this.mainDiv.append;
		if (options.replaceId)
			this.mainDiv.find('div[@rec-id="'+options.replaceId+'"]').replaceWith(block);
		else
			xpend.call(this.mainDiv, block);
		
		this.setPositionById(id);
		if (this.onItemDrawn)
		{
			this.onItemDrawn();
		}
		if (!window.callback)
		{
			this.currentBlock.find('[@action="select"]').remove();
		}
	}
	
	this.draw = function(entity)
	{
		if (!this.view)
			this.view = new View({url: this.itemTemplate});
		return this.view.render(entity);
	}
	
	this.getActionQuery = function()
	{
		return (this.currentRecordId) ? 
						"id="+this.currentRecordId+this.filters.getQueryString() :
						this.filters.getQueryString();
	}
	
	this.setPosition = function(element)
	{
		this.currentBlock = $(element).parents('div[@rec-id]');
		this.setPositionById(this.currentBlock.attr('rec-id'));
	}
	
	this.setPositionById = function(id)
	{
		this.currentRecordId = undefined;
		this.currentEntity = undefined;
		this.currentBlock = undefined;
		this.mainDiv.find("[@rec-id]").removeClass("highlighted");
		
		if (id != undefined)
		{
			this.currentBlock = $('div[@rec-id='+id+']');
			this.currentRecordId = id;
			if ((id != undefined) && this.currentBlock.get(0))
			{
				this.currentRecordId = this.currentBlock.attr('rec-id');
				this.currentEntity = this.currentBlock.get(0).entity;
			}
			
			// Highlight current block
			if (this.currentBlock != undefined)
			{
				this.currentBlock.addClass("highlighted");
			}
		}
	}
	
	
	this.getRecordIdentifier = function(entity)
	{
		if (entity.attr)
			return entity.attr('id');
		else if (entity.id)
			return entity.id;
		else
			return entity;
	}
	
	this.deleteRecord = function(id)
	{
		if (!id)
			id = this.currentRecordId;
		$('div[@rec-id='+id+']').remove();
	}
	
	this.initialize = function(dontRunRequest)
	{
		this.mainDiv = $('div#'+this.container);
		
		// Initialize filters
		//if (this.filters != undefined)
		//	Filters.fill(this.filters);
		
		//Autocomplete.updateFromHTML();
		if (!dontRunRequest)
			this.request();
	}
	
	this.doSelect = function()
	{
		window.callback(this.currentEntity);
	}
	
	this.doReset = function()
	{
		this.filters.reset();
		this.page = 1;
		this.request();
	}
	
	this.doEdit = function()
	{
		var id = (this.currentRecordId) ? this.currentRecordId : "-1";
		var win = window.open(webRoot + this.controller + "/edit.do?render-mode=popup&id=" + id, this.controller+"editwindow","location=0,status=0,scrollbars="+this.options.editwindow_scrollbars+",resizable="+this.options.editwindow_resizable+",width=200,height=200,modal=yes");
		win.callback = function(entity) 
		{
			if (self.onItemSaved)
			{
				self.onItemSaved(entity);
			}
				
			self.request(false, function()
			{
				self.setPositionById(entity["id"])
				win.close();
			}); 
		};
			
	}
	
	this.filters.onFilterChange = this.doRefresh = function()
	{
		self.request(true);
	}
	
	// Override
	this.pager.onStateChanged = function() 
	{
		self.page = self.pager.currentPage; 
		self.request();
	};
}

// UnifiedBrowser

function UnifiedBrowser()
{
	Browser.call(this);
	
	this.parentActionQuery = this.getActionQuery;
	this.getActionQuery = function(actionName)
	{
		var query = "";
		if (actionName == "saveall" || actionName == "savebasket")
		{
			query = this.filters.getQueryString();
			this.mainDiv.find("*[@send]").each(function()
			{
				var value =  ($(this).attr('value') == undefined) ? "" : URLEncode($(this).attr('value'));
				query += "&" + $(this).attr('name') + "=" + value;
			});
		}
		else
			query = this.parentActionQuery();
		return query;
	}
	
	this.onSaveallSuccess = function()
	{
		this.request();
	}
	
	this.setValue = function(name, value)
	{
		this.currentBlock.find('[@name="'+name+'"]').attr('value', value);
	}

	this.getValue = function(name)
	{
		return this.currentBlock.find('[@name="'+name+'"]').attr('value');
	}
}

function Filters() 
{
	var self = this;
	this.scope = document;
	this.firstTime = true;
	
	// Internal non-DOM filters
	this.values = new Object();
	
	this.getQueryString = function()
	{
		_data = ""; 
		
		if (this.firstTime)
		{
			this.attachHandlers();
			for (key in getParams)
				if (key != "include")
				{
					_data += '&'+key+'='+getParams[key];
				}
			//this.reset();
			this.firstTime = false;
		}

		// Internal non-DOM filters
		for (var key in this.values)
			_data += '&'+key+'='+URLEncode(self.values[key]);
		
		$(this.scope).find('*[@filter]').each
			(
				function()
				{
					var value;
					
					if ($(this).attr('type') == "checkbox")
						if (!this.checked)
							return;
						else
							value = "checked";
					else
						value = $(this).attr('value');
						
					if (value != undefined && value != $(this).attr('prompt') && value != "")
					{
						if ( value != undefined ) {
							//value = value.replace(/^\s+|\s+$/g,"");
						}
						_data += '&'+$(this).attr('name')+'='+URLEncode(value.trim());
						$(this).addClass("highlighted");
					}
					else
						$(this).removeClass("highlighted");
				}
			);
		return _data;
	}

	this.getValue = function(name)
	{
		var target = $(this.scope).find('[@filter][@name="'+name+'"]');
		if (target.length > 0)
			return target.attr('value');
		else
			return this.values[name];
	}
	
	this.reset = function()
	{
		$(this.scope).find('[@filter]').attr('value', '');	
		$(this.scope).find('[@filter] input').attr('value', '');	
		$(this.scope).find('input[@filter][@type="checkbox"]').removeAttr('checked');
		$(this.scope).find('[@filter]').removeClass("highlighted");
	}

	this.setValue = function(name, value, title)
	{
		var filter = $(this.scope).find('[@filter][@name="'+name+'"]');
		var filterDOM = filter.get(0);
		
		if (filterDOM && filterDOM != 'undefined')
		{
			// This is a regular filter in DOM
			filter.attr('value', value);
			if (filterDOM.autocomplete)
				filterDOM.autocomplete.setValue(title);
			if (filterDOM.tagName.toLowerCase() == "a")
				filterDOM.innerHTML = title;
			if (filter.attr('type') == "checkbox")
				filter.attr('checked', true);
			filter.addClass("highlighted");
		}
		else
			this.values[name] = value;
		
	}
	
	this.attachHandlers = function()
	{
		$(this.scope).find('input[@filter]').keypress(
			function(e)
			{
				if ((e.which == 13) && (self.onFilterChange))
				{
					self.onFilterChange();
					e.stopPropagation();
					e.preventDefault();
					return false;
				}
			}
		);
		$(this.scope).find('input[@filter][@type="checkbox"]').change(
			function(e)
			{
				self.onFilterChange();	
			}
		);
		
		$(this.scope).find('select[@filter]').change(
				function(e)
				{
					self.onFilterChange();	
				}
			);
		
	}
}
