var LtBase = Class.extend({
	init : function( props ) {
		this.apply(props);
	},
	apply : function( props ) {
		for( var p in props ) { this[p] = props[p]; }
	}
});

var Lt = LtBase.extend({
	context : "",
	user: null,
	_cache : null,
	_userbillCache : null,
	announcementInterval : null,
	init: function( props ) {
		this._super(props);
		// Make this optional eventually
		this._cache = new Object();
		this._userbillCache = new Object();
	},
	action: function( value ) {
		if(!value.startsWith("/")) {
			value = "/" + value;
		}
		
		return this.context + value;
	},
	image: function( name ) {
		return this.context + "/images/" + name;
	},
	go: function( value ) {
		if(!value.startsWith("/")) {
			value = "/" + value;
		}
		
		window.location = this.context + value;
	},
	startup: function() {
		var me = this;
		$(window).ready(function(){
			// Start checker to find when session is stale
			setInterval( function() { 
				$.post( me.action( "sessionCheck" ), function(data) { 
					if( ! data.hasSession ) {
						logout();
					}
				});
			}, 65 * 60 * 1000 );
		});
	},
	// id : unique name of cache entry
	// action : name of action to get data 
	// params : optional request params
	// clear : ignore cache and post
	// callback : method with data returned
	request : function( params ) {
		if( ! ( "id" in params || "name" in params || "callback" in params ) ) {	
			if( "callback" in params )	params.callback(null);
			return ;
		}

		var me = this;
		var _f = function( data ) {
			me._cache[params.id] = data;
			params.callback(data);
		};
		
		if( "clear" in params ) {
			delete this._cache[params.id];
		}
		
		if( "id" in this._cache ) {
			params.callback( this._cache[this.params.id] );
		} else {
			if( "params" in params )
				$.post( this.go( params.name),params.params, _f );
			else
				$.post( this.go( params.name), _f );
		}
	},
	// Add 'bills' to the following 'users' watchlist
	// with the given priority
	watch : function( users, bills, priority, callback ) {
		$.post( LT.action("bill/watch"),
				$.param({ "usernames" : users, 
						  "billIds" : bills, 
						  "priority.id" : priority }),
				callback );
	},
	unwatch : function( username, bills, callback ) {
		$.post( LT.action("bill/unwatch"),
				$.param({ "usernames" : username, 
						  "billIds" : bills }),
				callback );
	},
	unshare : function ( username, resource, callback) {
		$.post( LT.action("resource/removeShareUserResource"),
				$.param({"username" : username,
					     "resourceId" : resource}),
				callback );
	},
	kill : function( bills, callback ) {
		var params = null;
		if(typeof bills == "Array") { params = $.param({ "billIds" : bids }); } 
		else { params = { "billIds" : bills }; }		
		
		$.post(LT.action("bill/kill"), params, callback );
	},
	unkill : function( bills, callback ) {
		var params = null;
		if(typeof bills == "Array") { params = $.param({ "billIds" : bids }); } 
		else { params = { "billIds" : bills }; }		
		
		$.post(LT.action("bill/unkill"), params, callback );
	},
	priority : function( username, bills, priority, callback ) {
		var params = (username==null) ? 
				$.param( { "priority.id" : priority, "billIds" : bills } ) :
				$.param( { "priority.id" : priority, "billIds" : bills, "user.id.username" : username } );			   
		
		$.post( LT.action("userbill/changePriority"), params, callback );
	},
	mailBills : function(preferredEmail, bills) {
		var params = $.param({"subject" : "Bill",
							  "from" : preferredEmail,
							  "billIds" : bills});
		$.post(LT.action('email/saveBillEMail'),
				params,
			 	function(data) {
				  LT.go('email/email?emailId=' + data.id);
		});
	},
	announcements : function( element, interval ) {
		if( interval==null || interval=="undefined" ) {
			interval=60000;
		}
		
		$(element).append("<div class=\"announcement-wrapper\"></div>");
		$(element).children(".announcement-wrapper").load( LT.action("announcement/list"), function() { } );
		this.announcementInterval =
			setInterval(function() { 
				$(element).children(".announcement-wrapper").load( LT.action("announcement/list"), function() { } );
			}, interval );
	},
	userbills : function( domId, params ) {
		var _params;
		if( this._userbillCache[domId]==null ) {
			_params = {
					"username" : params.username,
					"by" : params.by,
					"direction" : params.direction,
					"killed" : params.killed,
					"page" : params.page==null?0:params.page,
					"records" : params.records==null?35:params.records
			};
			
			// Bind events
			$("#" + domId).bind("userbill.changepage", { id : domId},
					function(event, page) {
				LT.userbills( event.data.id, { "page" : page } );
			});
		} else {
			_params = this._userbillCache[domId].params;
			for( entry in params ) {
				_params[entry] = params[entry];	
			}
		}
		
		if( _params.priorities!=null && _params.priorities.length==0 ) {
			delete _params.priorities;
		}
		
		this._userbillCache[domId] = { "params" : _params };
		
		$("#" + domId).html("<div class=\"watched-bills-region\" style=\"text-align: center;\"><img style=\"margin-top: 150px\" src=\"" + LT.image("loading-animated.gif") + "\" /></div>");
		$("#" + domId).load( LT.action("userbill/list"), $.param( _params ) );
		$("#" + domId).attr("type","userbill");
	}
});

