dojo.require("dojo.cookie");
//dojo.require("dojo.event.*");


var tableData;
var queryLang;
//var libName = $C('NUID');
var libName = dojo.cookie('NUID') != null ? dojo.cookie('NUID') : "";
var collection = new Object();
var initialized = false;
var addQueue = new Array();
var activeGenreAlbumsInterval = false;
var waitCount = 0; // used in case tracks from existing playlists don't come down in sync 

function AddToLibrary( strIds, intType, doCheck, previouslyAddedTracks ) {
	//console.log("AddToLibrary strIds: " + strIds);
	if (dojo.cookie('SL') == 'VIS') {
		showVisitorPop();
		return;
	}
	if(typeof(doCheck) == "undefined") { doCheck = 0; }
	if(typeof(previouslyAddedTracks) == "undefined") { previouslyAddedTracks = 0; }
	var addedNew = false;
	var umessage = "";
	strIds = new String( strIds );
	// dojo.debug("AddToLibrary - " + strIds + ":" + intType);
	var itemIDs = strIds.split(",");
	if(itemIDs.length > 1) {
		if(itemIDs.length > 100) {
			leftoverIDs = itemIDs;
			itemIDs = leftoverIDs.splice(0, 100);
			leftoverIDs = leftoverIDs.join(",");
			previouslyAddedTracks += 100;
			addedNew = collection.store.addItems(itemIDs, intType, doCheck);
			AddToLibrary(leftoverIDs, intType, doCheck, previouslyAddedTracks);
			return;
		} else {
			addedNew = collection.store.addItems(strIds, intType, doCheck);
			//if(intType == 0) { umessage += (itemIDs.length + previouslyAddedTracks) + " "; }
			if(intType == 0) { 
				umessage += itemIDs.length + " " + itemMap[intType] + "s ";
			} else {
				umessage += itemMap[intType] + "s ";
			}
			previouslyAddedTracks = 0;
		}
	} else {
		addedNew = collection.store.addItem(strIds, intType, doCheck);
		//if(intType == 0) { umessage += "1 "; }
		umessage += itemMap[intType] + " ";
	}
	umessage += "added to your library"
	// dojo.debug("umessage");
	
	//MATTNOTE: hack this for now - capitalize first char
	umessage = umessage.substring(0,1).toUpperCase() + umessage.substring(1);
	
	displayUMessage(umessage, 2, "add");
	// SiteCatalyst Tracking
	var scSaveVarsStr = 's.eVar1="Save"; s.eVar3=s.pageName;'; 
	if(typeof(top.libDrag) != "undefined" && top.libDrag > 0) {
		scSaveVarsStr += 's.eVar2="Drag";';
		top.libDrag = 0;
	}
	else {
		scSaveVarsStr += 's.eVar2="Button";';
	}
	if( itemIDs.length > 1 && intType == 0 ){
		scSaveVarsStr += 's.eVar5="MultipleTracks";';
	}
	else{
		if( intType == 0 ) {
			scSaveVarsStr += 's.eVar5="Track";';
		}
		else if( intType == 1 ) {
			scSaveVarsStr += 's.eVar5="Album";';
		}
		else if( intType == 2 ) {
			scSaveVarsStr += 's.eVar5="Playlist";';
		}
		else if( intType == 6) { // check on this...
			scSaveVarsStr += 's.eVar5="Playlist";';
		}
	}
	$SCEG( 'ContentAction',scSaveVarsStr);
	if(intType != 2 && intType != 6) {
		if((doCheck && addedNew) || !doCheck) { refreshLibrary(0,0); }
	}
}

function refreshLibrary(refresh_content,refresh_playlists) {
	/* dojo.storage.clear(); */
	tableData = "";
	ARTISTS = "";
	TRACKS = "";
	initialized = false;
	collection.store.initialize(refresh_content,refresh_playlists);
//	libraryDisplay.initialize();
}

function html_escape(inputString) {
	if(inputString != null && inputString != "") {
		inputString = new String(inputString);
		var chars = new Array (
			'&','<','>');
		var entities = new Array (
			'amp','lt','gt');
		
		newString = inputString;
		for (var i = 0; i < chars.length; i++) {
			myRegExp = new RegExp();
			myRegExp.compile(chars[i],'g')
			newString = newString.replace (myRegExp, '&' + entities[i] + ';');
		}
		return newString;
	} else {
		return inputString;
	}
}

