function PlaylistMgr() {
  this.url = rhapsodyUrlJson + "/webservice/playlistmgr";
  this.globalPlaylists;
  this.mwidth = 10000;
  this.trackmwidth = 10000;
  this.albummwidth = 10000;
  this.artistmwidth = 10000;
  this.sort = 0;

  /** Sort values are
  NATURAL = 0;
  REVERSE_NATURAL_SORT = 1;
  NAME_SORT = 2;
  REVERSE_NAME_SORT = 3;
  MOD_DATE_SORT = 4;
  REVERSE_MOD_DATE_SORT = 5;
  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.messageCount = 0;
  this.messagesReceivedMapping = new Array();

  this.instanceId = Math.floor(Math.random()*10000000);

  this.returnAsArrays = function(data) {
                if (data){
                    var playlists = new Array();
                    for (var i=0; i < data.length; i++){
                      playlists[i] = new Playlist(data[i]);
                    }
                    return playlists;
                }
              };
              
  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
          callback(data);
          return;
        }
      }
    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: 'post',
          parameters: content.toQueryString()+"&sort="+this.sort+"&mwidth="+this.mwidth+"&albummwidth="+this.albummwidth+"&artistmwidth="+this.artistmwidth+"&trackmwidth="+this.trackmwidth
      });
  }
  
  
                    

  this.innerHasPlaylist = function (id, callback) {
                var localHandler = function(data){
                            for (var i =0; i<data.length; i++){
                              if (data[i].getId() == id){
                                callback(null, true);
                                return;
                              }
                            }
                            callback(null, false);
                          };
                if (this.globalPlaylists == null){
                  this.innerGetPlaylists( localHandler);
                } else {
                  localHandler(this.globalPlaylists);
                }
              }
              
  this.innerGetPlaylists = function (handler, sort) {
                var action = "get-playlists";
                var content = $H({
                        returntype: "array",
                        todo: action});
                var callback = function (data){
                  if (data.hasError){
                    handler(data);
                  } else {
                    var playlists = new PlaylistMgr().returnAsArrays(data);
                    this.globalPlaylists = playlists;
                    handler(playlists);
                  }
                  
                }
                this.sendMessage(this.url, content, callback);  
              }
            
}



PlaylistMgr.prototype.getPlaylists = function ( sort, handler ) {
  this.innerGetPlaylists(handler, sort);
}

PlaylistMgr.prototype.getPlaylist = function ( id, handler ) {
  // see if we have it in our local cache first.
  if (this.globalPlaylists != null) {
    for (var i = 0; i<this.globalPlaylists.length; i++){
      if (this.globalPlaylists[i].getId() == id){
        handler(data);
        return;
      }
    }
  }
  var action = "get";
  var content = $H({id: id,
            returntype: "object",
            todo: action});
  var callback = function (data){
            if(data.hasError){
              handler(data);  
              }else{
              data = new Playlist(data);
              handler(data);
              }
          }
  this.sendMessage(this.url, content, callback);  
}

PlaylistMgr.prototype.getNewestPlaylist = function ( handler) {
  // see if we have it in our local cache first.
  if (this.globalPlaylists != null) {
    var newestCreateDate = 0;
    var newestPlaylist;
    for (var i = 0; i<this.globalPlaylists.length; i++){
      var itemCreateDate = this.globalPlaylists[i].getCreatedate();
      if (itemCreateDate > newestCreateDate){
        newestCreateDate = itemCreateDate;
        newestPlaylist = this.globalPlaylists[i];
      }
    }
    handler(newestPlaylist);
    return;
  }
  var action = "get-newest";
  var content = $H({
            returntype: "object",
            todo: action});
  var callback = function (data){
            if(data.hasError){
              handler(data);  
              }else{
              data = new Playlist(data);
              handler(data);
              }
          }
  this.sendMessage(this.url, content, callback);  
}

// Name can be null to set a new untitled playlist.
PlaylistMgr.prototype.setPlaylist = function ( name, ids, handler) {
  var action = "set";
  var content = $H({name: unescape( encodeURIComponent(name)),
            ids: ids,
            returntype: "object",
            todo: action});
  var callback = function (data){
            if(data.hasError){
              handler(data);  
              }else{
                
                  var playlists = new PlaylistMgr().returnAsArrays(data);
              this.globalPlaylists = playlists;
              handler(playlists);
              }
          }
  this.sendMessage(this.url, content, callback);
}

PlaylistMgr.prototype.setExistingByName = function ( name, ids, handler) {
  var action = "set-existing";
  var content = $H({name: unescape( encodeURIComponent(name)),
            ids: ids,
            returntype: "object",
            todo: action});
  var callback = function (data){
            if(data.hasError){
              handler(data);  
              }else{
                
                  var playlists = new PlaylistMgr().returnAsArrays(data);
              this.globalPlaylists = playlists;
              handler(playlists);
              }
          }
  this.sendMessage(this.url, content, callback);
}

PlaylistMgr.prototype.setExisting = function (playlistId, ids, handler) {

  var action = "set-existing";
  var content = $H({id: playlistId,
            todo: action,
            returntype: "object",
            ids: ids
            });
  var callback = function (data){
            if (data.hasError){
                handler(data);
            } else {
                data = new Playlist(data);
                handler(data);
            }
          }
  this.sendMessage(this.url, content, callback);
  
}

PlaylistMgr.prototype.removePlaylist = function ( id, handler) {
  var action = "remove-playlist";
  var content = $H({id: id,
            returntype: "array",
            todo: action});
  var callback = function (data){
            if (data.hasError){
              handler(data);
            } else {
              var playlists = new PlaylistMgr().returnAsArrays(data);
              this.globalPlaylists = playlists
              handler(playlists);
              }
          }
  this.sendMessage(this.url, content, callback);
  
}

PlaylistMgr.prototype.renamePlaylist = function ( id, newname, handler) {
  var action = "rename";
  var content = $H({id: id,
          newname:unescape( encodeURIComponent(newname)),
            returntype: "object",
            todo: action});
  var callback = function (data){
            if (data.hasError){
              handler(data);
            } else {
              var playlists = new PlaylistMgr().returnAsArrays(data);
              this.globalPlaylists = playlists
              handler(playlists);
              }
          }
  this.sendMessage(this.url, content, callback);
  
}


PlaylistMgr.prototype.insertIntoPlaylist = function ( id, trackid, idx, handler) {
  var action = "insert-into-playlist";
  var content = $H({id: id,
          trackid:trackid,
          index:idx,
            returntype: "object",
            todo: action});
  var callback = function (data){
            if (data.hasError){
                handler(data);
            } else {
              var playlists = new PlaylistMgr().returnAsArrays(data);
              this.globalPlaylists = playlists
              handler(playlists);
              }
          }
  this.sendMessage(this.url, content, callback);
}

PlaylistMgr.prototype.hasPlaylist = function ( id, handler) {
  var callback = function (data){
              handler(data);
              }
  
  this.innerHasPlaylist( id, callback);
  
}

PlaylistMgr.prototype.getNextUntitledPlaylistName = function (handler) {
  var action = "get-next-untitled-playlist-name";
  var content = $H({todo: action,
            returntype: "object"});
  var callback = function (data){
            if (data.hasError){
              handler(data);
            } else {
              handler(data.value);
              }
          }
  this.sendMessage(this.url, content, callback);
  
}


PlaylistMgr.prototype.setSort = function (sort) {
               this.sort = sort
      }

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





PlaylistMgr.prototype.toString = function () {
  var output = '';
  for (var i = 0; i<this.list.length; i++){
    output = output + this.list[i].id + " " + this.list[i].rcid + " " + this.list[i].playlength + " " + this.list[i].name + " " + this.list[i].discindex + " " + this.list[i].remoteid + " " + this.list[i].artistdisplayname;
  }
  return output;
}   