/* Singleton Factory for all bill search methods */
var BillSearcher = {
		_cache : new Object(),
		prepare : function( areaid ) { // Use on region to get the element ready to recieve search results
			// Bind paging change events
			$("#" + areaid).bind("bill.changepage", { id : areaid},
					function(event, page) { BillSearcher.search( event.data.id, { "page" : page } );
			});
		},
		search : function ( areaid, params ) {
			var _params;
			if( this._cache[areaid]==null) {
				_params = {
					"text" : params.text,
					"page" : params.page,
					"records" : params.records,
					"number" : params.number,
					"filed" : params.filed,
					"start" : params.start,
					"end" : params.end,
					"includeBillText" : params.includeBillText,
					"includeTitle" : params.includeTitle,
					"includePurpose" : params.includePurpose,
					"sortField" : params.sortField,
					"sortDirection" : params.sortDirection,
					"billTypes" : params.billTypes
				};
			} else {
				_params = BillSearcher._cache[areaid].params;
				for( entry in params ) {
					_params[entry] = params[entry];	
				}
			}
			
			// Scrub params
			for( p in _params ) {
				if( _params[p]==null || _params[p]=='undefined') {
					delete _params[p];
				}
			}
			$("#"+areaid).html("<div style='text-align:center; padding-top: 150px'>" + 
					"<img width='400' src=\"" + LT.image("search/search-loader.gif") + "\" /></div>");
			BillSearcher._cache[areaid] = { "params" : _params };
			$("#"+areaid).load( LT.action("bill/search"), _params );
		},
		selected : function( areaid ) {
			var arr = new Array();
			$("#"+areaid).find("input:checked").each(function() { 
				arr.push( $(this).val() );
			});
			return arr;
		}
};

var ResourceFactory = {
		_cache : new Object(),
		prepare : function( areaid ) { // Use on region to get the element ready to recieve search results
			// Bind paging change events
			$("#" + areaid).bind("resource.changepage", { id : areaid},
					function(event, page) { ResourceFactory.load( event.data.id, { "page" : page } );
			});
		},
		load : function ( areaid, params ) {
			var _params;
			if( this._cache[areaid]==null) {
				_params = {
					"username" : params.username,
					"page" : params.page,
					"records" : params.records
				};
			} else {
				_params = ResourceFactory._cache[areaid].params;
				for( entry in params ) {
					_params[entry] = params[entry];	
				}
			}
			
			// Scrub params
			for( p in _params ) {
				if( _params[p]==null || _params[p]=='undefined') {
					delete _params[p];
				}
			}
			$("#"+areaid).html("<div style='text-align:center; padding-top: 150px'>" + 
					"<img src=\"" + LT.image("loading-animated.gif") + "\" /></div>");
			ResourceFactory._cache[areaid] = { "params" : _params };
			$("#"+areaid).load( LT.action("resource/list"), _params );
		},
		selected : function( areaid ) {
			var arr = new Array();
			$("#"+areaid).find("input:checked").each(function() { 
				arr.push( $(this).val() );
			});
			return arr;
		}
};