collection.store = {
	initialize: function(refresh_content,refresh_playlists,signing_out) {
		// dojo.debug("collection.store running...");
		this.connectSQL();
		var results;
		try {
			results = dojox.storage.get(libName);
		}
		catch(e) {
			// try and remove the bad item
			try {
				dojox.storage.removeItem(libName);
			}
			catch(e) {
				// nuclear option :)
				dojox.storage.clear();
			}
		}
		// dojo.debug("collection.store libName is: " + libName);
		// dojo.debug("collection.store results are: " + results);
		var self = this;
                // figure out the sync string for collection, can be used in both cases
                var syncStr = "";
                syncStr += $CollMgr('ADDTRACKS') ? "&tracks=" + $CollMgr('ADDTRACKS') : "";
                syncStr += $CollMgr('ADDALBUM') ? "&albums=" + $CollMgr('ADDALBUM') : "";
                syncStr += $CollMgr('ADDWORK') ? "&works=" + $CollMgr('ADDWORK') : "";
                syncStr += $CollMgr('DELTRACKS') ? "&delete=" + $CollMgr('DELTRACKS') : "";

                // figure out the sync string for collection
                var plSyncStr = "";
                plSyncStr += $CollMgr('ADDPL') ? "&pl_up=" + $CollMgr('ADDPL') : "";
                plSyncStr += $CollMgr('DELPL') ? "&pl_del=" + $CollMgr('DELPL') : "";

                // we're always gonna pull down last played, so this can be global
                var lpArgs = "";
                /*if($CollMgr('PLAYS')) {
                    lpArgs = {
                        url: "http://home.gb.napster.com/cgi-bin/sync_lastplays.cgi?ids=" + $CollMgr('PLAYS'),
                        mimetype: "text/plain",
                        load: function(type, jsonData, evt) {
                        	// dojo.debug("lpArgs load running...");
                            self.appendPlaysTable(jsonData);
                            self.saveData(libName,tableData.toSource());
                            // dojo.debug("libraryDisplay.initialize - lpArgs pre-run...");
                            libraryDisplay.initialize();
                            collection.mgr.clear('PLAYS');
                        }
                    };
                }*/
		if(signing_out && syncStr == "" && plSyncStr == "") { // if we're signing out and don't have anything to sync, return
			initialized = true;
			return;
		}
		if (results == null || results == "") {
		// we need to pull the data
			var self = this;
			var libraryArgs= {
				url: "http://home.gb.napster.com/cgi-bin/sync_collection.cgi?down_sync=1&last_sync=01-JAN-1970%2012:00:01" + syncStr,
				mimetype: "text/plain",
				error: function( error ) {
					var msg = "libraryArgs BIND FAILED:\n" + error.message;
					console.log(msg);
				}, 
				load: function(jsonData, evt) {
					// console.log("results nul - libraryArgs load running...");
					//clear the collection sync cookies
					collection.mgr.clear('ADDTRACKS');
					collection.mgr.clear('ADDALBUM');
					collection.mgr.clear('ADDWORK');
					collection.mgr.clear('DELTRACKS');
					self.buildTable(jsonData);
					dojo.xhrGet(plArgs);
				}
			};
			var plArgs= {
				url: "http://home.gb.napster.com/cgi-bin/sync_playlists.cgi?down_sync=1&last_sync=01-JAN-1970%2012:00:01",
				mimetype: "text/plain",
				error: function( error ) {
					var msg = "plArgs BIND FAILED:\n" + error.message;
					console.log(msg);
				}, 
				load: function(jsonData, evt) {
					// console.log("results nul - plArgs load running...");
					self.addPLToTable(jsonData);
					// dojo.debug("results nul - plArgs load - lpArgs: " + lpArgs);
					// dojo.io.bind(libraryArgs);
					if(lpArgs) {
						// console.log("dojo.xhrGet(lpArgs); - plArgs null results pre-run...");
						dojo.xhrGet(lpArgs);
					}
					else {
						//danComment//self.saveData(libName,tableData.toSource());
						self.saveData(libName,runToSource(tableData));
						// dojo.debug("libraryDisplay.initialize - plArgs null results pre-run...");
						libraryDisplay.initialize();
					}
				}
			};
			// dojo.xhrGet(plArgs);
			dojo.xhrGet(libraryArgs);
			// MRR initialized = true;
		} else {
			try { // check to make sure we have a working local storage
				tableData = eval(results);
				//alert(runToSource(tableData));
			} catch(e) { // if it's bad, clear it and try again
				//console.log("Bad results, clearning and trying again.");
				console.log("Bad results, clearning and trying again.");
				results = null;
				try {
					dojox.storage.remove(libName);
				} catch(e2) {
					dojox.storage.clear();
				}
				collection.store.initialize();
				return;
			}
			// build the table with existing info
                        //testing some stuff
                        //var testData = new dataObj(results);
                        //alert(testData.toSource());
			var lastsync = tableData?tableData.LASTSYNC:0;
			if(!lastsync) { lastsync = ""; }
		// we need to pull the updates
			var self = this;
			var libraryArgs= {
				url: "http://home.gb.napster.com/cgi-bin/sync_collection.cgi?down_sync=1&last_sync=" + lastsync + syncStr,
				mimetype: "text/plain", 
				error: function( error ) {
					var msg = "libraryArgs -2 BIND FAILED:\n" + error.message;
					console.log(msg);
				}, 
				load: function(syncData, evt) {
					// clear collection sync cookies
					collection.mgr.clear('ADDTRACKS');
					collection.mgr.clear('ADDALBUM');
					collection.mgr.clear('ADDWORK');
					collection.mgr.clear('DELTRACKS');
					self.updateTable(syncData);
					if(lpArgs) {
						dojo.xhrGet(lpArgs);
					} else {
						//danComment//self.saveData(libName,tableData.toSource());
						self.saveData(libName,runToSource(tableData));
						// dojo.debug("libraryDisplay.initialize - lpArgs non null pre-run...");
						libraryDisplay.initialize(refresh_playlists);
					}
				}
			};
			var plArgs= {
				url: "http://home.gb.napster.com/cgi-bin/sync_playlists.cgi?down_sync=1&last_sync=" + lastsync + plSyncStr,
				mimetype: "text/plain", 
				error: function( error ) {
					var msg = "plArgs -2 BIND FAILED:\n" + error.message;
					console.log(msg);
				}, 
				load: function(jsonData, evt) {
					collection.mgr.clear('ADDPL');
					collection.mgr.clear('DELPL');
					self.updatePLTable(jsonData);
					dojo.xhrGet(libraryArgs);
				}
			};
			dojo.xhrGet(plArgs);
		}
		// MRR initialized = true;
		if(refresh_content) { refreshContent(); }
	},

	saveData: function(key,jsonData) {
		//fix for the funny toSource method at bottom of file
		if(jsonData.indexOf("(") != 0) {
			//append parens onto string to make compatible
			jsonData = "(" + jsonData + ")";
		}
		try { dojox.storage.remove(key); } catch(e) { console.log("failed on dojox.storage.remove(" + key + ")");}
		libraryStorage._save(key,jsonData);
	},

	updateTable: function(syncData) {
		var syncObj = eval("(" + syncData + ")");
		console.log("updateTable(" + syncData + ")");
		// loop in the artists
		var syncArtists = syncObj.ARTISTS;
			//danComment//dojo.debug("syncArtists: " + syncArtists.toSource());
			// dojo.debug("syncArtists: " + runToSource(syncArtists));
		var syncTracks = syncObj.TRACKS;
                //add "" to cast as a string
		var delTracks = ("" + syncObj.DELETEDTRACKS).split(",");
		if(syncArtists && syncArtists.length) {
			for(var a = 0; a < syncArtists.length; a++) {
				var statement = queryLang.parseSQL(
				"SELECT ARTISTS.* " +
				"FROM ARTISTS " + 
				"WHERE ARTISTS.id = ?",[ syncArtists[a].id ]
				); 
				// Here we run the query...
				var result = statement.filter(tableData);
				if(result.length < 1) { // didn't find duplicate
					tableData.ARTISTS[tableData.ARTISTS.length] = syncArtists[a];
				}
			}
		}
		if(syncTracks && syncTracks.length) {
			//danComment//dojo.debug("syncTracks: " + syncTracks.toSource());
			// dojo.debug("syncTracks: " + runToSource(syncTracks));
			// dojo.debug("syncTracks.length: " + syncTracks.length);
			for(var t = 0; t < syncTracks.length; t++) {
				//danComment//dojo.debug("syncTracks[t]: " + syncTracks[t].toSource());
				// dojo.debug("syncTracks[t]: " + runToSource(syncTracks[t]));
				var statement = queryLang.parseSQL(
				"SELECT TRACKS.* " +
				"FROM TRACKS " + 
				"WHERE TRACKS.id = ?", [ syncTracks[t].id ]
				); 
				// Here we run the query...
				var result = statement.filter(tableData);
				if(result.length < 1) { // didn't find duplicate
					//danComment//dojo.debug("result: " + result.toSource());
					// dojo.debug("result: " + runToSource(result));
					tableData.TRACKS[tableData.TRACKS.length] = syncTracks[t];
				} else {
					//danComment//dojo.debug("found result: " + result.toSource());
					// dojo.debug("found result: " + runToSource(result));
				}
			}
		}
		//deal with deleted tracks
		var la = "";
		if(tableData.LASTADDED) {
			try {
				la = tableData.LASTADDED.split(",")
			} catch(e) {
				la = new Array(tableData.LASTADDED);
			}
		}
		
		// dojo.debug("delTracks: " + delTracks);
		if(delTracks && delTracks != "") {
			for(var d in delTracks) {
				this._deleteTrack(delTracks[d]);
				// we also need to get rid of it out of the "last added" array
				for(var l = 0; l < la.length; l++) {
					if(delTracks[d] == la[l]) {
						// this is a real array, so we can splice
						var dla = la.splice(l,1);
					}
				}
			}
		}
		// put the last added string back
		try{
			if(la && la != "") {
				if (typeof(la[0]) != "undefined") {
					try {
						tableData.LASTADDED = la.join(",");
					} catch(e) {
						tableData.LASTADDED = la[0];
					}
				}
			} else {
				tableData.LASTADDED = "";
			}
		} catch(e1) {
			alert(e1.message);
			tableData.LASTADDED = "";
		}

		// update last sync time
		tableData.LASTSYNC = syncObj.LASTSYNC;
		// push whatever newest tracks onto the front of the LASTADDED array
		var addedTracks = (syncObj.LASTADDED ? syncObj.LASTADDED + ',' : "") + tableData.LASTADDED;
		var addedArr = (addedTracks.split(",")).splice(0,200);
		tableData.LASTADDED = addedArr.join(",");
		delete syncObj;
		initialized = true;
		if(addQueue != "") { this.processQueue(addQueue); }
	},
	
	processQueue: function(queueToProcess) {
		// dojo.debug("processQueue(" + queueToProcess + ")");
		// addQueue = new Array();
		var processArray = new Array();
		for(l = 0; l < queueToProcess.length; l++) { // Gather up all items of like types
			queueItem = queueToProcess.pop();
			// typeof(processArray[queueToProcess[l][1]]) == "undefined"?processArray[queueToProcess[l][1]] = queueToProcess[l][0] : processArray[queueToProcess[l][1]] += "," + queueToProcess[l][0];
			typeof(processArray[queueItem[1]]) == "undefined"?processArray[queueItem[1]] = queueItem[0] : processArray[queueItem[1]] += "," + queueItem[0];
		}
		for(l = 0; l < processArray.length; l++) {
			if(typeof(processArray[l] != "undefined")) {
				// dojo.debug("addItems(" + processArray[l] + "," + l + ")");
				this.addItems(processArray[l],l);
			}
		}
		// alert(processArray);
	},

	buildTable: function(jsonData) {
		tableData = eval("(" + jsonData + ")");
		// we don't need deleted tracks in original build
		delete tableData.DELETEDTRACKS;
		initialized = true;
	},

	addPLToTable: function(plData) {
		var plObj = eval("(" + plData + ")");
		tableData.PLAYLISTS = plObj.ADD_PL;
		delete plObj;
	},

	updatePLTable: function(plData) {
		var syncObj = eval("(" + plData + ")");

		var syncAdds = syncObj.ADD_PL;
		var syncDels = syncObj.DEL_PL;
		
		if(syncAdds || syncDels) { //only run the updates if we have stuff in the return
			for(var a = 0; a < syncAdds.length; a++) {
				var statement = queryLang.parseSQL(
				"SELECT PLAYLISTS.* " +
				"FROM PLAYLISTS " + 
				"WHERE PLAYLISTS.id = ?",[ syncAdds[a].id ]
				); 
				// Here we run the query...
				var result = statement.filter(tableData);
				if(result.length < 1) { // didn't find duplicate
					tableData.PLAYLISTS[tableData.PLAYLISTS.length] = syncAdds[a];
				}
				else { // we found dupe, so we need to update, which has to be done on
						// the object level (TrimPath SQL doesn't do it)
					for(l = 0; l < tableData.PLAYLISTS.length; l++) {
						if(tableData.PLAYLISTS[l].id == syncAdds[a].id) {
							// overwrite the playlist with the sync'd data
							tableData.PLAYLISTS[l] = syncAdds[a];
						}
					}
				}
			}
			// run the deletes
			for(var d = 0; d < syncDels.length; d++) {
				this._deletePlaylist(syncDels[d].id);
			}
			// update last sync time
			tableData.LASTSYNC = syncObj.LASTSYNC;
		} else {
			console.log('no playlists to update');
		}
		delete syncObj;
	},

	appendPlaysTable: function(data) {
		var playsData =eval("(" + data + ")");
		if(!tableData.PLAYS) {
			tableData.PLAYS = playsData.PLAYS;
		}
		else {
			// we need to reverse the in data so we can add it on last to first 
			for(p = playsData.PLAYS.length - 1; p >= 0; p--) {
				tableData.PLAYS.unshift(playsData.PLAYS[p]);
			}
		}
	},

	connectSQL: function() {
		var columnDefs = {
		TRACKS: { id: { type: "Number" },
			n: { type: "String" },
			aid: { type: "Number" },
			ln: { type: "String" },
			lid: { type: "Number" },
			o: { type: "Number" }, 
			d: { type: "Number" },
			x: { type: "String" },
			gid: { type: "Number" } },
		ARTISTS: { id: { type: "Number" },
			n: { type: "String" } },
		PLAYLISTS: { id: { type: "Number" },
			n: { type: "String" },
			nsort: { type: "String" },
			desc: { type: "String" },
			tracks: { type: "String" } },
		PLAYS: { id: { type: "Number" },
			n: { type: "String" },
			an: { type: "String" },
			aid: { type: "Number" },
			ln: { type: "String" },
			lid: { type: "Number" },
			o: { type: "Number" }, 
			d: { type: "Number" },
			x: { type: "String" } }
		};
	    // First we precompile the query language object with the schema...
	    queryLang = TrimPath.makeQueryLang(columnDefs);
	},

	getArtists: function(sort) {
		var statement = queryLang.parseSQL(
		"SELECT ARTISTS.* " +
		"FROM ARTISTS " + 
		"ORDER BY ARTISTS.n DESC"
		); 

		// Here we run the query...
		var result = statement.filter(tableData);
		if(!sort || sort.toUpperCase() == 'ASC') {
			// this is done because of a weird bug that breaks sort with big array
			// will look at it later	
			result = result.reverse();
		}
		return result;
	},

	getGenres: function(sort) {
		var statement = queryLang.parseSQL(
		"SELECT TRACKS.gid " +
		"FROM TRACKS " + 
		"GROUP BY TRACKS.gid " +
		"ORDER BY TRACKS.gid ASC"
		); 
		// Here we run the query...
		var result = statement.filter(tableData);
		// alert(result.toSource());
		return result;
	},

	getPlaylists: function(sort) {
		for(var i=0; i<tableData.PLAYLISTS.length; i++) {
			var nsortVal = new String(tableData.PLAYLISTS[i].n).toUpperCase(); // Add case-insensitive sort field
			tableData.PLAYLISTS[i].nsort = nsortVal;
		}
		
		var statement = queryLang.parseSQL(
		"SELECT PLAYLISTS.* " +
		"FROM PLAYLISTS " + 
		"ORDER BY PLAYLISTS.nsort DESC"
		);
		
		// Here we run the query...
		var result = statement.filter(tableData);
		if(!sort || sort.toUpperCase() == 'ASC') {
			// this is done because of a weird bug that breaks sort with big array
			// will look at it later	
			result = result.reverse();
		}
		return result;
	},

	getRecentTracks: function(disp,ret,append,term) {
		if(initialized) {
			// get tracks	
			var statement = queryLang.parseSQL(
			"SELECT PLAYS.* " +
			"FROM PLAYS" 
			); 
			var recent = statement.filter(tableData);
			if(recent.length > 0) {
			var intCount = 0;
			var objDate = new Date();
			var startTime = objDate.getTime();
			var self = this; 
			var resultData = new Array();
			var initialReturn = 0;
			var objInterval = setInterval( function(){
			var trackData = new Object();
			trackData['artist_name'] = recent[intCount]['an'];
			trackData['artist_name_sort'] = trackData['artist_name'];
			trackData['artist_id'] = recent[intCount]['aid'];
			trackData['album'] = recent[intCount]['ln'];
			trackData['album_sort'] = trackData['album'];
			trackData['album_id'] = recent[intCount]['lid'];
			trackData['track'] = recent[intCount]['n'];
			trackData['track_sort'] = trackData['track'];
			trackData['track_id'] = recent[intCount]['id'];
			trackData['duration'] = recent[intCount]['d'];
			trackData['explicit'] = recent[intCount]['x'];
			trackData['track_number'] = recent[intCount]['o'];
					resultData[resultData.length] = trackData;
					intCount++;
					if(resultData.length >= disp) {
							var data = resultData;
							//empty out result data
							resultData = new Array();
							if(initialReturn < 1) {
									eval(ret);
									initialReturn++;
							}
							else {
									eval(append);
							}
					}
					if( intCount >= recent.length ){
						// do this to pick up remainder
						var data = resultData;

						//empty out result data
						resultData = new Array();
						if(data.length > 0) {
							if(initialReturn < 1) {
									eval(ret);
									initialReturn++;
							}
							else {
									eval(append);
							}
						}
						clearInterval( objInterval );
						eval(term);
					}
			}, 1 );
			}
			else {
			var data = '0';
				eval(ret);
				eval(term);
			}
		} else {
			alert("not initialized!");
		}
	},

	getArtistTracks: function(aid,sort,key,artistRef,filter_type,filter_key) {
		//define sort
		var sortDef = new Array();
		sortDef['default'] = "ORDER BY TRACKS.ln, TRACKS.o";
		sortDef['track_name'] = "ORDER BY TRACKS.n";
		sortDef['album_name'] = sortDef['default'];
		var sortOrder = sort ? " " + sort.toUpperCase() : "";
		var sortKey = key ? key : 'default';
		
		//define filter
		var filterSQL = "";
		if(filter_type && filter_key) {
			if(filter_type == "genre") { filterSQL = "AND TRACKS.gid = " + filter_key + " "; }
		}
		//get artist
		var artists = "";
		if(artistRef) {
			artists = artistRef;
		}
		else {
			var statement = queryLang.parseSQL(
			"SELECT ARTISTS.* FROM ARTISTS WHERE ARTISTS.id = ?", [ aid ]);
			var artistsArr = statement.filter(tableData);
			artists = artistsArr[0];
		}
		// now get tracks	
		var statement = queryLang.parseSQL(
		"SELECT TRACKS.* " +
		"FROM TRACKS " + 
		"WHERE TRACKS.aid = ? " +
		filterSQL +
		sortDef[sortKey] + sortOrder , [ aid ]
		); 
		var result = statement.filter(tableData);
		var tracks = new Array();
		for (var r = 0; r < result.length; r++) {
			var resultTmp = new Object();
			resultTmp['artist_name'] = artists['n'];
			resultTmp['artist_name_sort'] = resultTmp['artist_name'];
			resultTmp['artist_id'] = artists['id'];
			resultTmp['album'] = result[r]['ln'];
			resultTmp['album_sort'] = resultTmp['album'];
			resultTmp['album_id'] = result[r]['lid'];
			resultTmp['track'] = result[r]['n'];
			resultTmp['track_sort'] = resultTmp['track'];
			resultTmp['track_id'] = result[r]['id'];
			resultTmp['duration'] = result[r]['d'];
			resultTmp['explicit'] = result[r]['x'];
			resultTmp['track_number'] = result[r]['o'];
			tracks[tracks.length] = resultTmp;
		}
		return tracks;	
	},

	getAlbumTracks: function(lid,sort,key,artistRef) {
	/*
                //define sort
                var sortDef = new Array();
                sortDef['default'] = "ORDER BY TRACKS.ln, TRACKS.o";
                sortDef['track_name'] = "ORDER BY TRACKS.n";
                sortDef['album_name'] = sortDef['default'];
                var sortOrder = sort ? " " + sort.toUpperCase() : "";
                var sortKey = key ? key : 'default';
                //get artist
		var artists = "";
		if(artistRef) {
			artists = artistRef;
		}
		else {
			var statement = queryLang.parseSQL(
			"SELECT ARTISTS.* FROM ARTISTS WHERE ARTISTS.id = ?", [ aid ]);
			var artistsArr = statement.filter(tableData);
			artists = artistsArr[0];
		}
	*/
		// get tracks	
		var statement = queryLang.parseSQL(
		"SELECT TRACKS.* " +
		"FROM TRACKS " + 
		"WHERE TRACKS.lid = ? " +
		"ORDER BY TRACKS.id ", [ lid ]
		);
		var result = statement.filter(tableData);
		
		var tracks = new Array();
		for (var r = 0; r < result.length; r++) {
			var resultTmp = new Object();
			resultTmp['artist_name'] = this.getArtistName(result[r]['aid']);
			resultTmp['artist_name_sort'] = resultTmp['artist_name'];
			resultTmp['artist_id'] = result[r]['aid'];
			resultTmp['album'] = result[r]['ln'];
			resultTmp['album_sort'] = resultTmp['album'];
			resultTmp['album_id'] = result[r]['lid'];
			resultTmp['track'] = result[r]['n'];
			resultTmp['track_sort'] = resultTmp['track']
			resultTmp['track_id'] = result[r]['id'];
			resultTmp['duration'] = result[r]['d'];
			resultTmp['explicit'] = result[r]['x'];
			resultTmp['track_number'] = result[r]['o'];
			tracks[tracks.length] = resultTmp;
		}
		return tracks;	
	},

	getArtistName: function(aid) {
		//get playlist
		var statement = queryLang.parseSQL(
		"SELECT ARTISTS.* FROM ARTISTS WHERE ARTISTS.id = ?", [ aid ]);
		var arArr = statement.filter(tableData);
		if(arArr != "") {
			return arArr[0].n;
		} else {
			return "";
		}
	},

	getTrackFromColl: function(tid) {
		var resultTmp = new Object();
		var statement = queryLang.parseSQL(
		"SELECT TRACKS.* " +
		"FROM TRACKS " + 
		"WHERE TRACKS.id = ?", [ tid ]
		);

		var result = statement.filter(tableData);
		if(result.length > 0) {
			var tRes = result[0];
			//pull the artist name (joins are too slow)
			var artistStatement = queryLang.parseSQL(
			"SELECT ARTISTS.n " +
			"FROM ARTISTS " + 
			"WHERE ARTISTS.id = ?", [ tRes['aid'] ]
			);
			var artist = artistStatement.filter(tableData);

			resultTmp.artist_name = artist[0]['n'];
			resultTmp.artist_name_sort = resultTmp.artist_name;
			resultTmp.artist_id = tRes['aid'];
			resultTmp.album = tRes['ln'];
			resultTmp.album_sort = resultTmp.album;
			resultTmp.album_id = tRes['lid'];
			resultTmp.track = tRes['n'];
			resultTmp.track_sort = resultTmp.track;
			resultTmp.track_id = tRes['id'];
			resultTmp.duration = tRes['d'];
			resultTmp.explicit = tRes['x'];
			resultTmp.track_number = tRes['o'];
		} else {
			resultTmp = null;
		}
		return resultTmp;
	},

	getPlaylistData: function(pid) {
		//get playlist IDs
		var statement = queryLang.parseSQL(
		"SELECT PLAYLISTS.* FROM PLAYLISTS WHERE PLAYLISTS.id = ?", [ pid ]);
		var plArr = statement.filter(tableData);
		
		return plArr;
	},

	getPlaylistTracks: function(pid) {
		//get playlist
		var plArr = this.getPlaylistData(pid);
		var tracks = new Array();
		var tracksToRemove = false;
		if(!plArr[0].tracks) {
			// work out with Mark what to send back for 0 results
			return tracks;	
		}
		plTIDs = ("" + plArr[0].tracks).split(",");
		// now get tracks	
		for (var p = 0; p < plTIDs.length; p++) {
			var track = new Array();
			// if(plTIDs[p].indexOf(":") != 0) {
			if(isNaN(plTIDs[p])) {
				track["track_id"] = plTIDs[p];
				track["album_id"] = 0;
			} else {
				track = this.getTrackFromColl(plTIDs[p]);
			}
			if(!(track)) {
				tracksToRemove = true;
			} else {
				if(typeof(track.album_id) == "undefined") { //this is necessary to avoid the expense of removing tracks from playlists on delete
					dojo.debug(plTIDs[p] + " is not in library");
					tracksToRemove = true;
				} else {
					tracks[tracks.length] = track;
				}
			}
		}
					
		if(tracksToRemove) { //we have some tracks in our playlist that aren't in our library anymore and we need to remove them
			// alert("Tracks to Remove" - tracks.toSource());
			var plTracksList = new Array();
			for (var r = 0; r < tracks.length; r++) {
				plTracksList.push(tracks[r].track_id);
			}
			this.updatePlaylist(pid,plTracksList,0,0,this.getPlaylistName(pid));
		}
		
		return tracks;	
	},

	getPlaylistName: function(pid) {
		//get playlist
		var statement = queryLang.parseSQL(
		"SELECT PLAYLISTS.* FROM PLAYLISTS WHERE PLAYLISTS.id = ?", [ pid ]);
		var plArr = statement.filter(tableData);
		if(plArr == "") {
			// console.log(tableData);
			this.initialize();
		} else {
			if(typeof(plArr[0]) != undefined) { return plArr[0].n; } else { return ""; }
		}
	},

	getAllTracks: function(disp,ret,append,term) {
		// dojo.debug("allTracks - " + allTracks);
		if(!(initialized)) { setTimeout("collection.store.getAllTracks(" + disp + "," + ret + "," + append + "," + term + ")", 500); return ""; }
		// get artist first
		var statement = queryLang.parseSQL(
		"SELECT ARTISTS.* " + 
		"FROM ARTISTS " +
		"ORDER BY ARTISTS.n ASC" 
		);
		var artists = (!allArtists ? statement.filter(tableData) : allArtists);
		var intCount = 0;
		var objDate = new Date();
		var startTime = objDate.getTime();
		var self = this; 
		var resultData = new Array();
		var initialReturn = 0;
		if(artists.length > 0) {
		var objInterval = setInterval( function(){
			var artistTracks = self.getArtistTracks(artists[intCount]['id'],'','',artists[intCount]);
			resultData = resultData.concat(artistTracks);
			intCount++;
			if(resultData.length >= disp) {
				var data = resultData;
				//empty out result data
				resultData = new Array();
				if(initialReturn < 1) {
					eval(ret);
					initialReturn++;
				}
				else {
					eval(append);
				}
			}
			if( intCount == artists.length ){
				// do this to pick up remainder
				var data = resultData;
				//empty out result data
				resultData = new Array();
				if(initialReturn < 1) {
					eval(ret);
					initialReturn++;
				}
				else {
					eval(append);
				}
				clearInterval( objInterval );
				eval(term);

			}
		}, 1 );
            }
            else {
				console.log("ret: " + ret);
				console.log("term: " + term);
                data = '0';
                eval(ret);
                eval(term);
            }
		// dojo.debug("allTracks - " + allTracks);
	},
	
	_safeSendText: function(inText) {
		inText = inText.toString(); //convert our input text to a string
		var safeText = inText.replace(/'/g, "\\\'"); //escape all single quotes
		return safeText;
	},

	getGenreAlbums: function(disp,ret,append,term) {
		if(!(initialized)) { setTimeout("collection.store.getGenreAlbums(" + disp + "," + ret + "," + append + "," + term + ")", 500); return; }
		var self = this;
		// var t = new Date();
		// dojo.debug("entering getGenreAlbums - " + t);
		try {
			var statement = queryLang.parseSQL(
			"SELECT TRACKS.* " + 
			"FROM TRACKS " +
			"ORDER BY TRACKS.ln ASC" 
			);
			var tracksArr = statement.filter(tableData);
		} catch(sqlError) {
			console.log(sqlError.message);
		}
		
		genreList = this.getGenres();
		allGenres = genreList;
		var genreAlbumArr = new Array();
		
		for (var r = 0; r < genreList.length; r++) {
			genreList[r]['gid'] == "" || undefined ? genreID = 0 : genreID = genreList[r]['gid'];
			genreAlbumArr[genreID] = new Array();
		}
		var r = 0;
		// for (var q = 0; q < tracksArr.length; q++) {
		var q=0;
		dojo.byId("libraryGenres").innerHTML = "<ul><li><span>loading...</span></li></ul>";
		if(!activeGenreAlbumsInterval) {
			activeGenreAlbumsInterval = true;
			genreAlbumsInterval = setInterval( function(){
				if(q < tracksArr.length) {
					tracksArr[q]['gid'] == "" ? genreID = 0 : genreID = tracksArr[q]['gid'];
					var artistID = "_" + tracksArr[q]['aid'];
					var albumID = "_" + tracksArr[q]['lid'];
					// dojo.debug(genreID + " " + artistID + " " + albumID + " " + albumName);
					if(typeof(genreAlbumArr[genreID]) != "undefined") {
						if(typeof(genreAlbumArr[genreID][artistID]) == "undefined") {
							var artistName = self.getArtistName(tracksArr[q]['aid']);
							genreAlbumArr[genreID][artistID] = artistName;
						}
					} else {
						console.log(genreID + " not found in genreAlbumArr.");
					}
					// dojo.debug(genreAlbumArr[genreID][artistID][albumID]);
					q++
				} else {
					// return(genreAlbumArr);
					activeGenreAlbumsInterval = false;
					clearInterval(genreAlbumsInterval);
					// dojo.debug("genreAlbumsInterval - " + q + " | tracksArr.length - " + tracksArr.length);
					dojo.byId("libraryGenres").innerHTML = dump(genreAlbumArr);
					downList(dojo.byId("libraryGenres"));
				}
			}, 1);
		}
		t = new Date();
		// dojo.debug("exiting getGenreAlbums - " + t);
	},

	OLDgetGenreAlbums: function(disp,ret,append,term) {
		// dojo.debug("in getGenreAlbums");
		try {
			var statement = queryLang.parseSQL(
			"SELECT TRACKS.* " + 
			"FROM TRACKS " +
			"ORDER BY TRACKS.ln ASC" 
			);
			
			/*
			"SELECT TRACKS.* " + 
			"FROM TRACKS " +
			"ORDER BY TRACKS.ln ASC" 
			
			"JOIN ARTISTS.* " +
			"ON TRACKS.aid = ARTISTS.id " +
			*/
			var tracksArr = statement.filter(tableData);
		} catch(sqlError) {
			console.log(sqlError.message);
		}
		
		genreList = this.getGenres();
		var genreAlbumArr = new Array();
		
		for (var r = 0; r < genreList.length; r++) {
			genreList[r]['gid'] == "" || undefined ? genreID = 0 : genreID = genreList[r]['gid'];
			genreAlbumArr[genreID] = new Array();
		}
		for (var q = 0; q < tracksArr.length; q++) {
			tracksArr[q]['gid'] == "" ? genreID = 0 : genreID = tracksArr[q]['gid'];
			var artistID = "_" + tracksArr[q]['aid'];
			var albumID = "_" + tracksArr[q]['lid'];
			var albumName = tracksArr[q]['ln'];
			// dojo.debug(genreID + " " + artistID + " " + albumID + " " + albumName);
			try {
				genreAlbumArr[genreID][artistID][albumID] = albumName;
			} catch(e) {
				genreAlbumArr[genreID][artistID] = new Array();
				genreAlbumArr[genreID][artistID][albumID] = albumName;
			}
			// dojo.debug(genreAlbumArr[genreID][artistID][albumID]);
		}
		return(genreAlbumArr);
	},

	getArtistAlbums: function(aid,genre) {
		// dojo.debug("in getGenreAlbums");
		try {
			if(genre) {
				var statement = queryLang.parseSQL(
				"SELECT TRACKS.* " + 
				"FROM TRACKS " +
				"WHERE TRACKS.aid = " + aid + " " +
				"AND TRACKS.gid = " + genre + " " +
				"ORDER BY TRACKS.ln ASC");
			} else {
				var statement = queryLang.parseSQL(
				"SELECT TRACKS.* " + 
				"FROM TRACKS " +
				"WHERE TRACKS.aid = " + aid + " " +
				"ORDER BY TRACKS.ln ASC");
			}
			var tracksArr = statement.filter(tableData);
		} catch(sqlError) {
			console.log(sqlError.message);
		}
		var artistAlbumArr = new Array();
		for (var q = 0; q < tracksArr.length; q++) {
			var artistID = "_" + tracksArr[q]['aid'];
			var albumID = "_" + tracksArr[q]['lid'];
			var albumName = tracksArr[q]['ln'];
			artistAlbumArr[albumID] = albumName;
		}
		return(artistAlbumArr);
	},

	getAddedTracks: function(disp,ret,append,term) {
		var lastAdded = tableData.LASTADDED.split(",");
		var intCount = 0;
		var objDate = new Date();
		var startTime = objDate.getTime();
		var self = this; 
		var resultData = new Array();
		var initialReturn = 0;
		if(lastAdded[0].length > 0) {//check to see if we've got an empty string
		loadContent("http://home.gb.napster.com/info/fragments/last_added.html", "content_head");
		var objInterval = setInterval( function(){
				var trackData = self.getTrackFromColl(lastAdded[intCount]);
				resultData[resultData.length] = trackData;
				intCount++;
				if(resultData.length >= disp) {
						var data = resultData;
						//empty out result data
						resultData = new Array();
						if(initialReturn < 1) {
								eval(ret);
								initialReturn++;
						}
						else {
								eval(append);
						}
				}
				if( intCount == lastAdded.length ){
					// do this to pick up remainder
					var data = resultData;

					//empty out result data
					resultData = new Array();
					if(data.length > 0) {
						if(initialReturn < 1) {
								eval(ret);
								initialReturn++;
						}
						else {
								eval(append);
						}
					}
					clearInterval( objInterval );
					eval(term);
				}
		}, 1 );
		addedTracks = data;
		}
		else {
		var data = '0';
			eval(ret);
			eval(term);
		}

	},
	
	uniquePlaylistName: function(pName) {
		var origName = pName;
		var i = 0;
		for (var r = 0; r < allPlaylists.length; r++) {
			if(html_escape(pName) == html_escape(allPlaylists[r]['n'])) {
				i++;
				pName = origName + ' (' + i + ')';
				if(i >= 10) { r = 0; }
			}
		}
		return pName;
	},
	
	getNewTracksNotInLocalCollection: function(trackIDsUpArr, trackIDsReturnArr, checkLocalCollection) {
		var self = this;
		var debugThis = false;
		if(debugThis) { console.log("in getNewTracksNotInLocalCollection"); }
		if(typeof(checkLocalCollection) == "undefined") { checkLocalCollection = 1 };
		
		var trackID = 0;
		var unmatchedTracks = new Array();
		for(i in trackIDsUpArr) {
			if(typeof(trackIDsUpArr[i]) != "function") {
				trackID = trackIDsUpArr[i];
				var match = 0;
				if(checkLocalCollection) {
					if(self.getTrackFromColl(trackID) != null) {
						match = 1;
					}
				}
				if(!match) {
					for(j in trackIDsReturnArr) {
						if(trackID == trackIDsReturnArr[j]) {
							match = 1;
							if(debugThis) { console.log("found a match for id " + trackID); }
							trackIDsReturnArr.splice(j,1); // remove the match from our array
							break;
						}
					}
					if(!match) {
						if(debugThis) { console.log("no match for id " + trackID); }
						unmatchedTracks[unmatchedTracks.length] = trackIDsUpArr[i];
					}
				}
			}
		}
		if(unmatchedTracks.length) {
			return unmatchedTracks;
		} else {
			return 0;
		}
	},
	
	forceTracksIntoLocalCollection: function(trackIDs, checkLocal) {
		var debugThis = false;
		if(debugThis) {
			console.log("in forceTracksIntoLocalCollection(trackIDs, checkLocal):");
			console.log(trackIDs);
			console.log(checkLocal);
		}
		if(!(initialized)) { 
			if(debugThis) {
				console.log("not initialized, waiting to retry.");
			}
			setTimeout("collection.store.forceTracksIntoLocalCollection([" + trackIDs + "]," + checkLocal + ")", 500); return "";
		}
		
		var self = this;
		if(typeof(checkLocal) == "undefined") { checkLocal = 1; }
		var forceSyncURL = "http://home.gb.napster.com/cgi-bin/sync_collection.cgi?down_sync=1&last_sync=" + encodeURI(tableData.LASTSYNC) + "&force=1&tracks=";
		if(checkLocal) {
			var unmatchedTracks = new Array();
			for(i in trackIDs) {
				if(typeof(trackIDs[i]) != "function") {
					if(self.getTrackFromColl(trackIDs[i]) == null) {
						unmatchedTracks[unmatchedTracks.length] = trackIDs[i];
					}
				}
			}
			trackIDs = unmatchedTracks;
		}
		trackIDsString = trackIDs.join();
		if(trackIDsString != "") {
			forceSyncURL += trackIDsString;
			
			var trackSync = {
				url: forceSyncURL,
				mimetype: "text/plain",
				transport: "XMLHTTPTransport",
				error: function(type, errObj){ if(debugThis) { console.log("Data Bind Failed"); console.log(errObj); } },
				load: function(type, jsonData, evt) {
					if(debugThis) { console.log(jsonData); }
					self.updateTable(jsonData);
					self.saveData(libName,runToSource(tableData));
					libraryDisplay.initialize();
				}
			};
			
			if(debugThis) { console.log("about to hit: " + forceSyncURL); }
			dojo.xhrGet(trackSync);
		} else {
			if(debugThis) { console.log("nothing to add"); }
		}
	},
	
	getTrackIDsFromSyncData: function(syncData) {
		var debugThis = false;
		if(debugThis) { console.log("In getTrackIDsFromSyncData:"); console.log(syncData); }
		var returnArray = new Array();
		try {
			var syncReturn = eval('(' + syncData + ')');
			if(typeof(syncReturn.TRACKS != "undefined") && syncReturn.TRACKS != []) {
				var tracksReturn = syncReturn.TRACKS;
			}
			for(i in tracksReturn) {
				if(typeof(tracksReturn[i]) != "function") {
					returnArray[returnArray.length] = tracksReturn[i].id;
				}
			}
		} catch(e) {
		}
		if(debugThis) { console.log(returnArray); }
		return returnArray;
	},

	createPlaylist: function(name,content,contentType) {
		var debugThis = false;
		if(debugThis) {
			console.log("In createPlaylist(name, content, contentType)");
			console.log(name);
			console.log(content);
			console.log(contentType);
		}
		if(typeof(contentType) == "undefined") { contentType = '0'; }
		type = contentType;
		var self = this;
		name = self.uniquePlaylistName(name);
		// dojo.debug("in createPlaylist(" + name + "," + tracks + ")");
		// name = this._safeSendText(html_escape(name));
		// name = dojo.string.encodeAscii(name);
		// alert(name);
		// string is status,plid,name,desc,genre,tracks
		var addStr = "&pl_up=added||" + name + "||-1||" + (content ? (content + "|" + type) : "");
		var syncURL = "http://home.gb.napster.com/cgi-bin/sync_playlists.cgi?down_sync=1&last_sync=" + tableData.LASTSYNC + encodeURI(addStr);
		var libSyncURL = "http://home.gb.napster.com/cgi-bin/sync_collection.cgi?down_sync=1&last_sync=" + tableData.LASTSYNC;
		// syncURL = encodeURI(syncURL);
		var plID = 0;
		
		console.log("createPlaylist rollcall " + name + ", " + content + ", " + contentType);
		
		var libraryArgs= {
			url: libSyncURL,
			mimetype: "text/plain", 
			error: function( error ) {
				var msg = "libraryArgs -3 BIND FAILED:\n" + error.message;
				console.log(msg);
			}, 
			load: function(jsonData, evt) {
				// console.log("results nul - libraryArgs load running...");
				if(debugThis) { console.log("loaded data from: " + libSyncURL); console.log(jsonData); }
				//clear the collection sync cookies
				collection.mgr.clear('ADDTRACKS');
				collection.mgr.clear('ADDALBUM');
				collection.mgr.clear('ADDWORK');
				collection.mgr.clear('DELTRACKS');
				
				var newTracksArr = new Array();
				/* If we have a list of tracks, loop over it and build an array of tracks we don't have in our library */
				content = "" + content + "";
				var contentArray = content.split(",");
				var tracksToSync = 0;
				if(debugThis) { console.log(content); }
				if(contentArray.length && contentType == 0) {
					var tracksReturnIDs = self.getTrackIDsFromSyncData(jsonData);
					tracksToSync = self.getNewTracksNotInLocalCollection(contentArray, tracksReturnIDs, 1);
				}
				
				self.updateTable(jsonData);
				self.saveData(libName,runToSource(tableData));
				if(tracksToSync) {
					if(debugThis) { console.log("tracksToSync:"); console.log(tracksToSync); }
					self.forceTracksIntoLocalCollection(tracksToSync, 0);
				} else {
					allArtists = [];
					libraryDisplay.writeAllArtists();
				}
				return plID;
			}
		};
		var plArgs= {
				url: syncURL,
				mimetype: "text/plain", 
				error: function( error ) {
					var msg = "plArgs -3 BIND FAILED:\n" + error.message;
					console.log(msg);
				}, 
				load: function(jsonData, evt) {
					try{
						var added = eval("(" + jsonData + ")"); 
						self.updatePLTable(jsonData);
						self.saveData(libName,runToSource(tableData));
						allPlaylists = "";
						libraryDisplay.writeAllPlaylists();
						plID = added.ADD_PL[0]['id'];
						dojo.xhrGet(libraryArgs);
					} catch(e) {
						if(debugThis) { console.log(e.message); }
					}
					// return plID;
				}
		};
		dojo.xhrGet(plArgs);
	},

	saveExistingPlaylist: function(plid,type) {
		/*var i = 0;
		for (var r = 0; r < allPlaylists.length; r++) {
			if(html_escape(name) == html_escape(allPlaylists[r]['n'])) {
				i++;
				name = origName + ' (' + i + ')';
				if(i >= 10) { r = 0; }
			}
		}*/
		/* TODO - DEAL WITH NAME COLLISION */
		// type map
		plType = new Array();
		plType[2] = 'A';
		plType[6] = 'U';
		// dojo.debug("in saveExistingPlaylist(" + plid + "," + plType[type] + ")");
		// name = this._safeSendText(html_escape(name));
		// name = dojo.string.encodeAscii(name);
		// alert(name);
		// string is status,plid,name,desc,genre,tracks
		var saveStr = "&pl_save=" + plid + "||" + plType[type];
		var self = this;
		var syncURL = "http://home.gb.napster.com/cgi-bin/sync_playlists.cgi?down_sync=1&last_sync=" + tableData.LASTSYNC + encodeURI(saveStr);
		// syncURL = encodeURI(syncURL);
		var SPplArgs= {
				url: syncURL,
				mimetype: "text/plain", 
				error: function( error ) {
					var msg = "SPplArgs BIND FAILED:\n" + error.message;
					console.log(msg);
				}, 
				load: function(jsonData, evt) {
					var added = eval("(" + jsonData + ")"); 
					self.updatePLTable(jsonData);
					plID = added.ADD_PL[0]['id'];
					allPlaylists = "";
					libraryDisplay.writeAllPlaylists();
					//alert('done writing playlists');
					dojo.xhrGet(SPlibraryArgs);
				}
		};
		var SPlibraryArgs= { // we need to do this to pull new tracks from existing playlists,
							//don't deal with clearing collmgr cookies
			url: "http://home.gb.napster.com/cgi-bin/sync_collection.cgi?down_sync=1&last_sync=" + tableData.LASTSYNC,
			mimetype: "text/plain",
			error: function( error ) {
				var msg = "SPlibraryArgs BIND FAILED:\n" + error.message;
				console.log(msg);
			},
			load: function(syncData, evt) {
				// clear collection sync cookies
				self.updateTable(syncData);
				// check to make sure that we've got all the tracks (race condition in DB)
				var savePL = self.getPlaylistData(plID);
				var plTIDs = savePL[0].tracks.split(",");
				var tracksToSync = 0;
				
				if(plTIDs.length) {
					tracksToSync = self.getNewTracksNotInLocalCollection(plTIDs, new Array(), 1);
				}
				self.saveData(libName,runToSource(tableData));
				if(tracksToSync) {
					self.forceTracksIntoLocalCollection(tracksToSync, 0);
				} else {
					libraryDisplay.initialize();
				}
			}
		};
		dojo.xhrGet(SPplArgs);
	},

	addTracksToPlaylist: function(plid,track) {
		this.addContentToPlaylist(plid,0,track);
	},
	
	addContentToPlaylist: function(plid,type,content) {
		var statement = queryLang.parseSQL(
		"SELECT PLAYLISTS.* " + 
		"FROM PLAYLISTS " +
		"WHERE PLAYLISTS.id = ?" ,[ plid ] 
		);
		var plData = statement.filter(tableData);
		var tracks = "";
		if(plData[0].tracks != null) { tracks = new String(plData[0].tracks); }
		var plTracks = tracks.indexOf(",") == -1 ? new Array(tracks) : tracks.split(",");
		this.updatePlaylist(plid,plTracks,content,type,this.getPlaylistName(plid),0);
	},

	updatePlaylist: function(plid,tracklist,new_content,new_type,name,refresh) {
		var debugThis = false;
		var self = this;
		if(debugThis) {
			console.log("in updatePlaylist(plid,tracklist,new_content,new_type,name,refresh)");
			console.log(plid);
			console.log(tracklist);
			console.log(new_content);
			console.log(new_type);
			console.log(name);
			console.log(refresh);
		}
		if(new_content == 0 || new_content == "") {
			if(debugThis) { console.log("no new content"); }
			if(typeof(refresh) == "undefined") { refresh = 1 } // set refresh to be on by default 
			var statement = queryLang.parseSQL(
			"SELECT PLAYLISTS.* " + 
			"FROM PLAYLISTS " +
			"WHERE PLAYLISTS.id = ?" ,[ plid ] 
			);
			var plData = statement.filter(tableData);
			plData[0].tracks = tracklist.join(",");
			plData[0].n = name ? name : plData[0].n;
			for(l = 0; l < tableData.PLAYLISTS.length; l++) {
				if(tableData.PLAYLISTS[l].id == plid) {
					// overwrite the playlist with the updated data
					tableData.PLAYLISTS[l] = plData[0];
				}
			}
			//shove the update in the add cookie
			var modStr = "modified|" + plid + "|" + plData[0].n + "|" + plData[0].desc + "|-1|" + plData[0].tracks + "$$";
			// $CollMgr("ADDPL",modStr);
			this.saveData(libName,runToSource(tableData));
			collection.mgr.addItem(modStr,2);
		} else {
			if(debugThis) { console.log("have new content"); }
			//alert("updatePlaylist(" + plid + "|" + tracklist + "|" + new_content + "|" + new_type + "|" + name + "|" + refresh + ")");
			if(typeof(refresh) == "undefined") { refresh = 1 } // set refresh to be on by default 
			var statement = queryLang.parseSQL(
			"SELECT PLAYLISTS.* " + 
			"FROM PLAYLISTS " +
			"WHERE PLAYLISTS.id = ?" ,[ plid ] 
			);
			var plData = statement.filter(tableData);
			plData[0].tracks = tracklist.join(",");
			plData[0].n = name ? name : plData[0].n;
			for(l = 0; l < tableData.PLAYLISTS.length; l++) {
				if(tableData.PLAYLISTS[l].id == plid) {
					// overwrite the playlist with the updated data
					tableData.PLAYLISTS[l] = plData[0];
				}
			}
			//shove the update in the add cookie
			var modStr = "modified|" + plid + "|" + plData[0].n + "|" + plData[0].desc + "|-1|" + plData[0].tracks + "|" + new_content + "|" + new_type + "$$";
			if(debugThis) { console.log(modStr); }
			// $CollMgr("ADDPL",modStr);
			this.saveData(libName,runToSource(tableData));
			collection.mgr.addItem(modStr,2);
			initialized = false;
			collection.store.initialize();
			if(new_type == 0) {
				if(debugThis) {
					console.log("about to forceTracksIntoLocalCollection:");
					console.log(new_content);
				}
				self.forceTracksIntoLocalCollection(new_content, 1);
			} else {
				if(debugThis) { console.log("new_type:"); console.log(new_type); }
			}
		}
		if(refresh) { libraryDisplay.displayTracksFromPlaylist(plid,plData[0].n); }
	},

	updateCurrentPlaylist: function(refresh) {
		console.log("start updateCurrentPlaylist");
		if(typeof(refresh) == "undefined") { refresh = false; }
		var rowArr = dojo.byId("listReturnBody").getElementsByTagName("tr");
		var currentPlaylistTrackIDs = new Array();
		if(rowArr.length) {
			for(var i=0; i<rowArr.length; i++) {
				currentPlaylistTrackIDs.push(rowArr[i].id.substring(1));
			}
			this.updatePlaylist(currentPlaylistID, currentPlaylistTrackIDs, 0, 0, currentPlaylistName, 0);
		}
		if(refresh) { refreshContent(); }
	},
	
	sortServerSide: function(key) {
		
		try {
			activeDisplay = "";
			locationHash = getLocationHash();
			currentUrl = documentRoot + locationHash.substring(1);
			sortUrl = currentUrl;
			uriObj = parseUri(currentUrl);
			
			if(typeof(uriObj.queryKey["sortby"]) == "undefined") {
				uriObj.queryKey["sortby"] = "artist_name";
			}
			if(typeof(uriObj.queryKey["sortdir"]) == "undefined") {
				uriObj.queryKey["sortdir"] = "asc";
			}
			
			if((uriObj.queryKey["sortby"] == key) && uriObj.queryKey["sortby"]) {
				uriObj.queryKey["sortdir"] = uriObj.queryKey["sortdir"]=="asc"?"desc":"asc";
			} else {
				uriObj.queryKey["sortdir"] = "asc";
			}
			
			uriObj.queryKey["sortby"] = key;
			
			sortUrl = unParseUri(uriObj);
			
			navigate(sortUrl);
		} catch(e) {
			console.log(e.message);
		}
	},

	sortDisplay: function(data,sort,key) {
		// if(key == "track_name") { key = "track"; }
		// if(key == "track_name_sort") { key = "track_sort"; }
		// danComment - var dataStr = data.toSource();
		var dataStr = runToSource(data);
		// dojo.debug(sort + ", " + key + ", " + dataStr);
		try {
			var sortTable = eval("({SORT:" + dataStr + "})");
		} catch(e) {
			alert(e.message);
			console.log(dataStr);
			return;
		}
		/* old sort columns - 
		SORT: { artist_name: { type: "String" },
				artist_id: { type: "Number" },
				album_name: { type: "String" },
				album_id: { type: "Number" },
				track_name: { type: "String" },
				track_id: { type: "Number" },
				album_order: { type: "Number" }, 
				duration: { type: "Number" },
				explicit: { type: "String" } }
		}; 
		var sortDef = new Array();
		sortDef['artist_name'] = "ORDER BY SORT.artist_name";
		sortDef['track_name'] = "ORDER BY SORT.track_name";
		sortDef['album_name'] = "ORDER BY SORT.album_name, SORT.album_order"; */
		var sortColumnDefs = {
		SORT: { artist_name: { type: "String" },
				artist_name_sort: { type: "String" },
				artist_id: { type: "Number" },
				album: { type: "String" },
				album_sort: { type: "String" },
				album_id: { type: "Number" },
				track: { type: "String" },
				track_sort: { type: "String" },
				track_name: { type: "String" },
				track_name_sort: { type: "String" },
				track_id: { type: "Number" },
				duration: { type: "Number" },
				duration_sort: { type: "Number" },
				track_number: { type: "Number" },
				trackNumber: { type: "Number" },
				streamable: { type: "Number" },
				explicit: { type: "String" },
				sm_image_url: { type: "String" },
				image_url: { type: "String" },
				release_date: { type: "Number" },
				release_year: { type: "Number" },
				video_id: { type: "Number" },
				peak_position: { type: "Number" },
				peak_date: { type: "Number" },
				weeks_on_chart: { type: "Number" },
				can_download: { type: "Number" },
				can_purchase: { type: "Number" },
				can_download: { type: "Number" },
				can_download: { type: "Number" }
			}
		};
		var sortDef = new Array();
		sortDef['artist_name'] = "ORDER BY SORT.artist_name_sort, SORT.track";
		sortDef['track_name'] = "ORDER BY SORT.track_sort";
		sortDef['album_name'] = "ORDER BY SORT.album_sort, SORT.track_number";
		sortDef['release_date'] = "ORDER BY SORT.release_date, SORT.release_year";
	// First we precompile the query language object with the schema...
	sortQueryLang = TrimPath.makeQueryLang(sortColumnDefs);
		var sortStr = "";
		sortDef[key]?sortStr = sortDef[key]:sortStr = "ORDER BY SORT." + key;
		statementText = "SELECT SORT.* " + "FROM SORT " + sortStr + " " + sort.toUpperCase();
		var statement = sortQueryLang.parseSQL(statementText);
		//if(typeof(console) != "undefined") { console.log(sort + " | " + key); }
		// dojo.debug("statement: " + statement);
		// dojo.debug("sortTable: " + sortTable.toSource());
		var result = statement.filter(sortTable);
		if(eval("sortColumnDefs.SORT."+key+".type") == "Number" && sort.toUpperCase() == "DESC") { result.reverse(); }
		// dojo.debug("result: " + result.toSource());
		delete sortTable;
		return result;
	},
		
	addItem: function(id,type,doCheck) {
		console.log("collection.store.addItem - " + id + ":" + type);
		if(initialized) {
			if(doCheck && type == 0) {
				if(this.getTrackFromColl(id) == null) {
					this._addItem(id,type);
					var rTrackObj = new Object;
					
					// Loop through our recent tracks to get the rest of the track data
					for (var i = 0; i < recentTracks.length; i++) {
						if(recentTracks[i].track_id == id) {
							rTrackObj = recentTracks[i];
							break;
						}
					}
					
					//danComment//dojo.debug(rTrackObj.toSource());
					// dojo.debug(runToSource(rTrackObj));
					
					var newTrackObj = new Object;
					newTrackObj['id'] = rTrackObj.track_id - 0;
					newTrackObj['n'] = rTrackObj.track;
					newTrackObj['aid'] = rTrackObj.artist_id - 0;
					newTrackObj['ln'] = rTrackObj.album;
					newTrackObj['lid'] = rTrackObj.album_id - 0;
					newTrackObj['o'] = rTrackObj.track_number - 0;
					newTrackObj['d'] = rTrackObj.duration;
					newTrackObj['x'] = rTrackObj.explicit;
					newTrackObj['gid'] = rTrackObj.genre_id - 0;
					
					var newArtistObj = new Object;
					newArtistObj['n'] = rTrackObj.artist_name;
					newArtistObj['id'] = rTrackObj.artist_id - 0;
					
					var syncContainer = new Object;
					syncContainer['ARTISTS'] = new Array;
					syncContainer['ARTISTS'].push(newArtistObj);
					syncContainer['TRACKS'] = new Array;
					syncContainer['TRACKS'].push(newTrackObj);
					//danComment//dojo.debug("trackContainer: " + syncContainer.toSource());
					// dojo.debug("trackContainer: " + runToSource(syncContainer));
					//this.updateTable(syncContainer.toSource());
					this.updateTable(runToSource(syncContainer));
				} else {
					return false;
				}
			} else {
				this._addItem(id,type);
			}
			// this._addItem(id,type);
			
			
			if(type < 2) {
				// FIX ME - re-writing artist/genre lists takes too long, we need something that only writes our new items into our lists
				/* allArtists = "";
				libraryDisplay.writeAllGenres();
				allGenres = "";
				libraryDisplay.writeAllArtists(); */
			} else {
				console.log("REWRITING PLAYLIST LIST");
				allPlaylists = "";
				libraryDisplay.writeAllPlaylists();
			}
			return true;
		} else {
			var newAddItem = new Array(id,type,doCheck);
			addQueue.push(newAddItem);
		}
	},
		
	addItems: function(strIds,type,doCheck) {
		if(initialized) {
			if(typeof(doCheck) == "undefined") { doCheck = 0; }
			strIds = new String( strIds );
			// dojo.debug("collection.store.addItems - " + strIds + ":" + type);
			var itemIDs = strIds.split(",");
			// now get tracks	
			for (var i = 0; i < itemIDs.length; i++) {
				if(doCheck && type == 0) {
					if(this.getTrackFromColl(itemIDs[i]) == null) { this._addItem(itemIDs[i],type); } else { return false; }
				} else {
					this._addItem(itemIDs[i],type);
				}
			}
			
			if(type < 2) {
				// FIX ME - re-writing artist/genre lists takes too long, we need something that only writes our new items into our lists
				/* allArtists = "";
				libraryDisplay.writeAllGenres();
				allGenres = "";
				libraryDisplay.writeAllArtists(); */
			} else {
				console.log("REWRITING PLAYLIST LIST");
				allPlaylists = "";
				libraryDisplay.writeAllPlaylists();
			}
			return true;
		
		} else {
			var newAddItems = new Array(id,type,doCheck);
			addQueue.push(newAddItems);
		}
	},
		
	_addItem: function(id,type) {
		if(type == '2' || type == '6') {
			this.saveExistingPlaylist(id,type);
		}
		else {
			collection.mgr.addItem(id,type);
		}
	},
		
	playListReturnItems: function() {
		var playItems = false;
		var inputs = dojo.byId("listReturn").getElementsByTagName("input");
		var playItemArray = new Array();
		var itemType = "";
		if(inputs.length) {
			for(var i=0; i<inputs.length; i++) {
				var type = inputs[i].getAttribute("type");
				if(type == "checkbox" && inputs[i].value != "all") {
					if(inputs[i].checked) {
						playItems = true;
						switch(inputs[i].value.substring(0, 1)) {
							case "t":	// universalMessage += "Track ID#" + inputs[i].value.substring(1);
										playItemArray.push(inputs[i].value.substring(1));
										itemType = 0;
										// this.deleteItem(inputs[i].value.substring(1), 0);
										break;
						}
					}
				}
			}
			if(playItems) {
				Play(playItemArray, itemType);
			}
		}
	},
		
	addListReturnItemsToPlaylist: function() {
		var playItems = false;
		var inputs = dojo.byId("listReturn").getElementsByTagName("input");
		var playlistItemArray = new Array();
		var itemType = "";
		var addItems = false;
		if(inputs.length) {
			for(var i=0; i<inputs.length; i++) {
				var type = inputs[i].getAttribute("type");
				if(type == "checkbox" && inputs[i].value != "all") {
					if(inputs[i].checked) {
						addItems = true;
						switch(inputs[i].value.substring(0, 1)) {
							case "t":	// universalMessage += "Track ID#" + inputs[i].value.substring(1);
										playlistItemArray.push(inputs[i].value.substring(1));
										itemType = 0;
										// this.deleteItem(inputs[i].value.substring(1), 0);
										break;
						}
					}
				}
			}
			if(addItems) {
				showPlaylistPop(playlistItemArray, itemType);
			}
		}
	},
		
	deleteListReturnItems: function(deleteAll) {
		var deletedItems = false;
		var inputs = dojo.byId("listReturn").getElementsByTagName("input");
		var deleteItemArray = new Array();
		var itemType = "";
		if(typeof(deleteAll) == "undefined") { deleteAll = 0; }
		if(inputs.length) {
			universalMessage = "Deleted ";
			for(var i=0; i<inputs.length; i++) {
				var type = inputs[i].getAttribute("type");
				if(type == "checkbox" && inputs[i].value != "all") {
					if(inputs[i].checked || deleteAll) {
						deletedItems = true;
						switch(inputs[i].value.substring(0, 1)) {
							case "t":	// universalMessage += "Track ID#" + inputs[i].value.substring(1);
										deleteItemArray.push(inputs[i].value.substring(1));
										itemType = 0;
										// this.deleteItem(inputs[i].value.substring(1), 0);
										break;
							case "a":	// universalMessage += "Album ID#" + inputs[i].value.substring(1);
										this.deleteItem(inputs[i].value.substring(1), 1);
										break;
							case "p":	// universalMessage += "Playlist ID#" + elementID.substring(1);
										this.deleteItem(inputs[i].value.substring(1), 2);
										break;
						}
					}
				}
			}
			if(deletedItems) {
				this.deleteItems(deleteItemArray, itemType);
				// refreshContent();
			}
		}
	},
	
	removePlaylistTracks: function() {
		var deletedItems = false;
		var inputs = dojo.byId("listReturn").getElementsByTagName("input");
		var currentPlaylistTrackIDs = new Array();
		var checkedCount = 0;
		if(inputs.length) {
			//universalMessage = "Deleted ";
			for(var i=0; i<inputs.length; i++) {
				var type = inputs[i].getAttribute("type");
				if(type == "checkbox" && inputs[i].value != "all") {
					if(inputs[i].checked) {
						checkedCount++;
						deletedItems = true;
					} else {
						currentPlaylistTrackIDs.push(inputs[i].value.substring(1));
					}
				}
			}
			if(deletedItems) {
				// dojo.debug("currentPlaylistTrackIDs: " + currentPlaylistTrackIDs.toSource());
				this.updatePlaylist(currentPlaylistID, currentPlaylistTrackIDs, 0, 0, currentPlaylistName);
				var umessage = (checkedCount > 1) ? "Tracks" : "Track";
				umessage += " removed from playlist";
				displayUMessage(umessage, 1);
				// refreshContent();
			}
		}
	},

	deleteItems: function(itemArray,type) { // currently only supports items of one type, I don't think we need to support multiple types (list returns are all of the same type)
		// dojo.debug("deleteItems(" + itemArray.toSource() + "," + type + ")");
		var universalMessage = "";
		type = parseInt( type );
		// this is necessary so that we don't rewrite our artist and playlist lists multiple times when deleting multiple items
		switch(type) {
			case 0:	for(var i=0; i<itemArray.length; i++) {
						var id = itemArray[i];
						var la = tableData.LASTADDED ? tableData.LASTADDED.split(",") : "";
						this._deleteTrack(id);
						// we also need to get rid of it out of the "last added" array
						for(var l = 0; l < la.length; l++) {
							if(id == la[l]) {
								// this is a real array, so we can splice
								var dla = la.splice(l,1);
							}
						}
						tableData.LASTADDED = la ? la.join(",") : "";
					}
					universalMessage += (itemArray.length > 1) ? itemArray.length + " tracks" : " Track";
					break
			case 1:	alert("NOT YET IMPLEMENTED");
					universalMessage += "Album "
					break
			case 2:	// dojo.debug("type 2");
					var onDeletedPlaylist = false;
					for(var i=0; i<itemArray.length; i++) {
						var id = itemArray[i];
						// dojo.debug("_deletePlaylist(" + id + ")");
						this._deletePlaylist(id);
						if(id == currentPlaylistID) { onDeletedPlaylist = true; }
					}
					universalMessage += "Playlist "
					if(onDeletedPlaylist) { navigate(documentRoot + "MyLibrary"); }
					break
			default: alert("deleteItems - type: '" + type + "'");
		}
		universalMessage += " deleted from your Library"
		//danComment//this.saveData(libName,tableData.toSource());
		this.saveData(libName,runToSource(tableData));
		displayUMessage(universalMessage, 1);
		
		/* switch(type) {
			case "t":	universalMessage = "Deleted " + (inputs.length - 1);
						(inputs.length-1 > 1) ? universalMessage += " Tracks":universalMessage += " Track";
						universalMessage += " from your library.";
						break;
			case "a":	universalMessage = "Deleted " + (inputs.length - 1);
						(inputs.length-1 > 1) ? universalMessage += " Albums":universalMessage += " Album";
						universalMessage += " from your library.";
						break;
			case "p":	universalMessage = "Deleted " + (inputs.length - 1);
						(inputs.length-1 > 1) ? universalMessage += " Playlists":universalMessage += " Playlist";
						universalMessage += " from your library.";
						break;
		} */
		
		if(type < 2) {
			refreshLibrary(1);
			// allArtists = "";
			// libraryDisplay.writeAllArtists();
			// libraryDisplay.writeAllGenres();
		} else {
			allPlaylists = "";
			libraryDisplay.writeAllPlaylists();
		}
	},

	deleteItem: function(id,type) {
		// push our item into an arry and pass through to deleteItems
		var deleteItemArray = new Array();
		deleteItemArray.push(id);
		this.deleteItems(deleteItemArray, type);
	},

	_deleteTrack: function(id) {
		for(var s = 0; s < tableData.TRACKS.length; s++) {
			if(id == tableData.TRACKS[s].id) {
				var dlt = tableData.TRACKS[s];
				// get rid of the deleted track
				// do this by shifting last track to found position and 
				// truncating "array" (really an object, so splice doesn't work)
				tableData.TRACKS[s] = tableData.TRACKS[tableData.TRACKS.length - 1];
				tableData.TRACKS.length = tableData.TRACKS.length - 1;
				collection.mgr.delItem(id,0);
				// take the delete val and use it check to see if we need
				// delete the artist too (no album table, album info tied to track)
				var statement = queryLang.parseSQL(
				"SELECT TRACKS.* " +
				"FROM TRACKS " + 
				"WHERE TRACKS.aid = ?", [ dlt.aid ]
				);
				// Here we run the query...
				var result = statement.filter(tableData);
				if(result.length < 1) { // didn't find any more tracks,
										// so get rid of artist
					DELARTIST: for(var a = 0; a < tableData.ARTISTS.length; a++) {
						if(dlt.aid == tableData.ARTISTS[a].id) {
							tableData.ARTISTS[a] = tableData.ARTISTS[tableData.ARTISTS.length - 1];
							tableData.ARTISTS.length = tableData.ARTISTS.length - 1;
							break DELARTIST;
						}
					}
				}
			}
		}
		allTracks = new Array();
		// this.initialize();
	},

	_deletePlaylist: function(plid) {
		collection.mgr.delItem(plid, 2);
		for(var p = 0; p < tableData.PLAYLISTS.length; p++) {
			if(plid == tableData.PLAYLISTS[p].id) {
				var dlp = tableData.PLAYLISTS[p];
				// get rid of the deleted playlist
				// do this by shifting last playlist to found position and 
				// truncating "array" (really an object, so splice doesn't work)
				tableData.PLAYLISTS[p] = tableData.PLAYLISTS[tableData.PLAYLISTS.length - 1];
				tableData.PLAYLISTS.length = tableData.PLAYLISTS.length - 1;
			}
		}
	}
};


function runToSource(obj) {
	if(!obj.toSource) {
		obj.toSource=function(){
			if (this instanceof String){
				return '(new String("'+this.replace(/"/g, '\\"')+'"))';
			}
			var str=(this instanceof Array) ? '[' : (this instanceof Object) ? '{' : '(';
			EACH: for (var i in this){
					if (typeof this[i] == 'function') {
						continue;
					}
					if (this instanceof Array == false) {
						str+=(i.match(/\W/)) ? '"'+i.replace('"', '\\"')+'":' : i+':';
					}
					if (typeof this[i] == 'string'){
						str+='"'+this[i].replace(/\"/g, '\\"') + '"';
					}
					else if (this[i] instanceof Date){
						str+='new Date("'+this[i].toGMTString()+'")';
					}
					else if (this[i] instanceof Array || this[i] instanceof Object){
						//str+=this[i].toSource();
						str+=runToSource(this[i]);
					}
					else {
						str+=this[i];
					}
					str+=', ';
			};
			// length exception to account for empty arrays
			str=str.substring(0, ( (str.length > 1 && (str.lastIndexOf(",") == (str.length - 2) ) ) ? str.length-2 : str.length) )+( (this instanceof Array) ? ']' : (this instanceof Object) ? '}' : ')');
		return str;
		}
	}
	return obj.toSource();
}



/*
if (!Object.prototype.toSource){
    Object.prototype.toSource=function(){
        if (this instanceof String){
            return '(new String("'+this.replace(/"/g, '\\"')+'"))';
        }
        var str=(this instanceof Array) ? '[' : (this instanceof Object) ? '{' : '(';
        EACH: for (var i in this){
//            if (this[i] != Object.prototype.toSource) {
                if (typeof this[i] == 'function') {
					continue;
				}
                if (this instanceof Array == false) {
                    str+=(i.match(/\W/)) ? '"'+i.replace('"', '\\"')+'":' : i+':';
                }
                if (typeof this[i] == 'string'){
                    str+='"'+this[i].replace(/\"/g, '\\"') + '"';
                }
                else if (this[i] instanceof Date){
                    str+='new Date("'+this[i].toGMTString()+'")';
                }
                else if (this[i] instanceof Array || this[i] instanceof Object){
                    str+=this[i].toSource();
                }
                else {
                    str+=this[i];
                }
                str+=', ';
//            }
        };
        // length exception to account for empty arrays
        str=str.substring(0, ( (str.length > 1 && (str.lastIndexOf(",") == (str.length - 2) ) ) ? str.length-2 : str.length) )+( (this instanceof Array) ? ']' : (this instanceof Object) ? '}' : ')');
    return str;
    }
}*/
