function LibraryManager( ) {
	this.url = "/webservice/librarymgr";
	this.metadataUrl = "/webservice/librarymeta";
	this.trunc = 10000;
	this.sort = 0;
	
	/** Sort values are
	NATURAL = 0;
	REVERSE_NATURAL_SORT = 1;
	TRACK_NAME_SORT = 6;
	REVERSE_TRACK_NAME_SORT = 7;
	ARTIST_NAME_SORT = 8;
	REVERSE_ARTIST_NAME_SORT = 9;
	ALBUM_NAME_SORT = 10;
	REVERSE_ALBUM_NAME_SORT = 11;
	**/
	this.mwidth = 10000;
	this.trackmwidth = 10000;
	this.albummwidth = 10000;
	this.artistmwidth = 10000;

	this.tracklist_trackmwidth = 10000;
	this.tracklist_albummwidth = 10000;
	this.tracklist_artistmwidth = 10000;
	
	this.doSort = function( theArray, theField, reverseOrder ) {
		theArray.sort( 
			function(a,b) {
				return (a[theField]>b[theField]) ? 1 : ( (a[theField]<b[theField]) ? -1 : 0 )
			} );
		if( reverseOrder ) { theArray.reverse(); }
		return theArray;
	}

	this.doFieldSort = function( theArray, theField, reverseOrder, callbackMethod ) {
		callbackMethod(this.doSort(theArray,theField,reverseOrder));
	}

	this.doTrackNumSort = function( theArray, reverseOrder, callbackMethod ) {

		theArray.sort( 
			function(a,b) {
				if( a["index"] > b["index"] ) return 1;
				else if( a["index"] < b["index"] ) return -1;
				else {
					if( a["discindex"] > b["discindex"] ) return 1;
					else if( a["discindex"] < b["discindex"] ) return -1;
					else {
						if( a["albumname"] > b["albumname"] ) return 1;
						else if( a["albumname"] < b["albumname"] ) return -1;
						else {
							return (a["artistdisplayname"]>b["artistdisplayname"]) ? 1 : ( (a["artistdisplayname"]<b["artistdisplayname"]) ? -1 : 0 )
						}
					}
				}
			} );

		if( reverseOrder ) { theArray.reverse(); }
		callbackMethod( theArray );
	}
	
	this.doDiscSort = function( theArray, reverseOrder, callbackMethod ) {

		theArray.sort( 
			function(a,b) {
				if( a["discindex"] > b["discindex"] ) return 1;
				else if( a["discindex"] < b["discindex"] ) return -1;
				else {
					if( a["index"] > b["index"] ) return 1;
					else if( a["index"] < b["index"] ) return -1;
					else {
						if( a["albumname"] > b["albumname"] ) return 1;
						else if( a["albumname"] < b["albumname"] ) return -1;
						else {
							return (a["artistdisplayname"]>b["artistdisplayname"]) ? 1 : ( (a["artistdisplayname"]<b["artistdisplayname"]) ? -1 : 0 )
						}
					}
				}
			} );

		if( reverseOrder ) { theArray.reverse(); }
		callbackMethod( theArray );
	}
	
	this.doAlbumSort = function( theArray, reverseOrder, callbackMethod ) {

		theArray.sort( 
			function(a,b) {
				if( a["albumname"] > b["albumname"] ) return 1;
				else if( a["albumname"] < b["albumname"] ) return -1;
				else {
					if( a["albumid"] > b["albumid"] ) return 1;
					else if( a["albumid"] < b["albumid"] ) return -1;
					else {
						if( a["discindex"] > b["discindex"] ) return 1;
						else if( a["discindex"] < b["discindex"] ) return -1;
						else {
							return (a["index"]>b["index"]) ? 1 : ( (a["index"]<b["index"]) ? -1 : 0 )
						}
					}
				}
			} );

		if( reverseOrder ) { theArray.reverse(); }
		callbackMethod( theArray );
	}

	this.doArtistSort = function( theArray, reverseOrder, callbackMethod ) {

		theArray.sort( 
			function(a,b) {
				if( a["artistdisplayname"] > b["artistdisplayname"] ) return 1;
				else if( a["artistdisplayname"] < b["artistdisplayname"] ) return -1;
				else {
					if( a["albumname"] > b["albumname"] ) return 1;
					else if( a["albumname"] < b["albumname"] ) return -1;
					else {
						if( a["discindex"] > b["discindex"] ) return 1;
						else if( a["discindex"] < b["discindex"] ) return -1;
						else {
							return (a["index"]>b["index"]) ? 1 : ( (a["index"]<b["index"]) ? -1 : 0 )
						}
					}
				}
			} );

		if( reverseOrder ) { theArray.reverse(); }
		callbackMethod( theArray );
	}

	this.messageCount = 0;
	this.messagesReceivedMapping = new Array();
	
	this.sendMessage = function(url, content, callback){
		
		var CURRENTMESSAGECOUNT = "" + (this.messageCount++);
		var MESSAGEMAPPING = this.messagesReceivedMapping;
		
		var wrappedCallback = function (requestObj, emptyData) {
			if( MESSAGEMAPPING[CURRENTMESSAGECOUNT]=="true" ) { return; }
			MESSAGEMAPPING[CURRENTMESSAGECOUNT] = "true";

			if(requestObj.status == 200){
				var text = requestObj.responseText;
				if (text.substring(0,2) == "[{"){
					var data = eval(text);
				}
				else {
					var data = eval('('+text+')');
				}
				callback(data);
			} else {
				var data = new Array();
				data.exception = new Array();
				data.exception.message="Bad response from ajax request. "
				data.exception.code=requestObj.status
				data.hasError=true;
				callback(data);
			}
		}
	
		var theParameters = content.toQueryString()+"&sort="+this.sort;
		theParameters += "&mwidth="+this.mwidth+"&albummwidth="+this.albummwidth+"&artistmwidth="+this.artistmwidth+"&trackmwidth="+this.trackmwidth;
		
		if( content.todo=="get-children" && content.type=="tra" ) {
			theParameters += "&tracklist_albummwidth="+this.tracklist_albummwidth+"&tracklist_artistmwidth="+this.tracklist_artistmwidth+"&tracklist_trackmwidth="+this.tracklist_trackmwidth;
		}

		new PeriodicalExecuter( function(pe) {
				if( MESSAGEMAPPING[CURRENTMESSAGECOUNT]!="true" ) {
					MESSAGEMAPPING[CURRENTMESSAGECOUNT] = "true";
					var data = new Array();
					data.hasError = true;
					callback(data);
				}
				MESSAGEMAPPING[CURRENTMESSAGECOUNT] = "true";

				// Need to stop this thread the first time through...
				pe.stop();

			}, 30 /* 30s */ );

		new Ajax.Request(url,{
			onSuccess: wrappedCallback,
			method: 'get',
			parameters: theParameters
		});
	}
	
	this.add = function ( ids, handler) {
		handler = this.getSynchHandler( handler );
		var action = "add";
		var content = $H({
			ids: ids,
			todo: action
		});
		var callback = function (data){
			handler(data);
		}
		this.sendMessage(this.url, content, callback);
	}
	
	this.remove = function (rcids, handler) {
		var action = "remove";
		var content = $H({
			todo: action,
			ids: rcids
		});
		var callback = function (data){
			handler(rcids);
		}
		this.sendMessage(this.url, content, callback);
	}				
	
	this.get = function (type, rcid, children, tiedToAction, handler) {
		if( tiedToAction ) { handler = this.getSynchHandler( handler ); }
		if (children) {
			var action = "get-children";
		} else {
			var action = "get";
		}
		var content = $H({
   		  todo: action,
   		  parent: rcid,
   		  type: type
  		  });
		var callback = function (data){
			handler(data);
		}
		this.sendMessage(this.url, content, callback);
		
	}
						
	this.getMeta = function (ids, childIds, handler) {
		handler = this.getSynchHandler( handler );
		var action = "get-metadata";
		var content = $H({
		    		  todo: action,
		    		  ids: ids,
		    		  childids: childIds
		    		  });
		var callback = function (data){
			handler(data);
		}
		this.sendMessage(this.metadataUrl, content, callback);
		
	}
	


	this.ACTIONID = 0;
	
	this.getSynchHandler = function( anotherHandler ) {
		var currentActionId = this.ACTIONID;
		var currentLibInstance = this;
		return function(data) {
			if( currentLibInstance.ACTIONID == currentActionId ) {
				anotherHandler(data);
			}
			else {
//				alert( "Ignoring response this.ACTIONID="+currentLibInstance.ACTIONID+" currentActionId="+currentActionId );
			}
		}
	};

	this.newAction = function() {
		this.ACTIONID ++;
	};
}