var UserTreeFactory = {
		init : function( treeid ) {
			// Bind events
			$("#"+treeid).find("input[name='username']").bind("click", function( event ) {
				$("#"+treeid).trigger("selection-changed");
			});
			
			if($("#"+treeid).has("[selection='single']") ) {
				$("#"+treeid).bind("change", { "tree" : $("#"+treeid) }, this._toggleSelectedSing );
			} else {
				$("#"+treeid).bind("change", this._toggleSelectedMult );
			}
			
			$("#"+treeid).find(".ut-filter>input").bind("focusout", function(event) { 
				if( $(event.currentTarget).val().trim()=="" ) { 
					$(event.currentTarget).removeClass("ut-filter-out").addClass("ut-filter-out");
					$(event.currentTarget).val("filter here"); 
				}
			});
			
			$("#"+treeid).find(".ut-filter>input").bind("focusin", function(event) { 
				if( $(event.currentTarget).val().trim()=="filter here" ) { 
					 $(event.currentTarget).val("");
					$(event.currentTarget).removeClass("ut-filter-out");
				}
			});
			$("#"+treeid).find(".ut-filter>input").focusout();
		},
		selected : function( treeid ) {
			var sel = new Array();
			$("#"+treeid).find("input[name='username']:checked").each(function() { 
				sel.push($(this).val());
			} );
			return nunique(sel);			
		},
		selectAll : function( treeid, on, event ) {
			if( on==null || on=="undefined" ) {
				on = $("#"+treeid).find(".ut-select-all>input").is(":checked");
			}
			if( event==null || event=="undefined" ) { event = true; }				
			
			var _vis = null;
			if(on) { _vis = function() { $(this).find("input[name='username']").attr("checked","checked").parent().removeClass("ut-selected").addClass("ut-selected"); };
			} else { _vis = function() { $(this).find("input[name='username']").removeAttr("checked").parent().removeClass("ut-selected"); }; }
			
			$("#"+treeid).find(".ut-user-element")
				.filter(function() { return !$(this).find("input[name='username']:disabled").length>0; }).each(_vis);
			
			if( event ) {	$("#"+treeid).trigger("selection-changed"); }
		},
		_toggleSelectedSing : function(event) {
			$(event.data.tree).find("input[name='username']").each(function() {
				if( $(this).is(":checked") ) {
					$(this).parent().removeClass("ut-selected").addClass("ut-selected");
				} else {
					$(this).parent().removeClass("ut-selected");
				}						
			});
		},
		_toggleSelectedMult : function(event) {
			if( $(event.currentTarget).is(":checked") &&
					$(event.currentTarget).parent().not(".ut-selected") ) {
				$(event.currentTarget).parent().addClass("ut-selected");
			} else {
				$(event.currentTarget).parent().removeClass("ut-selected");
			}
		},
		select : function( treeid, usernames, event ) {
			if( event==null ) { event=true; } 
			
			if( usernames instanceof Array ) 
			{ for( var i in usernames ) {
				if(usernames[i] instanceof String) {
					UserTreeFactory._select( treeid, usernames[i] );
				} else {
					UserTreeFactory._select( treeid, usernames[i].username );
				}
			} }
			else
			{ UserTreeFactory._select(treeid, usernames); }
			
			if( event ) {  $("#"+treeid).trigger("selection-changed"); }
		},
		_select : function( treeid, usernames ) {
			if( usernames instanceof Array ) {
				for( var i in usernames ) {
					UserTreeFactory._select( treeid, usernames[i] );
				}
			} 
			$("#"+treeid).find("input[name='username'][value='"+usernames+"']")
				.each(function(){  
					$(this).attr("checked","checked"); 
					if( $(this).parent().not(".ut-selected") ) {
						$(this).parent().addClass("ut-selected");
					}}); 
		},
		disable : function( treeid, usernames, fire ) {
			var ew = false;
			
			if( fire==null ) { fire=true; }
			
			if( usernames instanceof Array ) 
				{ for( var i in usernames ) { ew = UserTreeFactory._disable( treeid, usernames[i], false ); } }
			else 
				{ ew = UserTreeFactory._disable( treeid, usernames, false ); }
			
			if( fire && ew ) {  $("#"+treeid).trigger("selection-changed"); }
		},
		_disable : function( treeid, usernames ) {
			var ew = false;
			$("#"+treeid).find("input[name='username'][value='"+usernames+"']")
			.each(function(){  
				ew = true;
				$(this).removeAttr("checked"); 
				$(this).attr("disabled","disabled");
				$(this).parent().removeClass("ut-selected"); 
				$(this).parent().css({"opacity" : .5});
				if( $(this).parent().not(".ut-disabled") ) {
					$(this).parent().addClass("ut-disabled");
				}}); 
			return ew;
		},
		enable : function( treeid, usernames ) {
			if( usernames instanceof Array ) {
				for( var i in usernames ) {
					UserTreeFactory.enable( treeid, usernames[i] );
				}
			} 
			$("#"+treeid).find("input[name='username'][value='"+usernames+"']")
				.each(function(){  
					$(this).removeAttr("disabled");
					$(this).parent().css({"opacity" : 1});
					$(this).parent().removeClass("ut-disabled"); });
		},
		filter : function( treeid ) {
			var fs = $("#"+treeid).find(".ut-filter>input").val();
			
			$("#"+treeid).find(".ut-user-element")
				.each(function(){  
					if( $(this).find(".ut-text").html().toLowerCase().indexOf(fs)>-1 ) {
						// show
						$(this).removeClass("ut-hide");
					} else {
						$(this).removeClass("ut-hide").addClass("ut-hide");
					}});
		},
		listen : function( treeid, event, callback ) {
			$("#"+treeid).bind(event, callback);				
		}
};

