/* vim: set noexpandtab tabstop=4 shiftwidth=4 nowrap textwidth=100
*
* Echo Media Player
* Copyright (C) 2008 Shane O'Connell
*
* [ The original file includes a copyright header in this location describing
* the file as being released under the terms of the GNU General Public
* License. It has been removed in order to display the file as part of the
* archive. ]
*/
using Echo.Interfaces;
public class Echo.Core.Playlist : GLib.Object, IPlaySource, IModPlaySource
{
// TODO set up Playlist to forward track_changed events from sources which have tracks
// that are in this playlist
private string _name;
private Gee.ArrayList<PlaylistTrack> _tracks;
public string name { get { return _name; } }
public string icon { get { return "text-x-generic"; } }
public Playlist(string name)
{
_name = name;
_tracks = new Gee.ArrayList<PlaylistTrack>();
}
public int get_num_tracks()
{
return _tracks.size;
}
public weak ITrack get_track(int index)
{
assert(index >= 0);
assert(index < get_num_tracks());
ITrack track = _tracks.get(index);
return track;
}
public void insert_track(int index, ITrack track)
{
assert(index >= 0);
assert(index <= get_num_tracks()); // <= because it could be at the end
while (track is PlaylistTrack)
track = ((PlaylistTrack)track).get_real_track();
_tracks.insert(index, new PlaylistTrack(this, index, track));
for (int i = index; i < _tracks.size; i++)
_tracks.get(i).set_index(i);
this.track_inserted(index);
}
public void remove_track(int index)
{
assert(index >= 0);
assert(index < get_num_tracks());
_tracks.get(index).invalidate();
_tracks.remove_at(index);
for (int i = index; i < _tracks.size; i++)
_tracks.get(i).set_index(i);
this.track_removed(index);
}
public void move_track(int old_index, int new_index)
{
assert(old_index >= 0);
assert(old_index < get_num_tracks());
assert(new_index >= 0);
assert(new_index <= get_num_tracks()); // <= because it could be at the end
var track = _tracks.get(old_index);
_tracks.remove_at(old_index);
for (int i = old_index; i < _tracks.size; i++)
_tracks.get(i).set_index(i);
this.track_removed(old_index);
if (old_index < new_index)
new_index--;
_tracks.insert(new_index, track);
for (int i = new_index; i < _tracks.size; i++)
_tracks.get(i).set_index(i);
this.track_inserted(new_index);
}
private class PlaylistTrack : GLib.Object, ITrack
{
public IPlaySource source { get { return _playlist; } }
private int _index;
public int index { get { return _index; } }
public string title { get { return _real_track.title; } }
public string artist { get { return _real_track.artist; } }
public string album { get { return _real_track.album; } }
public int track_number { get { return _real_track.track_number; } }
public int release_year { get { return _real_track.release_year; } }
public int release_month { get { return _real_track.release_month; } }
public int release_day { get { return _real_track.release_day; } }
public string uri { get { return _real_track.uri; } }
private Playlist _playlist;
private ITrack _real_track;
private bool _valid = true;
public PlaylistTrack(Playlist playlist, int index, ITrack real_track)
{
_playlist = playlist;
_index = index;
_real_track = real_track;
_real_track.track_invalidated += (ITrack) => {
_valid = false;
this.track_invalidated();
};
}
public void set_index(int index)
{
_index = index;
}
public ITrack? get_next()
{
int i = this.index + 1;
if (i >= 0 && i < _playlist.get_num_tracks())
return _playlist.get_track(i);
else
return null;
}
public ITrack? get_prev()
{
int i = this.index - 1;
if (i >= 0 && i < _playlist.get_num_tracks())
return _playlist.get_track(i);
else
return null;
}
public weak ITrack get_real_track()
{
return _real_track;
}
public void invalidate()
{
_valid = false;
this.track_invalidated();
}
public bool valid
{
get { return _valid; }
}
}
/*
public IPlaySourceTrackRef get_track_ref(int index)
{
return new PlaylistIterator(this, index);
}
private class PlaylistIterator : GLib.Object, IPlaySourceTrackRef
{
private Playlist _playlist;
private int _index;
private bool _valid;
public PlaylistIterator(Playlist playlist, int index)
{
_playlist = playlist;
_index = index;
_valid = true;
// TODO check that these functions are automatically detached from the signal
// when the iterator is freed
_playlist.track_removed += (playlist, removed_index) => {
if (removed_index < _index)
_index--;
else if (removed_index == _index) {
_valid = false;
this.track_invalidated();
}
};
_playlist.track_inserted += (playlist, inserted_index) => {
if (inserted_index <= _index)
_index++;
};
}
public bool next()
{
if (!_valid)
return false;
if (_index < _playlist.get_num_tracks())
_index++;
return (_index < _playlist.get_num_tracks());
}
public bool prev()
{
if (!_valid)
return false;
if (_index >= 0)
_index--;
return (_index >= 0);
}
public weak Track? get()
{
if (!_valid)
return null;
if (_index >= 0 && _index < _playlist.get_num_tracks())
return _playlist.get_track(_index);
else
return null;
}
public IPlaySource? get_source()
{
if (!_valid)
return null;
else
return _playlist;
}
public int get_index()
{
if (!_valid || _index < 0 || _index >= _playlist.get_num_tracks())
return -1;
else
return _index;
}
}*/
}