LibraryManager.prototype.setMwidth = function (mwidth) { this.mwidth = mwidth; }
LibraryManager.prototype.setTrackMwidth = function (mwidth) { this.trackmwidth = mwidth; }
LibraryManager.prototype.setAlbumMwidth = function (mwidth) { this.albummwidth = mwidth; }
LibraryManager.prototype.setArtistMwidth = function (mwidth) { this.artistmwidth = mwidth; }

LibraryManager.prototype.setTracklistTrackMwidth = function (mwidth) { this.tracklist_trackmwidth = mwidth; }
LibraryManager.prototype.setTracklistAlbumMwidth = function (mwidth) { this.tracklist_albummwidth = mwidth; }
LibraryManager.prototype.setTracklistArtistMwidth = function (mwidth) { this.tracklist_artistmwidth = mwidth; }




LibraryManager.prototype.getLibraryByType = function (type, handler) {
	this.get(type, null, null, true, handler);
}

LibraryManager.prototype.getChildrenByType = function (type, rcid, handler) {
	this.get(type, rcid, true, true, handler);
}

LibraryManager.prototype.getChildrenByTypeUntied = function (type, rcid, handler) {
	this.get(type, rcid, true, false, handler);
}

LibraryManager.prototype.getMetadata = function (ids, childIds, handler) {
	this.getMeta(ids, childIds, handler);
}

LibraryManager.prototype.setSort = function (sort) {
	this.sort = sort;
}



	