var LtThrobber = LtBase.extend({
	container : null,
	init : function(props) {
		this._super(props);
		$(this["FRAME"]=document.createElement("div"))
			.addClass("ui-loader shadow ui-corner-all");
		this.content("<img src='" + LT.image("loading-animated.gif") + "' />");
		$(document.body).append(this["FRAME"]);
	},
	refresh : function() {
		var top = $(this.container).offset().top + 100;
		var left = $(this.container).offset().left;
		var t_w = $(this.container).width() / 2;
		var w = $(this.FRAME).width() / 2;
		$(this.FRAME).css( { "left" : left + t_w - w, "top" : top  } );
	},
	show : function() { 
		$(this["FRAME"]).show(); 
		this.refresh();
	},
	hide : function() { 
		$(this["FRAME"]).hide(); 
	},
	content : function( content ) { $(this["FRAME"]).html( content ); }
});

var LtItem = LtBase.extend({
	container : null,
	template : null,
	viewer : null,
	input : null,
	selectable: true,
	selectedTopic : null,
	init: function(props) {
		this._super(props);
		var me = this;
		
		this["ELEMENT"] = 
			$("#lt-templates").find("div[template='" + this.template + "']").clone()
				.removeAttr("template")
				.wrap("<div class='ez-box'></div>");
		
		if( this.selectable ) {
			this["SELECTOR"] = 
				$(this["ELEMENT"]).find(".ui-selector")
					.append("<input class='ui-selector-input' type='checkbox' />");
			$(this["SELECTOR"]).find(".ui-selector-input").bind("click", function(event){
				me.setSelected();
			});
		}
		
		if( this.viewer != null ) {
			$(this.viewer.container).append( this["ELEMENT"] );
		} else {
			$(this.container).append( this["ELEMENT"] );
		}
	},
	setInput: function(input) {
		this.input = input;
		this["ELEMENT"].data( "input", this.input );
		this.update();
	},
	update: function() { /* override me */ },
	setSelected: function( value ) {
		// If not value specified, toggle the selection
		if( value == null )
			value = !$(this["ELEMENT"]).hasClass("ui-selected");
		
		if( this.viewer != null ) {
			if( ! this.viewer.multi) {
				this.viewer.clear();
			}
		}
		
		if( value ) {
			this["ELEMENT"].addClass("ui-selected"); 
		} else {
			this["ELEMENT"].removeClass("ui-selected"); 
		}
		
		if( this.viewer != null ) {
			this.viewer.selectionChanged( this );
		} else if( this.selectedTopic != null ) {
			$.publish( this.selectedTopic );
		}
	}
});

