+#include <cstdlib>
+#include <msp/datafile/collection.h>
+#include "playlist.h"
+
+using namespace std;
+
+namespace Msp {
+namespace AL {
+
+Playlist::Playlist():
+ shuffle(false)
+{ }
+
+void Playlist::add_track(const string &trk)
+{
+ tracks.push_back(trk);
+}
+
+void Playlist::remove_track(const string &trk)
+{
+ for(vector<Track>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ if(i->filename==trk)
+ {
+ tracks.erase(i);
+ break;
+ }
+}
+
+void Playlist::clear_tracks()
+{
+ tracks.clear();
+}
+
+void Playlist::set_shuffle(bool s)
+{
+ shuffle = s;
+}
+
+const string &Playlist::get_track(unsigned i) const
+{
+ if(i>=tracks.size())
+ throw out_of_range("Playlist::get_track");
+ return tracks[i].filename;
+}
+
+unsigned Playlist::advance(unsigned i, int d) const
+{
+ unsigned s = tracks.size();
+ if(i>=s)
+ throw out_of_range("Playlist::next_track");
+
+ if(shuffle)
+ {
+ if(s>1)
+ {
+ unsigned j = i;
+ while(j==i)
+ j = rand()%s;
+ i = j;
+ }
+ }
+ else if(d>0)
+ i = (i+d)%s;
+ else
+ i = s-1-(s-1-i-d)%s;
+
+ return i;
+}
+
+IO::Seekable *Playlist::open(unsigned i) const
+{
+ if(i>=tracks.size())
+ throw out_of_range("Playlist::open");
+
+ const Track &track = tracks[i];
+ if(track.collection)
+ return track.collection->open_raw(track.filename);
+
+ return new IO::BufferedFile(track.filename);
+}
+
+
+Playlist::Track::Track():
+ collection(0)
+{ }
+
+Playlist::Track::Track(const string &fn):
+ collection(0),
+ filename(fn)
+{ }
+
+
+Playlist::Loader::Loader(Playlist &p):
+ DataFile::CollectionObjectLoader<Playlist>(p, 0)
+{
+ init();
+}
+
+Playlist::Loader::Loader(Playlist &p, Collection &c):
+ DataFile::CollectionObjectLoader<Playlist>(p, &c)
+{
+ init();
+}
+
+void Playlist::Loader::init()
+{
+ add("track", &Loader::track);
+ add("shuffle", &Playlist::shuffle);
+}
+
+void Playlist::Loader::track(const string &fn)
+{
+ Track trk;
+ trk.collection = coll;
+ trk.filename = fn;
+ obj.tracks.push_back(trk);
+}
+
+} // namespace AL
+} // namespace Msp