var LtViewer = LtBase.extend({
	container : null,
	list : "data",
	action : null,
	params : null,
	selectionTopic : null,
	refreshTopic: null,
	completeTopic: null,
	_loader : null,
	usethrobber : false,
	multi: true,
	paged: false,
	pagerSelector: null,
	records: 50,
	page: 0,
	height: null,
	_results : 0,
	_latestRequest : null,
	init: function( props ) {
		this._super(props);
		
		var me = this;
		$(this["FRAME"] = document.createElement("div"))
		.addClass("ez-wr ui-viewer-content");
	
		if( this.height != null ) {
			$(this["FRAME"]).css({ "max-height" : this.height + "px", "height" : this.height + "px", "min-height" : this.height + "px",
				"overflow" : "auto", "overflow-y" : "auto", "overflow-x" : "auto" });
		} 
		
		// Create pager elements
		if( this.paged ) {
			$(this.pagerSelector).hide();
			$(this.pagerSelector).find(".pager-previous").bind("click", function() {
				me.page--;
				me.refresh();
			});
			
			$(this.pagerSelector).find(".pager-next").bind("click", function() {
				me.page++;
				me.refresh();
			});
		}
		
		if(this.refreshTopic != null ) {
			$.subscribe(this.refreshTopic, function() { 
				me.refresh(); 
			} );
		}
		
		$(this.container).append( this["FRAME"] );
		
		if( this.usethrobber ) {
			this._loader = new LtThrobber({ container : this["FRAME"] });
			this.loader("hide");
		}
	},
	loader : function( toggle ) {
		if( this._loader==null )	return ;
		if( toggle==null )	{
			this._loader.hide(); 
		} else if( toggle=="show") {
			this._loader.show();
		} else {
			this._loader.hide();
		}
		
	},
	_internalRefresh: function(data) {
		this.data = data;
		
		var j_items = data[this.list];
		this._results = 0;
		for( ji in j_items ) {
			if( this.filter( j_items[ji] ) ) {
				this._results++;
				var element = this.createElement();
				element.setInput( j_items[ji] );
				element.viewer = this;
				$(element["ELEMENT"]).addClass("ui-item");
			}
		}
		
		if( this.paged ) {
			this.updatePager();
		}
		
		this.loader("hide");
		
		if( this.completeTopic != null ) {
			$.publish(this.completeTopic);
		}
	},
	refresh: function( selection ) {
		if( this._latestRequest != null ) {
			this._latestRequest.abort();
			this._latestRequest = null;
		}
		if( this.paged ) {
			$(this.pagerSelector).hide();
		}
		
		var me = this;
		var _ref = function(data) {		
			$(me["FRAME"]).html("");
			me._internalRefresh(data);		
			if( selection != null )
				me.selected( selection );
		};
		
		this.loader("show");
		
		if( this.paged ) {
			this.params.records = this.records;
			this.params.page = this.page;
		}
		
		if( this.params != null) {
			this._latestRequest = $.post( LT.action( this.action ), this.params, _ref );
		}
		else { 
			this._latestRequest = $.post( LT.action( this.action ), _ref );
		}
	},
	updatePager: function() {
		if( this.data.page==null || this.data.total <= 0 ) {
			$(this.pagerSelector).hide();
			return ;
		}
		if( this.data.page==0 ) {
			$(this.pagerSelector).find(".pager-previous").hide();
		} else {
			$(this.pagerSelector).find(".pager-previous").show();
		}
		
		var to = this.data.total < ((this.data.page+1)*this.records) ? this.data.total :
			((this.data.page+1)*this.records);
		
		if( (this.data.page+1)*this.records > this.data.total ) {
			$(this.pagerSelector).find(".pager-next").hide();
		} else {
			$(this.pagerSelector).find(".pager-next").show();
		}
		
		this._results = this.data.total;
		
		$(this.pagerSelector).find(".pager-results")
			.html( "Showing " + ((this.data.page*this.records)+1) + " to " + 
				to + " of " + this.data.total );
		$(this.pagerSelector).show();		
	},
	createElement: function() {
		return "<div>Override Me</div>";
	},
	elementId: function(element) {
		return null; // Override this
	},
	filter : function( element ) { return true; },
	compareInput: function( i1, i2 ) { // This should be overridden
		return i1 == i2;
	},
	selected: function( selection, fireEvent ) {
		if( selection != null ) {
			if( typeof(selection)=="string") {
				var sn = new Array();
				sn.push( selection );
				selection = sn;
			}
			
			var me = this;
			$(this["FRAME"]).find(".ui-item").each(function(index) { 
				var input = $(this).data("input");
				for( s in selection ) {
					if( me.compareInput( selection[s], input ) ) {
						$(this).addClass("ui-selected");
						$(this).find(".ui-selector-input").attr("checked",true);
						break;
					}
				}
			});
			
			if( fireEvent ) this.selectionChanged(null);
			return this.selected();
		}
		
		var selected = new Array();
		$(this["FRAME"]).find(".ui-selected")
			.each(function(index){
				selected.push($(this).data("input"));
			});
		return selected;
	},
	selectedIds: function() {
		var selected = this.selected();
		var sids = new Array();
		for( s in selected ) {
			sids.push( this.elementId( selected[s] ) );
		}
		return sids;
	},
	clear: function( fireEvent ) { // Clear selection
		$(this["FRAME"]).find(".ui-item")
		.each(function(index){
			if( $(this).hasClass("ui-selected") ) {
				$(this).removeClass("ui-selected");
				$(this).find(".ui-selector-input").attr("checked",false);
			}
		});
		
		if( fireEvent != null && fireEvent )
			this.selectionChanged(null);
	},
	setParams: function( params ) {
		this.params = params;
		this.page = 0;
		this.refresh();
	},
	setAction: function( action, params ) {
		this.action = action;
		this.setParams(params);
	},
	selectionChanged: function( item ) {
		if( this.selectionTopic != null )
			$.publish( this.selectionTopic );	
	}
});

var LtTreeItem = LtBase.extend({
	template : null,
	viewer : null,
	input : null,
	parent: null,
	treeChildren: null,
	level: 0,
	expanded: false,
	selectable: true,
	selectedTopic : null,
	init: function(props) {
		this._super(props);
		
		var me = this;
		
		this["TREE_ELEMENT"] = 
			$("*[template='" + this.viewer.template + "']").clone()
				.removeAttr("template");
		
		if( this.parent != null ) {
			this.level = this.parent.level + 1;
			$(this["TREE_ELEMENT"]).css("margin-left", (this.level) + "em");
		}
		
		$(this["TREE_ELEMENT"]).find(".ui-tree-expander")
			.bind("click", function() { 
				if( me.expanded ) {
					me.viewer.collapse( me );
					me.expanded = false;
					$(me["TREE_ELEMENT"]).find(".ui-tree-expander")
						.attr("src", LT.image( "tree_plus.gif" ) );
				} else {
					me.viewer.expand( me );
					me.expanded = true;
					$(me["TREE_ELEMENT"]).find(".ui-tree-expander")
						.attr("src", LT.image( "tree_minus.gif") );
				}
			} );
		
		this["ELEMENT"] = 
			$("*[template='" + this.template + "']").clone()
				.removeAttr("template");
		
		if( this.selectable ) {
			this["SELECTOR"] = 
				$(this["ELEMENT"]).find(".ui-selector")
					.append("<input class='ui-selector-input' type='checkbox' />");
			$(this["SELECTOR"]).find(".ui-selector-input").bind("click", function(event){
				me.setSelected();
			});
		}
		
		$(this["TREE_ELEMENT"]).find(".ui-tree-content")
			.append(this["ELEMENT"]);
			
		$(this["TREE_ELEMENT"]).hide();
		
		if( this.parent != null ) {
			$(this.parent["TREE_ELEMENT"]).after( this["TREE_ELEMENT"] );
		} else {
			$(this.viewer["FRAME"]).append( this["TREE_ELEMENT"] );
		}
		
		if( this.parent == null )
			$(this["TREE_ELEMENT"]).show();
		else
			$(this["TREE_ELEMENT"]).slideDown(200);
		$(this["TREE_ELEMENT"]).data("handle",this);
	},
	setInput: function(input) {
		this.input = input;
		this["ELEMENT"].data( "input", this.input );
		if( this.input.users.length <= 0 ) {
			$(this["TREE_ELEMENT"]).find(".ui-tree-expander")
				.attr("src", LT.image("tree_blank.gif") )
				.css({ "cursor" : "default"})
				.unbind();
		}
		this.update();
	},
	update: function() { /* override me */ },
	remove: function() { 
		if( this.treeChildren != null ) {
			for( c in this.treeChildren ) {
				this.treeChildren[c].remove();
			}
		}
		var me = this;
		$(this["TREE_ELEMENT"]).slideUp(200, function() { $(this["TREE_ELEMENT"]).remove(); });
	},
	isSelected: function() {
		return $(this["ELEMENT"]).hasClass("ui-selected");		
	},
	setSelected: function( value ) {
		// If not value specified, toggle the selection
		if( value == null )
			value = !$(this["ELEMENT"]).hasClass("ui-selected");
		else if( value == this.isSelected() )
			return;
		
		if( this.viewer != null ) {
			if( ! this.viewer.multi) {
				this.viewer.clear();
			}
		}
		
		if( value ) {
			this["ELEMENT"].addClass("ui-selected"); 
		} else {
			this["ELEMENT"].removeClass("ui-selected"); 
		}
		
		if( this.viewer != null ) {
			this.viewer.selectionChanged( this );
		}
		
		if( this.selectedTopic != null ) {
			$.publish( this.selectedTopic );
		}
	}
});

var LtContentProvider = LtBase.extend({
	viewer : null,
	action : null,
	params : null,
	childList : null,
	init: function(props) {
		this._super(props);
	},
	elements: function( input ) { }
});

var LtPseudoTree = LtViewer.extend({
	childList : null,
	init : function( params ) {
		this._super( params );
		
	},
	_sort : function( e1, e2 ) { return 0 ; },
	_makeChildren: function( parent, input, depth ) {
		if( this.childList in input ) {
			var j_items = input[this.childList];
			
			if( j_items != null && j_items.length > 0) {
				j_items.sort( this._sort );
				for( ji in j_items ) {
					var element = this.createElement();
					var input = j_items[ji];
					element.setInput( input );
					element.viewer = this;
					element.parent = parent;
					$(element["ELEMENT"]).addClass("ui-item");
					$(element["ELEMENT"]).attr("level", depth);
					$(element["ELEMENT"]).css({ "padding-left" : (depth*16)+"px"});
					this._makeChildren( element, input, depth+1);
				}
			}
		}
	},
	selectedParentIds: function( global ) {
		var selected = $(this["FRAME"]).find(".ui-selected");
		var pids = new Array();
		var me = this;
		// For each selected element
		$(selected).each(function(){
			var level = $(this).attr("level")-1;
			for( i=level; i>=0; i-- ) {
				var m = $(this).prevAll("div[level='" + i + "']").first();
				var data = $(m).data("input");
				pids.push( me.elementId( data ) );
			}
		});
		
		return pids;
	},
	_internalRefresh: function(data) {
		this.data = data;
		
		var j_items = data[this.list];
		
		if( j_items != null && j_items.length > 0) {
			j_items.sort( this._sort );
			for( ji in j_items ) {
				var element = this.createElement();
				var input = j_items[ji];
				element.setInput( input );
				element.viewer = this;
				$(element["ELEMENT"]).addClass("ui-item");
				$(element["ELEMENT"]).css({ "padding-left" : "0px"});
				$(element["ELEMENT"]).attr("level", 0);
				this._makeChildren( element, input, 1);
			}
		}
		
		if( this.paged ) {
			this.updatePager();
		}
		
		this.loader("hide");
		
		if( this.completeTopic != null ) {
			$.publish(this.completeTopic);
		}
	}
});

var LtTree = LtBase.extend({
	container : null,
	list : "data",
	template : "tree-element",
	provider : null,	// Required
	selectionTopic : null,
	multi: true,
	usethrobber: true,
	_loader : null,
	init: function( props ) {
		this._super(props);
		this.provider.viewer = this;		
		
		$(this["FRAME"] = document.createElement("div"))
		.addClass("ez-wr ui-viewer-content");
	
		if( this.usethrobber ) {
			this._loader = new LtThrobber({ container : this["FRAME"] });
			this._loader.hide();
		}
	},
	_internalRefresh: function(data) {
		var j_items = data[this.list];
		for( ji in j_items ) {
			var element = this.createElement();
			element.setInput( j_items[ji] );
			$(element["TREE_ELEMENT"]).addClass("ui-tree-item");
		}
		this.loader("hide");
	},
	createElement: function( element ) {
		return "<div>Override Me</div>";
	},
	loader : function( toggle ) {
		if( this._loader==null )	return ;
		if( toggle==null )	{
			this._loader.hide(); 
		} else if( toggle="show") {
			this._loader.show();
		} else {
			this._loader.hide();
		}
		
	},
	selected: function() {
		var selected = new Array();
		// TODO Optimize Selector
		$(this["FRAME"]).find("div")
			.each(function(index){
				if( $(this).hasClass("ui-selected"))
					selected.push($(this).data("input"));
			});
		return selected;
	},
	clear: function() { // Clear selection
		$(this["FRAME"]).find("div")
		.each(function(index){
			if( $(this).hasClass("ui-selected") ) {
				$(this).removeClass("ui-selected");
				$(this).find(".ui-selector-input").attr("checked",false);
			}
		});
	},
	refresh: function() {
		var me = this;
		
		$(this["FRAME"]).children("div[.ui-tree-item]").remove();
		
		this._loader.show();
		
		var _ref = function(data) {		me._internalRefresh(data);		};
		this.provider.elements( { element: null, callback: _ref } );
	},
	expand: function( element ) {
		if( element.expanded )	return ;
		
		var me = this;
		
		var f = function(data) {
			var j_items = data[me.list];
			for( ji in j_items ) {
				var newElement = me.createElement( element );
				if( element.treeChildren==null ) {
					element.treeChildren = new Array();
				}
				element.treeChildren.push( newElement );
				newElement.setInput( j_items[ji] );
				$(newElement["TREE_ELEMENT"]).addClass("ui-tree-item");
			}
		};
		
		this.provider.elements( { element : element.input, callback : f } );
	},
	collapse: function( element ) {
		var me = this;
		if(element.treeChildren != null ) {
			for( c in element.treeChildren ) {
				element.treeChildren[c].remove();
			}
		}		
	},
	selectionChanged: function( item ) {
		if( this.selectionTopic != null )
			$.publish( this.selectionTopic );	
	}
});
