banshee r3837 - in trunk/banshee: . build src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Database src/Core/Banshee.Services/Banshee.Playlist src/Core/Banshee.Services/Banshee.SmartPlaylist src/Core/Banshee.Services/Banshee.Sources src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue src/Extensions/Banshee.Podcasting src/Extensions/Banshee.Podcasting/Banshee.Podcasting src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/ColumnCells src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views src/Libraries/Hyena/Hyena.Data.Sqlite src/Libraries/Migo src/Librar ies/Migo/Migo/Migo.Syndication src/Libraries/Migo/Migo/Migo.Syndication/EventArgs src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Rss tests/Hyena



Author: gburt
Date: Mon Apr 28 21:42:18 2008
New Revision: 3837
URL: http://svn.gnome.org/viewvc/banshee?rev=3837&view=rev

Log:
2008-04-28  Gabriel Burt  <gabriel burt gmail com>

	WARNING: This commit is a first pass at reworking some of the Podcast/Migo
	internals to use Hyena and be more consistent with Banshee's style.  It
	severely breaks the podcast extension for the time being, so unless you
	are working with Mike and me to fix it, you should not build or run it.

	* build/build.environment.mk: Link Migo against Hyena.

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumInfo.cs:
	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistInfo.cs:
	* src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs:
	Update to new Load method (w/o superflous int arg).

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs:
	Fix DatabaseColumn attributes to be on properties, not private members.

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs:
	Use new IDatabaseTrackModel[Provider|Cache] interfaces to allow this class
	to handle DatabaseTrackInfo subclasses (eg to handle PodcastInfo objects).

	* src/Core/Banshee.Services/Banshee.Playlist/AbstractPlaylistSource.cs:
	Override AfterInitialized method, moving quite a bit of track model
	property setting there.

	* src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs:
	* src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs:
	* src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs:
	Change static LoadAll method to take a primary source id, so that as
	primary sources are loaded, they fetch/load only their playlists.

	* src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs: Add virtual
	HasArtistAlbum property so sources can avoid instantiating the
	Artist/Album models at all if they don't use them.

	* src/Core/Banshee.Services/Banshee.Sources/Source.cs: Check the
	artist/album models aren't null before using them.

	* src/Core/Banshee.Services/Makefile.am:
	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackModelCache.cs:
	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackModelProvider.cs:
	* src/Core/Banshee.Services/Banshee.Collection.Database/IDatabaseTrackModelCache.cs:
	* src/Core/Banshee.Services/Banshee.Collection.Database/IDatabaseTrackModelProvider.cs:
	New interfaces/classes to enable DatabaseTrackInfo subclasses to be
	used/loaded by DatabaseTrackListModel and therefore any DatabaseSource
	subclass.

	* src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs:
	Override HasArtistAlbum to false.

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastItem.cs:
	Migo's FeedItem class is backed by a database table (PodcastItems), so
	the idea is intead of having another table for Banshee specific podcast item
	information, push as much as possible into Migo, and have PodcastItem
	actually subclass from DatabaseTrackInfo, and pull in information from the
	Migo tables as necessary (using VirtualDatabaseColumn attributes).

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastFeed.cs:
	Deleted, since we just use the Migo table/Feed class now.
	
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastFeedPropertiesDialog.cs:
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastPropertiesDialog.cs:
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastSubscribeDialog.cs:
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/SyncPreferenceComboBox.cs:
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/ColumnCells/FeedActivityColumnCell.cs:
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models/PodcastFeedModel.cs:
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSourceContents.cs:
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views/PodcastFeedView.cs:
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views/PodcastItemView.cs:
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastCore.cs:
	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastCore_Interface.cs:
	Many HACKING fixes, quite a lot of work to do still.

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models/PodcastItemModel.cs:
	Remove the custom model since we use a DatabaseTrackListModel now.

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSource.cs:
	Change to subclass from PrimarySource.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs: Fix bug in
	exception logging.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs: Use
	Action<IDataReader> instead of custom delegate type for AggregatesUpdated
	event.

	* src/Core/Banshee.Services/Banshee.Database/BansheeModelProvider.cs:
	* src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs: Make not
	abstract, taking default properties and empty virtual methods from
	BansheeModelProvider.  Remove unused int arg in Load method.  Add
	FetchAllMatching, FetchFirstMatching, FetchSingle (id), and Delete
	methods.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteCommand.cs:
	* src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteUtils.cs: Handle bools.

	* src/Libraries/Migo/Makefile.am:
	* src/Libraries/Migo/Migo.mdp: Several files removed, a few added.

	* src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedDownloadCompletedEventArgs.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedDownloadCountChangedEventArgs.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedEventArgs.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedItemCountChangedEventArgs.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedItemEventArgs.cs:
	Renamed to follow HACKING.

	* src/Libraries/Migo/Migo/Migo.Syndication/Feed.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/FeedEnclosure.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/FeedItem.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/FeedUpdateTask.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/FeedsManager.cs: Many updates,
	including HACKING fixes, trying to get rid of unnecessary dictionaries
	etc.  There are some commented out pieces of code in this commit that have
	broken podcasts temporarily until they are 'ported'.  For the
	database-backed classes (Feed, FeedItem, and FeedEnclosure) use
	Hyena.Data.Sqlite [DatabaseColumn] attributes to flag db-backed
	properties.

	* src/Libraries/Migo/Migo/Migo.Syndication/IFeed.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/IFeedEnclosure.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/IFeedItem.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/IFeedsManager.cs: Deleted.

	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/EnclosuresTableManager.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/FeedsTableManager.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/ItemsTableManager.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/DataUtility.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/DatabaseManager.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/DbDefines.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/QueuedDbCommand.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/SQLiteUtility.cs:
	Deleted; Migo uses Hyena.Data.Sqlite now for db related functionality.

	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/DataWrapper.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/FeedDataWrapper.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/FeedEnclosureDataWrapper.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/FeedItemDataWrapper.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/IFeedEnclosureWrapper.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/IFeedItemWrapper.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/IFeedWrapper.cs: 
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Rss/RssFeedEnclosureWrapper.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Rss/RssFeedItemWrapper.cs:
	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Rss/RssFeedWrapper.cs:
	Deleted; Wrapper concept had a lot of redundancy in property definitions
	etc.  The Db wrappers are unnecessary since Hyena.Data.Sqlite uses
	reflection to instantiate objects/set properties.

	* src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/RssParser.cs:
	New class largley taken from the Rss*Wrapper classes.

	* tests/Hyena/SqliteCommandTests.cs: Test SQLification of bools.


Added:
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackModelCache.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackModelProvider.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/IDatabaseTrackModelCache.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/IDatabaseTrackModelProvider.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/RssParser.cs
Removed:
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastFeed.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/IFeed.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/IFeedEnclosure.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/IFeedItem.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/IFeedsManager.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/DataUtility.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/DatabaseManager.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/DbDefines.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/QueuedDbCommand.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/SQLiteUtility.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/DataWrapper.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/FeedDataWrapper.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/FeedEnclosureDataWrapper.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/FeedItemDataWrapper.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/IFeedEnclosureWrapper.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/IFeedItemWrapper.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/IFeedWrapper.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Rss/RssFeedEnclosureWrapper.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Rss/RssFeedItemWrapper.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Rss/RssFeedWrapper.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/build/build.environment.mk
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeModelProvider.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/AbstractPlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs
   trunk/banshee/src/Core/Banshee.Services/Makefile.am
   trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastItem.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastFeedPropertiesDialog.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastPropertiesDialog.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastSubscribeDialog.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/SyncPreferenceComboBox.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/ColumnCells/FeedActivityColumnCell.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models/PodcastFeedModel.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models/PodcastItemModel.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSource.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSourceContents.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views/PodcastFeedView.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views/PodcastItemView.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastCore.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastCore_Interface.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Makefile.am
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteCommand.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteUtils.cs
   trunk/banshee/src/Libraries/Migo/Makefile.am
   trunk/banshee/src/Libraries/Migo/Migo.mdp
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedDownloadCompletedEventArgs.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedDownloadCountChangedEventArgs.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedEventArgs.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedItemCountChangedEventArgs.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedItemEventArgs.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Feed.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedEnclosure.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedItem.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedUpdateTask.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedsManager.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/EnclosuresTableManager.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/FeedsTableManager.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/ItemsTableManager.cs
   trunk/banshee/tests/Hyena/SqliteCommandTests.cs

Modified: trunk/banshee/build/build.environment.mk
==============================================================================
--- trunk/banshee/build/build.environment.mk	(original)
+++ trunk/banshee/build/build.environment.mk	Mon Apr 28 21:42:18 2008
@@ -75,7 +75,7 @@
 LINK_LASTFM_GUI = -r:$(DIR_BIN)/Lastfm.Gui.dll
 LINK_LASTFM_GUI_DEPS = $(REF_LASTFM_GUI) $(LINK_LASTFM_GUI)
 
-REF_MIGO = $(LINK_SYSTEM) $(LINK_SYSTEM_WEB) $(LINK_SQLITE)
+REF_MIGO = $(LINK_SYSTEM) $(LINK_SYSTEM_WEB) $(LINK_SQLITE) $(LINK_HYENA)
 LINK_MIGO = -r:$(DIR_BIN)/Migo.dll
 LINK_MIGO_DEPS = $(REF_MIGO) $(LINK_MIGO)
 

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumInfo.cs	Mon Apr 28 21:42:18 2008
@@ -83,7 +83,7 @@
 
             using (IDataReader reader = ServiceManager.DbConnection.Query (select_command, artist.DbId, album.Title)) {
                 if (reader.Read ()) {
-                    last_album = provider.Load (reader, 0);
+                    last_album = provider.Load (reader);
                     last_album.ArtistId = artist.DbId;
                     last_album.ArtistName = artist.Name;
                 } else {

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistInfo.cs	Mon Apr 28 21:42:18 2008
@@ -81,7 +81,7 @@
 
             using (IDataReader reader = ServiceManager.DbConnection.Query (select_command, artist.Name)) {
                 if (reader.Read ()) {
-                    last_artist = provider.Load (reader, 0);
+                    last_artist = provider.Load (reader);
                 } else {
                     last_artist = artist;
                     last_artist.Save ();

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs	Mon Apr 28 21:42:18 2008
@@ -37,7 +37,6 @@
 using Banshee.Configuration.Schema;
 using Banshee.Database;
 using Banshee.Sources;
-using Banshee.IO;
 using Banshee.ServiceStack;
 
 // Disabling "is never used" warnings here because there are a lot
@@ -146,10 +145,11 @@
             }
         }
         
-        [DatabaseColumn ("TrackID", Constraints = DatabaseColumnConstraints.PrimaryKey)]
         private int track_id;
+        [DatabaseColumn ("TrackID", Constraints = DatabaseColumnConstraints.PrimaryKey)]
         public int TrackId {
             get { return track_id; }
+            protected set { track_id = value; }
         }
 
         private int primary_source_id;
@@ -228,7 +228,7 @@
         
         private string uri_field;
         [DatabaseColumn ("Uri")]
-        private string UriField {
+        protected string UriField {
             get {
                 if (uri_fields_dirty) {
                     PrimarySource.UriToFields (Uri, out uri_type, out uri_field);
@@ -245,7 +245,7 @@
         private bool uri_type_set;
         private TrackUriType uri_type;
         [DatabaseColumn ("UriType")]
-        private TrackUriType UriType {
+        protected TrackUriType UriType {
             get {
                 if (uri_fields_dirty) {
                     PrimarySource.UriToFields (Uri, out uri_type, out uri_field);

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs	Mon Apr 28 21:42:18 2008
@@ -55,8 +55,9 @@
         ICacheableDatabaseModel, IFilterable, ISortable, ICareAboutView
     {
         private readonly BansheeDbConnection connection;
-        private readonly BansheeModelProvider<DatabaseTrackInfo> provider;
-        private BansheeModelCache<DatabaseTrackInfo> cache;
+        private IDatabaseTrackModelProvider provider;
+        protected IDatabaseTrackModelCache cache;
+        
         private long count;
 
         private long filtered_count;
@@ -78,24 +79,21 @@
         private DatabaseArtistListModel artist_model;
         private DatabaseAlbumListModel album_model;
 
-        private string uuid;
-        
         private int rows_in_view;
         
-        public DatabaseTrackListModel (BansheeDbConnection connection, string uuid)
+        public DatabaseTrackListModel (BansheeDbConnection connection, IDatabaseTrackModelProvider provider)
         {
             this.connection = connection;
-            this.uuid = uuid;
-            provider = DatabaseTrackInfo.Provider;
+            this.provider = provider;
         }
 
         private bool initialized = false;
-        public void Initialize ()
+        public void Initialize (IDatabaseTrackModelCache cache)
         {
-            Initialize (null, null);
+            Initialize (cache, null, null);
         }
 
-        public void Initialize (DatabaseArtistListModel artist_model, DatabaseAlbumListModel album_model)
+        public void Initialize (IDatabaseTrackModelCache cache, DatabaseArtistListModel artist_model, DatabaseAlbumListModel album_model)
         {
             if (initialized)
                 return;
@@ -104,7 +102,7 @@
             this.album_model = album_model;
 
             initialized = true;
-            cache = new BansheeModelCache <DatabaseTrackInfo> (connection, uuid, this, provider);
+            this.cache = cache;
             cache.AggregatesUpdated += HandleCacheAggregatesUpdated;
 
             GenerateSortQueryPart ();

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackModelCache.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackModelCache.cs	Mon Apr 28 21:42:18 2008
@@ -0,0 +1,54 @@
+//
+// DatabaseTrackModelCache.cs
+//
+// Author:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using Hyena.Data.Sqlite;
+using Banshee.Database;
+
+namespace Banshee.Collection.Database
+{
+    public class DatabaseTrackModelCache<T> : BansheeModelCache<T>, IDatabaseTrackModelCache
+        where T : DatabaseTrackInfo, new()
+    {
+        public DatabaseTrackModelCache (HyenaSqliteConnection connection, string uuid,
+                                        ICacheableDatabaseModel model, BansheeModelProvider <T> provider)
+            : base (connection, uuid, model, provider)
+        {
+        }
+
+        public new TrackInfo GetSingle (string random_fragment, params object [] args)
+        {
+            return base.GetSingle (random_fragment, args);
+        }
+
+        public new TrackInfo GetValue (long index)
+        {
+            return base.GetValue (index);
+        }
+    }
+}

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackModelProvider.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackModelProvider.cs	Mon Apr 28 21:42:18 2008
@@ -0,0 +1,42 @@
+//
+// DatabaseTrackModelProvider.cs
+//
+// Author:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using Hyena.Data.Sqlite;
+using Banshee.Database;
+
+namespace Banshee.Collection.Database
+{
+    public class DatabaseTrackModelProvider<T> : BansheeModelProvider<T>, IDatabaseTrackModelProvider
+        where T : DatabaseTrackInfo, new()
+    {
+        public DatabaseTrackModelProvider (BansheeDbConnection connection) : base (connection, "CoreTracks")
+        {
+        }
+    }
+}

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/IDatabaseTrackModelCache.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/IDatabaseTrackModelCache.cs	Mon Apr 28 21:42:18 2008
@@ -0,0 +1,50 @@
+//
+// IDatabaseTrackModelCache.cs
+//
+// Author:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Data;
+using Banshee.Collection;
+using Hyena.Data.Sqlite;
+
+namespace Banshee.Collection.Database
+{
+    public interface IDatabaseTrackModelCache
+    {
+        void Clear ();
+        void SaveSelection ();
+        void UpdateAggregates ();
+        void RestoreSelection ();
+        long Count { get; }
+        void Reload ();
+        long IndexOf (long item_id);
+        TrackInfo GetSingle (string random_fragment, params object [] args);
+        TrackInfo GetValue (long index);
+        long CacheId { get; }
+        event Action<IDataReader> AggregatesUpdated;
+    }
+}

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/IDatabaseTrackModelProvider.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/IDatabaseTrackModelProvider.cs	Mon Apr 28 21:42:18 2008
@@ -0,0 +1,37 @@
+//
+// IDatabaseTrackModelProvider.cs
+//
+// Author:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Banshee.Collection.Database
+{
+    // BansheeModelProvider<DatabaseTrackInfo> :
+    public interface IDatabaseTrackModelProvider
+    {
+        string From { get; }
+        string Where { get; }
+    }
+}

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	Mon Apr 28 21:42:18 2008
@@ -639,7 +639,7 @@
                 while (reader.Read ()) {
                     DatabaseTrackInfo track = null;
                     try {
-                        track = DatabaseTrackInfo.Provider.Load (reader, 0);
+                        track = DatabaseTrackInfo.Provider.Load (reader);
                         
                         try {
                             TagLib.File file = StreamTagger.ProcessUri (track.Uri);

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeModelProvider.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeModelProvider.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeModelProvider.cs	Mon Apr 28 21:42:18 2008
@@ -38,25 +38,9 @@
 {
     public class BansheeModelProvider<T> : SqliteModelProvider<T> where T : new ()
     {
-        private string table_name;
-
         public BansheeModelProvider (BansheeDbConnection connection, string table_name)
-            : base (connection)
+            : base (connection, table_name)
         {
-            this.table_name = table_name;
-            Init ();
-        }
-        
-        public override sealed string TableName {
-            get { return table_name; }
-        }
-        
-        protected override int ModelVersion {
-            get { return 1; }
-        }
-        
-        protected override sealed int DatabaseVersion {
-            get { return 1; }
         }
         
         protected override sealed void CheckVersion ()
@@ -79,18 +63,5 @@
                     namespce, key, new_version);
             }
         }
-
-        protected override sealed void MigrateDatabase (int old_version)
-        {
-        }
-        
-        protected override void MigrateTable (int old_version)
-        {
-        }
-        
-        protected override T MakeNewObject (int index)
-        {
-            return new T ();
-        }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/AbstractPlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/AbstractPlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/AbstractPlaylistSource.cs	Mon Apr 28 21:42:18 2008
@@ -79,28 +79,10 @@
         public int? DbId {
             get { return dbid; }
             protected set {
-                if (value == null) {
-                    return;
+                if (value != null && value != dbid) {
+                    dbid = value;
+                    AfterInitialized ();
                 }
-                dbid = value;
-                track_model.JoinTable = TrackJoinTable;
-                track_model.JoinPrimaryKey = JoinPrimaryKey;
-                track_model.JoinColumn = "TrackID";
-                track_model.CachesJoinTableEntries = CachesJoinTableEntries;
-                track_model.Condition = String.Format (TrackCondition, dbid);
-                AfterInitialized ();
-
-                count_updated_command = new HyenaSqliteCommand (String.Format (
-                    @"SELECT COUNT(*) FROM {0} WHERE {1} = {2} AND TrackID IN (
-                        SELECT TrackID FROM CoreTracks WHERE DateUpdatedStamp > ?)",
-                    TrackJoinTable, SourcePrimaryKey, dbid
-                ));
-
-                count_removed_command = new HyenaSqliteCommand (String.Format (
-                    @"SELECT COUNT(*) FROM {0} WHERE {1} = {2} AND TrackID IN (
-                        SELECT TrackID FROM CoreRemovedTracks WHERE DateRemovedStamp > ?)",
-                    TrackJoinTable, SourcePrimaryKey, dbid
-                ));
             }
         }
 
@@ -114,8 +96,29 @@
             set { primary_source_id = value.DbId; }
         }
 
-        protected HyenaSqliteCommand count_updated_command;
-        protected HyenaSqliteCommand count_removed_command;
+        private HyenaSqliteCommand count_updated_command;
+        protected HyenaSqliteCommand CountUpdatedCommand {
+            get {
+                return count_updated_command ??
+                    count_updated_command = new HyenaSqliteCommand (String.Format (
+                        @"SELECT COUNT(*) FROM {0} WHERE {1} = {2} AND TrackID IN (
+                            SELECT TrackID FROM CoreTracks WHERE DateUpdatedStamp > ?)",
+                        TrackJoinTable, SourcePrimaryKey, dbid
+                    ));
+            }
+        }
+
+        private HyenaSqliteCommand count_removed_command;
+        protected HyenaSqliteCommand CountRemovedCommand {
+            get {
+                return count_removed_command ??
+                    count_removed_command = new HyenaSqliteCommand (String.Format (
+                        @"SELECT COUNT(*) FROM {0} WHERE {1} = {2} AND TrackID IN (
+                            SELECT TrackID FROM CoreRemovedTracks WHERE DateRemovedStamp > ?)",
+                        TrackJoinTable, SourcePrimaryKey, dbid
+                    ));
+            }
+        }
 
         public AbstractPlaylistSource (string generic_name, string name, int primarySourceId)
             : this (generic_name, name, null, -1, 0, primarySourceId)
@@ -128,6 +131,17 @@
             this.primary_source_id = primarySourceId;
         }
 
+        protected override void AfterInitialized ()
+        {
+            DatabaseTrackModel.JoinTable = TrackJoinTable;
+            DatabaseTrackModel.JoinPrimaryKey = JoinPrimaryKey;
+            DatabaseTrackModel.JoinColumn = "TrackID";
+            DatabaseTrackModel.CachesJoinTableEntries = CachesJoinTableEntries;
+            DatabaseTrackModel.Condition = String.Format (TrackCondition, dbid);
+
+            base.AfterInitialized ();
+        }
+
         public override void Rename (string newName)
         {
             base.Rename (newName);

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs	Mon Apr 28 21:42:18 2008
@@ -290,10 +290,11 @@
             }
         }
 
-        public static IEnumerable<PlaylistSource> LoadAll ()
+        public static IEnumerable<PlaylistSource> LoadAll (int primary_id)
         {
             using (IDataReader reader = ServiceManager.DbConnection.Query (
-                "SELECT PlaylistID, Name, SortColumn, SortType, PrimarySourceID FROM CorePlaylists WHERE Special = 0")) {
+                @"SELECT PlaylistID, Name, SortColumn, SortType, PrimarySourceID FROM CorePlaylists 
+                    WHERE Special = 0 AND PrimarySourceID = ?", primary_id)) {
                 while (reader.Read ()) {
                     yield return new PlaylistSource (
                         reader[1] as string, Convert.ToInt32 (reader[0]),

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs	Mon Apr 28 21:42:18 2008
@@ -418,10 +418,11 @@
             return String.IsNullOrEmpty (ConditionSql) ? " " : String.Format ("{0} ({1})", with, ConditionSql);
         }
 
-        public static IEnumerable<SmartPlaylistSource> LoadAll ()
+        public static IEnumerable<SmartPlaylistSource> LoadAll (int primary_id)
         {
             using (IDataReader reader = ServiceManager.DbConnection.Query (
-                "SELECT SmartPlaylistID, Name, Condition, OrderBy, LimitNumber, LimitCriterion, PrimarySourceID FROM CoreSmartPlaylists")) {
+                @"SELECT SmartPlaylistID, Name, Condition, OrderBy, LimitNumber, LimitCriterion, PrimarySourceID 
+                    FROM CoreSmartPlaylists WHERE PrimarySourceID = ?", primary_id)) {
                 while (reader.Read ()) {
                     SmartPlaylistSource playlist = null;
                     try {

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs	Mon Apr 28 21:42:18 2008
@@ -78,36 +78,74 @@
             DatabaseSourceInitialize ();
         }
 
+        protected virtual bool HasArtistAlbum {
+            get { return true; }
+        }
+
+        protected DatabaseTrackListModel DatabaseTrackModel {
+            get {
+                return track_model ?? track_model = new DatabaseTrackListModel (ServiceManager.DbConnection, TrackProvider);
+            }
+            set { track_model = value; }
+        }
+
+        private IDatabaseTrackModelCache track_cache;
+        protected IDatabaseTrackModelCache TrackCache {
+            get {
+                return track_cache ?? track_cache = new DatabaseTrackModelCache<DatabaseTrackInfo> (
+                    ServiceManager.DbConnection, UniqueId, DatabaseTrackModel, TrackProvider);
+            }
+            set { track_cache = value; }
+        }
+
+
+        private DatabaseTrackModelProvider<DatabaseTrackInfo> track_provider;
+        protected DatabaseTrackModelProvider<DatabaseTrackInfo> TrackProvider {
+            get {
+                return track_provider ?? track_provider = new DatabaseTrackModelProvider<DatabaseTrackInfo> (
+                    ServiceManager.DbConnection
+                );
+            }
+        }
+
         private void DatabaseSourceInitialize ()
         {
-            track_model = new DatabaseTrackListModel (ServiceManager.DbConnection, UniqueId);
-            artist_model = new DatabaseArtistListModel (track_model, ServiceManager.DbConnection, UniqueId);
-            album_model = new DatabaseAlbumListModel (track_model, artist_model, ServiceManager.DbConnection, UniqueId);
+            InitializeTrackModel ();
+
+            if (HasArtistAlbum) {
+                artist_model = new DatabaseArtistListModel (DatabaseTrackModel, ServiceManager.DbConnection, UniqueId);
+                album_model = new DatabaseAlbumListModel (DatabaseTrackModel, artist_model, ServiceManager.DbConnection, UniqueId);
+            }
+
             reload_limiter = new RateLimiter (RateLimitedReload);
         }
 
+        protected virtual void InitializeTrackModel ()
+        {
+        }
+
 #region Public Properties
 
         public override int Count {
-            get { return track_model.UnfilteredCount; }
+            get { return DatabaseTrackModel.UnfilteredCount; }
         }
 
         public override int FilteredCount {
-            get { return track_model.Count; }
+            get { return DatabaseTrackModel.Count; }
         }
 
         public TimeSpan Duration {
-            get { return track_model.Duration; }
+            get { return DatabaseTrackModel.Duration; }
         }
 
         public long FileSize {
-            get { return track_model.FileSize; }
+            get { return DatabaseTrackModel.FileSize; }
         }
 
         public override string FilterQuery {
             set {
                 base.FilterQuery = value;
-                track_model.Filter = FilterQuery;
+                DatabaseTrackModel.Filter = FilterQuery;
                 ThreadAssist.SpawnFromMain (delegate {
                     Reload ();
                 });
@@ -131,11 +169,11 @@
         }
 
         public override string TrackModelPath {
-            get { return DBusServiceManager.MakeObjectPath (track_model); }
+            get { return DBusServiceManager.MakeObjectPath (DatabaseTrackModel); }
         }
 
         public TrackListModel TrackModel {
-            get { return track_model; }
+            get { return DatabaseTrackModel; }
         }
         
         public AlbumListModel AlbumModel {
@@ -167,7 +205,7 @@
         protected void RateLimitedReload ()
         {
             lock (track_model) {
-                track_model.Reload ();
+                DatabaseTrackModel.Reload ();
                 OnUpdated ();
             }
         }
@@ -353,11 +391,12 @@
             }
         }
 
-        protected void AfterInitialized ()
+        protected virtual void AfterInitialized ()
         {
-            track_model.Initialize (artist_model, album_model);
+            DatabaseTrackModel.Initialize (TrackCache, artist_model, album_model);
 
             ThreadAssist.SpawnFromMain (delegate {
+                // TODO delay or get rid of this reload altogether
                 Reload ();
                 OnSetupComplete ();
             });

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs	Mon Apr 28 21:42:18 2008
@@ -183,11 +183,11 @@
 
             primary_sources[dbid] = this;
             
-            foreach (PlaylistSource pl in PlaylistSource.LoadAll ())
+            foreach (PlaylistSource pl in PlaylistSource.LoadAll (DbId))
                 if (pl.PrimarySourceId == dbid)
                     AddChildSource (pl);
 
-            foreach (SmartPlaylistSource pl in SmartPlaylistSource.LoadAll ())
+            foreach (SmartPlaylistSource pl in SmartPlaylistSource.LoadAll (DbId))
                 if (pl.PrimarySourceId == dbid)
                     AddChildSource (pl);
         }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs	Mon Apr 28 21:42:18 2008
@@ -107,11 +107,15 @@
                 tm_source.TrackModel.Parent = this;
                 ServiceManager.DBusServiceManager.RegisterObject (tm_source.TrackModel);
                 
-                tm_source.ArtistModel.Parent = this;
-                ServiceManager.DBusServiceManager.RegisterObject (tm_source.ArtistModel);
+                if (tm_source.ArtistModel != null) {
+                    tm_source.ArtistModel.Parent = this;
+                    ServiceManager.DBusServiceManager.RegisterObject (tm_source.ArtistModel);
+                }
                 
-                tm_source.AlbumModel.Parent = this;
-                ServiceManager.DBusServiceManager.RegisterObject (tm_source.AlbumModel);
+                if (tm_source.AlbumModel != null) {
+                    tm_source.AlbumModel.Parent = this;
+                    ServiceManager.DBusServiceManager.RegisterObject (tm_source.AlbumModel);
+                }
             }
         }
 

Modified: trunk/banshee/src/Core/Banshee.Services/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Makefile.am	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Makefile.am	Mon Apr 28 21:42:18 2008
@@ -13,6 +13,10 @@
 	Banshee.Collection.Database/DatabaseImportManager.cs \
 	Banshee.Collection.Database/DatabaseTrackInfo.cs \
 	Banshee.Collection.Database/DatabaseTrackListModel.cs \
+	Banshee.Collection.Database/DatabaseTrackModelCache.cs \
+	Banshee.Collection.Database/DatabaseTrackModelProvider.cs \
+	Banshee.Collection.Database/IDatabaseTrackModelCache.cs \
+	Banshee.Collection.Database/IDatabaseTrackModelProvider.cs \
 	Banshee.Collection/AlbumListModel.cs \
 	Banshee.Collection/ArtistListModel.cs \
 	Banshee.Collection/BansheeListModel.cs \

Modified: trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	Mon Apr 28 21:42:18 2008
@@ -53,6 +53,10 @@
 
         private DatabaseTrackInfo playing_track;
         private bool actions_loaded = false;
+
+        protected override bool HasArtistAlbum {
+            get { return false; }
+        }
         
         public PlayQueueSource () : base (Catalog.GetString ("Play Queue"), null, 0)
         {

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastItem.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastItem.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastItem.cs	Mon Apr 28 21:42:18 2008
@@ -57,61 +57,64 @@
         Paused = 9
     }
 
-    public class PodcastItem
+    public class PodcastItem : DatabaseTrackInfo
     {
-        [DatabaseColumn ("New", Constraints = DatabaseColumnConstraints.NotNull)]    
-        private int _new;
-        private int position;
-             
-        private IFeedItem item;
-        private long feedItemID;      
-        
-        private PodcastFeed feed;
-      
-        private int trackID;
-        private DatabaseTrackInfo track;
-        
-        private static BansheeModelProvider<PodcastItem> provider;
-        
-        public static BansheeModelProvider<PodcastItem> Provider {
+        private static BansheeModelProvider<PodcastItem> provider = new DatabaseTrackModelProvider<PodcastItem> (ServiceManager.DbConnection);
+        public static new BansheeModelProvider<PodcastItem> Provider {
             get { return provider; }
         }
+        
+        private bool @new;
+        private int position;
+        private long item_id;
 
-        public PodcastFeed Feed {
-            get { return feed; }
-            internal set { feed = value; }
+        /*private static BansheeModelProvider<PodcastItem> provider;
+        public new static BansheeModelProvider<PodcastItem> Provider {
+            get { return provider; }
+        }*/
+
+#region Properties
+
+        public Feed Feed {
+            get { return item.Feed; }
         }
         
-        public IFeedItem Item {
-            get { return item; }
-            internal set {
-                if (value != null) {
-                    item = value;
-                    feedItemID = item.LocalID;                    
-                } else {
-                    item = null;
-                    feedItemID = 0;
+        private FeedItem item;
+        public FeedItem Item {
+            get {
+                if (item == null && item_id > 0) {
+                    item = FeedItem.Provider.FetchSingle (item_id);
                 }
+                return item;
             }
+            set { item = value; item_id = value.DbId; }
         }
         
-        public IFeedEnclosure Enclosure {
-            get { 
-                IFeedEnclosure ret = null;
-            
-                if (item != null) {
-                    ret = item.Enclosure;
-                }
-                
-                return ret;
-            }
+        public bool New {
+            get { return @new; }
+            set { @new = value; }
+        }
+        
+        public int Position {
+            get { return position; }
+            set { position = value; }
+         }
+        
+        [DatabaseColumn ("ExternalID")]
+        public long ItemID {
+            get { return item_id; }
+            set { item_id = value; }
+        }
+        
+        public FeedEnclosure Enclosure {
+            get { return (item == null) ? null : item.Enclosure; }
         }
 
         public PodcastItemActivity Activity {
             get {
                 PodcastItemActivity ret = PodcastItemActivity.None;
             
-                if (Track != null) {
+                /*if (Track != null) {
                     if (ServiceManager.PlayerEngine.CurrentTrack == Track) {
                         if (ServiceManager.PlayerEngine.CurrentState == PlayerEngineState.Playing) {
                             ret = PodcastItemActivity.Playing;
@@ -146,40 +149,71 @@
                         ret = PodcastItemActivity.DownloadPaused;
                         break;                        
                     }
-                }
+                }*/
                 
                 return ret;
             }
         }
+
+#endregion
+
+#region Constructors
+    
+        public PodcastItem () : base ()
+        {
+        }
         
-        public string Title {
+        public PodcastItem (FeedItem feed_item) : base ()
+        {
+            Item = feed_item;
+        }
+
+#endregion
+
+        public void Delete ()
+        {
+            Provider.Delete (this);
+            //feed.Delete ();
+        }
+
+        public static void DeleteWithFeedId (long feed_id)
+        {
+            /*PodcastItem item = Provider.FetchFirstMatching (String.Format (
+                "primarysourceid = {0} and externalid = {1}", primary_id, feed_id
+            ));
+
+            if (item != null) {
+                item.Delete ();
+            }*/
+        }
+
+        /*public string Title {
             get { return item.Title; }
         }
         
         public string PodcastTitle {
-            get { return item.Parent.Title; }
+            get { return item.Feed.Title; }
         }
         
+        [VirtualDatabaseColumn ("PubDate", "PodcastItems", "TrackID", "TrackID")]
         public DateTime PubDate {
-            get { return item.PubDate.ToLocalTime (); }
+            get { return item.PubDate; }
+            set { item.PubDate = value; }
         }
-
-        // drr...  I know.  FeedItemID should be the primary key, but, it's a 
-        // long and sqlite is throwing a hissy fit, I'll look into it 
-        // again later when time isn't short.
-        private int id = 0;
-        [DatabaseColumn ("ID", Constraints = DatabaseColumnConstraints.PrimaryKey)]
-        private int ID {
-            get { return id; }
-            set { id = value; }
+        
+        [DatabaseColumn]
+        public string Author {
+            get { return item.Author; }
+            set { item.Author = value; }
         }
-
+        
         [DatabaseColumn ("FeedItemID", Constraints = DatabaseColumnConstraints.NotNull)]
         public long FeedItemID {
             get { return feedItemID; }
             private set { feedItemID = value; }
         }
 
+        [DatabaseColumn ("New", Constraints = DatabaseColumnConstraints.NotNull)]   
         public bool New {
             get { return (_new != 0) ? true : false; }
             set { _new = (value) ? 1 : 0; }
@@ -191,120 +225,6 @@
             private set { 
                 position = (value < 0) ? 0 : value;
             }
-        }        
-
-        [DatabaseColumn ("TrackID", Constraints = DatabaseColumnConstraints.NotNull)]
-        public int TrackID {
-            get { return trackID; }
-            private set { trackID = value; }
-        }
-        
-        public DatabaseTrackInfo Track {
-            get {  
-                if (track == null && trackID != 0) {
-                    Console.WriteLine ("Fetching Track:  {0}", trackID);
-                    track = DatabaseTrackInfo.Provider.FetchSingle (trackID);
-                }             
-                
-                return track;
-            }
-            
-            set {
-                if (value != null) {
-                    track = value;
-                    trackID = track.TrackId;                    
-                } else {
-                    track = null;
-                    trackID = 0;
-                }
-            }
-        }
-
-        static PodcastItem ()
-        {
-            try {
-                if (!ServiceManager.DbConnection.TableExists ("PodcastItems")) {
-                    ServiceManager.DbConnection.Execute (@"
-                        CREATE TABLE PodcastItems (
-                            ID         INTEGER PRIMARY KEY,
-                            FeedItemID INTEGER NOT NULL DEFAULT 0,
-                            TrackID    INTEGER NOT NULL DEFAULT 0,
-                            New        INTEGER NOT NULL DEFAULT 0,
-                            Position   INTEGER NOT NULL DEFAULT 0
-                        );
-                        
-                        CREATE INDEX podcast_item_id_index ON PodcastItems(ID);                    
-                        CREATE INDEX feed_item_id_index ON PodcastItems(FeedItemID);
-                        CREATE INDEX track_id_index ON PodcastItems(TrackID);
-                    ");
-                }
-                
-                provider = new BansheeModelProvider<PodcastItem> (
-                    ServiceManager.DbConnection, "PodcastItems"
-                );   
-            } catch (Exception e) { Console.WriteLine (e.Message); throw; }
-        }   
-
-        public PodcastItem ()
-        {
-        }
-
-        public PodcastItem (IFeedItem item)
-        {
-            if (item == null) {
-                throw new ArgumentNullException ("item");                
-            }
-
-            Item = item;
-        }
-        
-        public void Save ()
-        {
-            provider.Save (this);
-        }  
-        
-        public void Delete () 
-        {
-            PodcastItem.Delete (this);
-        }
-        
-        private static string deleteBaseQuery = "DELETE FROM PodcastItems WHERE ID ";
-        
-        public static void Delete (PodcastItem pi)
-        {
-            if (pi.ID != 0) {
-                ServiceManager.DbConnection.Execute (
-                    new HyenaSqliteCommand (
-                        deleteBaseQuery + "= ?", pi.ID
-                    )
-                );
-            }  
-        }        
-        
-        public static void Delete (IEnumerable<PodcastItem> pis)
-        {
-            List<int> piids = new List<int> ();
-        
-            foreach (PodcastItem pi in pis) {                    
-                if (pi.ID != 0) {
-                    piids.Add (pi.ID);
-                }
-            }
-            
-            StringBuilder builder = new StringBuilder (deleteBaseQuery + "IN (");
-            
-            if (piids.Count > 0) {
-                foreach (int id in piids) {
-                    builder.AppendFormat ("{0},", id);
-                }
-                
-                builder.Remove (builder.Length-1, 1);
-                builder.Append (");");
-                
-                ServiceManager.DbConnection.Execute (
-                    new HyenaSqliteCommand (builder.ToString ())
-                );                
-            }
-        }
+        }        */
     }
-}
\ No newline at end of file
+}

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastFeedPropertiesDialog.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastFeedPropertiesDialog.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastFeedPropertiesDialog.cs	Mon Apr 28 21:42:18 2008
@@ -32,6 +32,7 @@
 using Gtk;
 using Pango;
 
+using Migo.Syndication;
 using Banshee.Base;
 using Banshee.Podcasting.Data;
 
@@ -39,10 +40,10 @@
 {
     internal class PodcastFeedPropertiesDialog : Dialog
     {
-        private PodcastFeed feed;
+        private Feed feed;
         private SyncPreferenceComboBox new_episode_option_combo;
 
-        public PodcastFeedPropertiesDialog (PodcastFeed feed)
+        public PodcastFeedPropertiesDialog (Feed feed)
         {
             this.feed = feed;
 
@@ -91,20 +92,20 @@
             new_episode_option_label.SetAlignment (0f, 0.5f);
             new_episode_option_label.Justify = Justification.Left;
 
-            Label last_updated_text = new Label (feed.Feed.LastDownloadTime.ToString ("f"));
+            Label last_updated_text = new Label (feed.LastDownloadTime.ToString ("f"));
             last_updated_text.Justify = Justification.Left;
             last_updated_text.SetAlignment (0f, 0f);
 
-            Label feed_url_text = new Label (feed.Feed.Url.ToString ());
+            Label feed_url_text = new Label (feed.Url.ToString ());
             feed_url_text.Wrap = false;
             feed_url_text.Selectable = true;
             feed_url_text.SetAlignment (0f, 0f);
             feed_url_text.Justify = Justification.Left;
             feed_url_text.Ellipsize = Pango.EllipsizeMode.End;
 
-            string description_string = (String.IsNullOrEmpty (feed.Feed.Description)) ?
+            string description_string = (String.IsNullOrEmpty (feed.Description)) ?
                                         Catalog.GetString ("No description available") :
-                                        feed.Feed.Description;
+                                        feed.Description;
 
             if (!description_string.StartsWith ("\""))
             {
@@ -133,7 +134,7 @@
             description_viewport.Add (descrition_text);
             description_scroller.Add (description_viewport);
 
-            new_episode_option_combo = new SyncPreferenceComboBox (feed.SyncPreference);
+            new_episode_option_combo = new SyncPreferenceComboBox (feed.AutoDownload);
 
             table.Attach (
                 feed_url_label, 0, 1, 0, 1,
@@ -204,11 +205,10 @@
 
             if (args.ResponseId == Gtk.ResponseType.Ok)
             {
-                SyncPreference new_sync_pref = new_episode_option_combo.ActiveSyncPreference;
+                FeedAutoDownload new_sync_pref = new_episode_option_combo.ActiveSyncPreference;
 
-                if (feed.SyncPreference != new_sync_pref)
-                {
-                    feed.SyncPreference = new_sync_pref;
+                if (feed.AutoDownload != new_sync_pref) {
+                    feed.AutoDownload = new_sync_pref;
                     feed.Save ();
                 }
             }

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastPropertiesDialog.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastPropertiesDialog.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastPropertiesDialog.cs	Mon Apr 28 21:42:18 2008
@@ -50,7 +50,7 @@
             
             this.pi = pi;            
             
-            Title = pi.Title;
+            Title = pi.TrackTitle;
             BuildWindow ();
             //IconThemeUtils.SetWindowIcon (this);
         }
@@ -90,7 +90,7 @@
             Label feed_title_text = new Label (pi.Feed.Title);
             labels.Add (feed_title_text);
 
-            Label pubdate_text = new Label (pi.PubDate.ToString ("f"));
+            Label pubdate_text = new Label (pi.Item.PubDate.ToString ("f"));
             labels.Add (pubdate_text);
 
             Label url_text = new Label (pi.Item.Link);

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastSubscribeDialog.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastSubscribeDialog.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/PodcastSubscribeDialog.cs	Mon Apr 28 21:42:18 2008
@@ -34,6 +34,8 @@
 using Banshee.Gui;
 using Banshee.Base;
 
+using Migo.Syndication;
+
 using Banshee.Podcasting;
 using Banshee.Podcasting.Data;
 
@@ -45,13 +47,12 @@
         private Gtk.AccelGroup accelGroup;
         private SyncPreferenceComboBox syncCombo;        
 
-
         public string Url {
             get { return url_entry.Text; }
             set { url_entry.Text = value; }
         }
 
-        public SyncPreference SyncPreference
+        public FeedAutoDownload SyncPreference
         {
             get { return syncCombo.ActiveSyncPreference; }
         }

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/SyncPreferenceComboBox.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/SyncPreferenceComboBox.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Dialog/SyncPreferenceComboBox.cs	Mon Apr 28 21:42:18 2008
@@ -30,6 +30,7 @@
 using System;
 using Mono.Unix;
 
+using Migo.Syndication;
 using Banshee.Podcasting.Data;
 
 namespace Banshee.Podcasting.Gui
@@ -42,21 +43,23 @@
             Catalog.GetString ("Let me decide which episodes to download")
         };
 
-        public SyncPreference ActiveSyncPreference 
+        public FeedAutoDownload ActiveSyncPreference 
         {
-            get { return (SyncPreference) Active; }
+            get { return (FeedAutoDownload) Active; }
         }
 
-        public SyncPreferenceComboBox (SyncPreference syncPref) : base (combo_text_entries)
+        public SyncPreferenceComboBox (FeedAutoDownload syncPref) : base (combo_text_entries)
         {
-            if ((int) syncPref >= (int) SyncPreference.All &&
-                (int) syncPref <= (int) SyncPreference.None) {
+            if ((int) syncPref >= (int) FeedAutoDownload.All &&
+                (int) syncPref <= (int) FeedAutoDownload.None) {
                 Active = (int) syncPref;
             } else {
-                Active = (int) SyncPreference.One;
+                Active = (int) FeedAutoDownload.One;
             }
         }
 
-        public SyncPreferenceComboBox (): this (SyncPreference.One) {} 
+        public SyncPreferenceComboBox (): this (FeedAutoDownload.One)
+        {
+        }
     }
 }

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/ColumnCells/FeedActivityColumnCell.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/ColumnCells/FeedActivityColumnCell.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/ColumnCells/FeedActivityColumnCell.cs	Mon Apr 28 21:42:18 2008
@@ -34,6 +34,7 @@
 using Cairo;
 
 using Hyena.Data.Gui;
+using Migo.Syndication;
 
 using Banshee.Gui;
 using Banshee.Podcasting.Data;
@@ -42,8 +43,7 @@
 {
     public class FeedActivityColumnCell : PixbufColumnCell
     {
-        Dictionary<PodcastFeedActivity,Pixbuf> pixbufs = 
-            new Dictionary<PodcastFeedActivity,Pixbuf> ();
+        Dictionary<PodcastFeedActivity, Pixbuf> pixbufs = new Dictionary<PodcastFeedActivity, Pixbuf> ();
     
         public FeedActivityColumnCell (string property) : base (property)
         {
@@ -67,29 +67,20 @@
             
             Gtk.Image pp = new Gtk.Image ();
 
-            pixbufs[PodcastFeedActivity.Updating] = 
-                pp.RenderIcon (Stock.Refresh, IconSize.Menu, "");
-            
-            pixbufs[PodcastFeedActivity.UpdateFailed] =
-                pp.RenderIcon (Stock.DialogError, IconSize.Menu, "");
-            
-            pixbufs[PodcastFeedActivity.ItemsDownloading] =
-                pp.RenderIcon (Stock.GoForward, IconSize.Menu, "");
+            pixbufs[PodcastFeedActivity.Updating] = pp.RenderIcon (Stock.Refresh, IconSize.Menu, String.Empty);
+            pixbufs[PodcastFeedActivity.UpdateFailed] = pp.RenderIcon (Stock.DialogError, IconSize.Menu, String.Empty);
+            pixbufs[PodcastFeedActivity.ItemsDownloading] = pp.RenderIcon (Stock.GoForward, IconSize.Menu, String.Empty);
             
             pp.Sensitive = false;
-            pixbufs[PodcastFeedActivity.ItemsQueued] = 
-                pp.RenderIcon (Stock.GoForward, IconSize.Menu, "");
+            pixbufs[PodcastFeedActivity.ItemsQueued] = pp.RenderIcon (Stock.GoForward, IconSize.Menu, String.Empty);
         }
         
-        public override void Render (CellContext context, 
-                                     StateType state, 
-                                     double cellWidth, 
-                                     double cellHeight)
+        public override void Render (CellContext context, StateType state, double cellWidth, double cellHeight)
         {
             PodcastFeedActivity bound = (PodcastFeedActivity)BoundObject;
             Pixbuf = (pixbufs.ContainsKey (bound)) ? pixbufs[bound] : null;
             
             base.Render (context, state, cellWidth, cellHeight);
         }
-    }   
+    }
 }

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models/PodcastFeedModel.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models/PodcastFeedModel.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models/PodcastFeedModel.cs	Mon Apr 28 21:42:18 2008
@@ -42,7 +42,7 @@
         public const string Title = "Title";        
     }
 
-    public class PodcastFeedModel : ListModel<PodcastFeed>
+    public class PodcastFeedModel : ListModel<Feed>
     {
         public override int Count { 
             get { 
@@ -56,11 +56,11 @@
         {
         }
 
-        public override PodcastFeed this[int index] {
+        public override Feed this[int index] {
             get { 
                 lock (SyncRoot) {
                     if (index == 0) {
-                        return PodcastFeed.All;
+                        return Feed.All;
                     }
 
                     return (index <= List.Count) ? List[index-1] : null;                    
@@ -68,18 +68,18 @@
             }
         }    
 
-        public override ReadOnlyCollection<PodcastFeed> CopySelectedItems () 
+        public override ReadOnlyCollection<Feed> CopySelectedItems () 
         {
-            List<PodcastFeed> feeds = null;
+            List<Feed> feeds = null;
             
             lock (SyncRoot) {
-                ModelSelection<PodcastFeed> selected = SelectedItems;
+                ModelSelection<Feed> selected = SelectedItems;
                 
                 if (selected.Count > 0) {
-                    feeds = new List<PodcastFeed> (selected.Count);
+                    feeds = new List<Feed> (selected.Count);
                     
-                    foreach (PodcastFeed feed in selected) {
-                        if (feed != PodcastFeed.All) {
+                    foreach (Feed feed in selected) {
+                        if (feed != Feed.All) {
                             feeds.Add (feed);                            
                         }
                     }
@@ -87,7 +87,7 @@
             }
 
             return (feeds != null) ? 
-                new ReadOnlyCollection<PodcastFeed> (feeds) : null;
+                new ReadOnlyCollection<Feed> (feeds) : null;
         }    
     
         public override void Sort ()
@@ -105,17 +105,17 @@
             }
         }
         
-        private class TitleComparer : SortTypeComparer<PodcastFeed>
+        private class TitleComparer : SortTypeComparer<Feed>
         {
             public TitleComparer (SortType type) : base (type)
             {
             }
             
-            public override int Compare (PodcastFeed lhs, PodcastFeed rhs)
+            public override int Compare (Feed lhs, Feed rhs)
             {
                 int ret = String.Compare (lhs.Title, rhs.Title);   
                 return (SortType == SortType.Ascending) ? ret * -1 : ret;
             }
         } 
     }
-}
\ No newline at end of file
+}

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models/PodcastItemModel.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models/PodcastItemModel.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Models/PodcastItemModel.cs	Mon Apr 28 21:42:18 2008
@@ -30,6 +30,7 @@
 using System.Collections.Generic;
 
 using Hyena.Data;
+using Migo.Syndication;
 using Banshee.Podcasting.Data;
 
 namespace Banshee.Podcasting.Gui
@@ -40,108 +41,4 @@
         public const string PubDate = "PubDate";
         public const string Title = "Title";        
     }
-
-    public class PodcastItemModel : FilterableListModel<PodcastItem>
-    {      
-        public PodcastItemModel ()
-        {
-        }
-        
-        public void FilterOnFeed (PodcastFeed feed)
-        {
-            if (feed == null || feed == PodcastFeed.All) {
-                Filter = null;
-            } else {
-                Filter = delegate (PodcastItem item) {
-                    return (item.Feed.FeedID == feed.FeedID);
-                };            
-            }
-        }
-        
-        public void FilterOnFeeds (ICollection<PodcastFeed> feeds)
-        {
-            if (feeds != null) {
-                Filter = delegate (PodcastItem item) {
-                    return (feeds.Contains (item.Feed));
-                };                           
-            } else {
-                Filter = null;
-            }
-        }       
-        
-        public override void Sort ()
-        {
-            lock (SyncRoot) {
-                if (SortColumn == null) {
-                    return;
-                }
-                
-                switch (SortColumn.SortKey) {
-                case PodcastItemSortKeys.PodcastTitle:
-                    List.Sort (new PodcastTitleComparer (SortColumn.SortType));
-                    break;
-                case PodcastItemSortKeys.PubDate:
-                    List.Sort (new PubDateComparer (SortColumn.SortType));
-                    break;
-                case PodcastItemSortKeys.Title:
-                    List.Sort (new TitleComparer (SortColumn.SortType));
-                    break;                    
-                }  
-            }
-        }
-        
-        private class PodcastTitleComparer : SortTypeComparer<PodcastItem>
-        {
-            public PodcastTitleComparer (SortType type) : base (type)
-            {
-            }
-            
-            public override int Compare (PodcastItem lhs, PodcastItem rhs)
-            {
-                int ret = String.Compare (lhs.PodcastTitle, rhs.PodcastTitle);
-                
-                // Just incase two podcasts have the same title...
-                // found this when I tinyurl'd a feed.
-                if (ret == 0) {
-                    ret = String.Compare (
-                        lhs.Item.Parent.Url, rhs.Item.Parent.Url
-                    );
-                }
-
-                if (ret == 0) {
-                    ret = DateTime.Compare (rhs.PubDate, lhs.PubDate);
-                } else if (SortType == SortType.Ascending) {
-                    ret *= (-1);
-                }
-                
-                return ret;
-            }
-        }
-        
-        private class PubDateComparer : SortTypeComparer<PodcastItem>
-        {
-            public PubDateComparer (SortType type) : base (type)
-            {
-            }
-            
-            public override int Compare (PodcastItem lhs, PodcastItem rhs)
-            {
-                int ret = DateTime.Compare (lhs.PubDate, rhs.PubDate);
-                return (SortType == SortType.Ascending) ? ret * (-1) : ret;
-            }
-        }        
-        
-        private class TitleComparer : SortTypeComparer<PodcastItem>
-        {
-            public TitleComparer (SortType type) : base (type)
-            {
-            }
-            
-            public override int Compare (PodcastItem lhs, PodcastItem rhs)
-            {
-                int ret = String.Compare (lhs.Title, rhs.Title);
-                return (SortType == SortType.Ascending) ? ret * (-1) : ret;
-            }
-        }        
-    }
-}
\ No newline at end of file
+}

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSource.cs	Mon Apr 28 21:42:18 2008
@@ -36,9 +36,11 @@
 
 using Hyena.Data;
 using Hyena.Data.Gui;
+using Hyena.Data.Sqlite;
 
 using Banshee.Gui;
 using Banshee.Base;
+using Banshee.Database;
 using Banshee.Collection;
 using Banshee.ServiceStack;
 using Banshee.Collection.Database;
@@ -52,123 +54,98 @@
 
 namespace Banshee.Podcasting.Gui
 {
-    public class PodcastSource : PrimarySource
-    {        
-        private int count;
-
-        private string baseDirectory;
-
- 	    private PodcastFeedView feedView;
- 	    private PodcastItemView itemView;     
- 	    
-        private PodcastFeedModel feedModel;
-        private PodcastItemModel itemModel;           
-        
-        private string tuid = "podcasting";
-        
-        private readonly object sync = new object (); 
-
-        public override string BaseDirectory {
-            get { return baseDirectory; }
+    public class PodcastListModel : DatabaseTrackListModel, IListModel<PodcastItem>
+    {
+        public PodcastListModel (BansheeDbConnection conn, IDatabaseTrackModelProvider provider) : base (conn, provider)
+        {
         }
         
-        internal string BaseDirectorySet {
-            set { baseDirectory = value; }        
-        }
-
-        public override bool CanRename {
-            get { return false; }
-        }
-               
-        public override int Count {
-            get { lock (sync) { return count; } }
-        }
-        
-        public int CountSet {
-            set { 
-                lock (sync) {
-                    if (count != value) {
-                        count = value;
-                        OnUpdated ();
-                    }
-                } 
-            }        
-        }
-       
-        public PodcastFeedModel FeedModel {
-            get { return feedModel; }
+        public new PodcastItem this[int index] {
+            get {
+                lock (this) {
+                    return cache.GetValue (index) as PodcastItem;
+                }
+            }
         }
+    }
+    
+    public class PodcastSource : PrimarySource
+    {
+        private PodcastFeedModel feed_model;
         
-        public PodcastItemModel ItemModel {
-            get { return itemModel; }
-        }        
-
+        private PodcastFeedView feed_view;
         public PodcastFeedView FeedView {
-            get { return feedView; }
+            get { return feed_view; }
         }
         
+        private PodcastItemView item_view;
         public PodcastItemView ItemView {
-            get { return itemView; }
-        }        
-
-        protected override string TypeUniqueId {
-            get { return tuid; }
+            get { return item_view; }
+        }
+        
+        private string baseDirectory;
+        public override string BaseDirectory {
+            get { return baseDirectory; }
         }
 
-        public override bool CanSearch {
+        public override bool CanRename {
             get { return false; }
         }
-        
+
         public override bool CanAddTracks {
             get { return false; }
         }
+        
+        public PodcastFeedModel FeedModel {
+            get { return feed_model; }
+        }
 
-        public PodcastSource (PodcastFeedModel feedModel,
-                              PodcastItemModel itemModel) : 
-                              this (null, feedModel, itemModel)
+        public PodcastSource () : this (null)
         {
         }
 
-        public PodcastSource (string baseDirectory,
-                              PodcastFeedModel feedModel,
-                              PodcastItemModel itemModel) : base (
-                              "PodcastLibrary",
-                              Catalog.GetString ("Podcasts"), 
-                              "PodcastLibrary", 100)
-        {
-            if (feedModel == null) {
-                throw new ArgumentNullException ("feedModel");
-            } else if (itemModel == null) {
-                throw new ArgumentNullException ("itemModel");
-            }
-            
+        public PodcastSource (string baseDirectory) : base ("PodcastLibrary", Catalog.GetString ("Podcasts"), "PodcastLibrary", 100)
+        {
             this.baseDirectory = baseDirectory;
-            // track_model
-            album_model = null;
-            artist_model = null;
-            
-            this.feedModel = feedModel;
-            this.itemModel = itemModel;
-
-            feedView = new PodcastFeedView ();
-            itemView = new PodcastItemView ();
 
             Properties.SetString ("Icon.Name", "podcast-icon-22");
             Properties.SetString ("ActiveSourceUIResource", "ActiveSourceUI.xml");
             Properties.SetString ("GtkActionPath", "/PodcastSourcePopup");
             Properties.Set<bool> ("Nereid.SourceContents.HeaderVisible", false);
 
+            feed_view = new PodcastFeedView ();
+            item_view = new PodcastItemView ();
             Properties.Set<ISourceContents> (
                 "Nereid.SourceContents", 
-                new PodcastSourceContents (feedView, itemView)
+                new PodcastSourceContents (feed_view, item_view)
             );
         }
+        
+        protected override bool HasArtistAlbum {
+            get { return false; }
+        }
+        
+        protected override void InitializeTrackModel ()
+        {
+            DatabaseTrackModelProvider<PodcastItem> track_provider =
+                new DatabaseTrackModelProvider<PodcastItem> (ServiceManager.DbConnection);
+
+            DatabaseTrackModel = new PodcastListModel (ServiceManager.DbConnection, track_provider);
+
+            TrackCache = new DatabaseTrackModelCache<PodcastItem> (ServiceManager.DbConnection,
+                    UniqueId, track_model, track_provider);
+                    
+            feed_model = new PodcastFeedModel ();
+            
+            AfterInitialized ();
+        }
 
         public override void Reload ()
         {
-            itemModel.Reload ();
-            feedModel.Reload ();
-        }        
+            feed_model.Reload ();
+            TrackModel.Reload ();
+        }
+
 /*
         public new TrackListModel TrackModel {
             get { return null; }

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSourceContents.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSourceContents.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSourceContents.cs	Mon Apr 28 21:42:18 2008
@@ -41,6 +41,7 @@
 using Banshee.ServiceStack;
 
 using Banshee.Collection;
+using Banshee.Collection.Database;
 using Banshee.Collection.Gui;
 
 using Banshee.Podcasting.Data;
@@ -83,10 +84,6 @@
  	
         public bool SetSource (ISource source)
         {
-            bool ret = false;
-            
-            Console.WriteLine ("SetSource Called");
-            
             PodcastSource ps = source as PodcastSource;
             
             if (ps != null) {
@@ -99,18 +96,16 @@
                 itemView.HeaderVisible = true;
                 
                 feedView.SetModel (ps.FeedModel);
-                itemView.SetModel (ps.ItemModel);
+                itemView.SetModel (ps.TrackModel as PodcastListModel);
                 
-                ret = true;
+                return true;
             }
             
-            return ret;             
+            return false;
         }
         
         public void ResetSource ()
         {
-            Console.WriteLine ("ResetSource Called");
-
             SaveState ();           
 
             feedView.SetModel (null);
@@ -125,8 +120,6 @@
 
         private void InitializeWidget ()
         {
-            Console.WriteLine ("InitializeWidget Called");
-            
             itemViewColumnController = 
                 itemView.ColumnController as PersistentColumnController;
             
@@ -174,50 +167,6 @@
             itemCC.Save ();
         }
 
-
-        // Was going to add bookmarking but looking at the actual bookmark code
-        // it appears that the PlayerEngine needs to be worked on before a
-        // non-fucked implementation can be implemented.
-        
-        // <abortion>
-        
-        // See bookmark extension.        
-    /*        
-        private uint position;
-        private TrackInfo currentTrack;
-        
-        private TrackInfo previousPlayerEngineTrack;        
-        private void HandleEventChanged (object sender, PlayerEngineEventArgs e)
-        {
-
-        }
-        
-        private void HandleStateChanged (object sender, PlayerEngineStateArgs args)
-        {
-            if (args.State == PlayerEngineState.Playing) {
-                if (currentTrack == ServiceManager.PlayerEngine.CurrentTrack) {                
-                    if (!ServiceManager.PlayerEngine.CurrentTrack.IsLive) {
-                        // Sleep in 5ms increments for at most 250ms waiting for CanSeek to be true
-                        int count = 0;
-                        while (count < 100 && !ServiceManager.PlayerEngine.CanSeek) {
-                            System.Threading.Thread.Sleep (5);
-                            count++;
-                        }
-                    }
-                    
-                    if (ServiceManager.PlayerEngine.CanSeek) {
-                        Console.WriteLine (position);
-                        ServiceManager.PlayerEngine.Position = position;
-                    }
-                } else if (currentTrack == previousPlayerEngineTrack) {
-                    
-                }
-                
-                previousPlayerEngineTrack = ServiceManager.PlayerEngine.CurrentTrack;                 
-            }
-        }        
-        // </abortion>
-    */
         public static readonly SchemaEntry<int> VPanedPositionSchema = new SchemaEntry<int> (
             "plugins.podcasting", "vpaned_position", 120, "VPaned Position", ""
         );     

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views/PodcastFeedView.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views/PodcastFeedView.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views/PodcastFeedView.cs	Mon Apr 28 21:42:18 2008
@@ -47,7 +47,7 @@
 
 namespace Banshee.Podcasting.Gui
 {
-    public class PodcastFeedView : ListView<PodcastFeed>
+    public class PodcastFeedView : ListView<Feed>
     {
         private ColumnController columnController;
         
@@ -94,7 +94,7 @@
             Menu popup;
             PodcastFeedModel model = Model as PodcastFeedModel;
             
-            ReadOnlyCollection<PodcastFeed> feeds = model.CopySelectedItems ();
+            ReadOnlyCollection<Feed> feeds = model.CopySelectedItems ();
             
             if (feeds.Count == 0) {
                 popup = allPopup;         
@@ -116,4 +116,4 @@
             return true;
         } 
     }
-}
\ No newline at end of file
+}

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views/PodcastItemView.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views/PodcastItemView.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/Views/PodcastItemView.cs	Mon Apr 28 21:42:18 2008
@@ -37,7 +37,9 @@
 
 using Banshee.Gui;
 using Banshee.ServiceStack;
+using Banshee.Collection;
 using Banshee.Collection.Gui;
+using Banshee.Collection.Database;
 
 using Migo.Syndication;
 
@@ -45,7 +47,7 @@
 
 namespace Banshee.Podcasting.Gui
 {
-    public class PodcastItemView : ListView<PodcastItem>
+    public class PodcastItemView : ListView<TrackInfo>
     {
         private PersistentColumnController columnController;
         
@@ -60,10 +62,11 @@
             );
             
             columnController.AddRange (
-                new Column (null, Catalog.GetString ("Activity"), new PodcastItemActivityColumn ("Activity"), 0.00, true, 26, 26),            
+                new Column ("test", new ColumnCellText ("TrackTitle", true), 0.45, true)
+                /*new Column (null, Catalog.GetString ("Activity"), new PodcastItemActivityColumn ("Activity"), 0.00, true, 26, 26),            
                 new SortableColumn (Catalog.GetString ("Title"), new ColumnCellText ("Title", true), 0.30, PodcastItemSortKeys.Title, true),
                 podcastTitleSortColumn,
-                new SortableColumn (Catalog.GetString ("Date"), new ColumnCellDateTime ("PubDate", false), 0.5, PodcastItemSortKeys.PubDate, true)                
+                new SortableColumn (Catalog.GetString ("Date"), new ColumnCellDateTime ("PubDate", false), 0.5, PodcastItemSortKeys.PubDate, true) */
             );
             
             podcastTitleSortColumn.SortType = Hyena.Data.SortType.Descending;
@@ -101,8 +104,7 @@
                 markOldItem = uiManager.GetWidget ("/PodcastItemViewPopup/PodcastItemMarkOld") as MenuItem;              
             }
             
-            PodcastItemModel model = Model as PodcastItemModel;
-            ReadOnlyCollection<PodcastItem> items = model.CopySelectedItems (); 
+            DatabaseTrackListModel model = Model as DatabaseTrackListModel;
             
             bool showCancel = false;            
             bool showDownload = false;
@@ -110,9 +112,10 @@
             bool showMarkNew = false;
             bool showMarkOld = false;
             
+            ModelSelection<Banshee.Collection.TrackInfo> items = model.SelectedItems;
+            
             foreach (PodcastItem i in items) {
-                if (showCancel && showDownload && 
-                    showMarkNew && showMarkOld) {
+                if (showCancel && showDownload && showMarkNew && showMarkOld) {
                     break;
                 } else if (!showDownload &&
                     i.Activity == PodcastItemActivity.None ||
@@ -125,15 +128,13 @@
                     i.Activity == PodcastItemActivity.DownloadPaused                     
                 ) {
                     showCancel = true;
-                } else if (i.Track != null &&
-                           (!showMarkNew ||
-                           !showMarkOld)) {
+                }/* else if ((!showMarkNew || !showMarkOld)) {
                     if (i.New) {
                         showMarkOld = true;
                     } else { 
                         showMarkNew = true;
                     }
-                } 
+                }*/
             }
             
             if (items.Count > 1) {

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastCore.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastCore.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastCore.cs	Mon Apr 28 21:42:18 2008
@@ -50,133 +50,59 @@
 {
     public partial class PodcastCore : IDisposable
     {  
-        private readonly string tmpDownloadPath;
-        private string tmpEnclosurePath; 
+        private readonly string tmp_download_path;
+        private string tmp_enclosure_path; 
             
         private bool disposed;
         
-        private DownloadManager dm;
-        private DownloadManagerInterface dmInterface;
+        private DownloadManager download_manager;
+        private DownloadManagerInterface download_manager_iface;
         
-        private FeedsManager feedsManager;
+        private FeedsManager feeds_manager;
         
-        private PodcastFeedModel feedModel;
-        private PodcastItemModel itemModel;
-        
-        private PodcastSource podcastSource;
-        private PodcastImportManager importManager;
-        
-        private Dictionary<long,PodcastItem> itemDict;
-        private Dictionary<long,PodcastFeed> feedDict;
+        private PodcastSource source;
+        //private PodcastImportManager import_manager;
         
         private readonly object sync = new object ();
 
         public PodcastCore ()
         {
-            tmpEnclosurePath = Path.Combine (Paths.LibraryLocation, "Podcasts"); 
-            tmpDownloadPath = Path.Combine (Paths.ApplicationData, "downloads");
+            // TODO translate Podcasts folder?
+            tmp_enclosure_path = Path.Combine (Paths.LibraryLocation, "Podcasts");
+            tmp_download_path = Path.Combine (Paths.ApplicationData, "downloads");
             
-            dm = new DownloadManager (2, tmpDownloadPath);  
+            download_manager = new DownloadManager (2, tmp_download_path);  
 
-            dmInterface = new DownloadManagerInterface (dm);
-            dmInterface.Initialize ();    
+            download_manager_iface = new DownloadManagerInterface (download_manager);
+            download_manager_iface.Initialize ();    
     
-            feedsManager = new FeedsManager (
-                Path.Combine (Paths.ApplicationData, "syndication.db"), dm
-            );
-
-// All of these need to be moved into the FeedsManager as part of the larger 
-// refactoring effort.
-            dm.Group.TaskAssociated += OnTaskAssociated;                        
-            dm.Group.TaskStatusChanged += OnTaskStatusChanged;
+            feeds_manager = new FeedsManager (ServiceManager.DbConnection, download_manager);
+
+            download_manager.Group.TaskAssociated += OnTaskAssociated;                        
+            download_manager.Group.TaskStatusChanged += OnTaskStatusChanged;
             
 //            dm.Group.TaskStopped += OnTaskStoppedHandler;                
-            dm.Group.TaskStarted += TaskStartedHandler;   
-//
-            feedsManager.FeedAdded += OnFeedAddedHandler;
-            feedsManager.FeedDeleted += OnFeedRemovedHandler;
-            feedsManager.FeedRenamed += OnFeedRenamedHandler;
-            feedsManager.FeedUrlChanged += OnFeedRenamedHandler;
-            
-            feedsManager.FeedItemAdded += OnFeedItemAddedHandler;
-            feedsManager.FeedItemRemoved += OnFeedItemRemovedHandler;
-            feedsManager.FeedItemCountChanged += OnFeedItemCountChanged;
-            
-            feedsManager.FeedDownloading += OnFeedUpdatingHandler;
-            feedsManager.FeedDownloadCompleted += OnFeedDownloadCompletedHandler;
-            feedsManager.FeedDownloadCountChanged += OnFeedDownloadCountChangedHandler;            
-            
-            feedsManager.EnclosureDownloadCompleted += OnTaskStoppedHandler;
+            download_manager.Group.TaskStarted += TaskStartedHandler;   
+
+            feeds_manager.FeedAdded += OnFeedAddedHandler;
+            feeds_manager.FeedDeleted += OnFeedRemovedHandler;
+            feeds_manager.FeedRenamed += OnFeedRenamedHandler;
+            feeds_manager.FeedUrlChanged += OnFeedRenamedHandler;
+            
+            feeds_manager.FeedItemAdded += OnFeedItemAddedHandler;
+            feeds_manager.FeedItemRemoved += OnFeedItemRemovedHandler;
+            feeds_manager.FeedItemCountChanged += OnFeedItemCountChanged;
+            
+            feeds_manager.FeedDownloading += OnFeedUpdatingHandler;
+            feeds_manager.FeedDownloadCompleted += OnFeedDownloadCompletedHandler;
+            feeds_manager.FeedDownloadCountChanged += OnFeedDownloadCountChangedHandler;
+            feeds_manager.EnclosureDownloadCompleted += OnTaskStoppedHandler;
               
             ServiceManager.PlayerEngine.StateChanged += OnPlayerEngineStateChangedHandler;
-     
-            feedModel = new PodcastFeedModel ();
-            itemModel = new PodcastItemModel ();
 
-            List<IFeedItem> enclosureItems = null;
-            List<PodcastItem> podcastItems = new List<PodcastItem> ();
-            
-            feedDict = new Dictionary<long,PodcastFeed> ();
-            itemDict = new Dictionary<long,PodcastItem> ();
-
-            IEnumerable<PodcastItem> pis = PodcastItem.Provider.FetchAll ();
-            IEnumerable<PodcastFeed> feeds = PodcastFeed.Provider.FetchAll ();
-/*
-            //Dictionary<int,DatabaseTrackInfo> tracks = new Dictionary<int,DatabaseTrackInfo> ();                                
-            ServiceManager.DbConnection.BeginTransaction ();
-            
-            try {
-                foreach (PodcastItem p in pis) {
-                    if (p.TrackID != 0) {
-                        //p.Track = DatabaseTrackInfo.Provider.FetchSingle (p.TrackID);
-                        //tracks.Add (p.TrackID, p.Track);                            
-                    }
-                }
-                
-                ServiceManager.DbConnection.CommitTransaction ();
-            } catch {
-                ServiceManager.DbConnection.RollbackTransaction ();
-                throw;
-            }
-*/            
-            foreach (PodcastFeed feed in feeds) {
-                feedDict.Add (feed.FeedID, feed);                    
-            }         
-     
-            foreach (PodcastItem item in pis) {
-                itemDict.Add (item.FeedItemID, item);                    
-            }
-                
-            PodcastFeed f = null;
-            PodcastItem pi = null;
-            
-            foreach (IFeed feed in feedsManager.Feeds) {
-                if (feedDict.ContainsKey (feed.LocalID)) {
-                    f = feedDict[feed.LocalID];
-                    f.Feed = feed;
-                    
-                    feedModel.Add (f);
-                    enclosureItems = GetEnclosureItems (feed.Items);
-        
-                    if (enclosureItems.Count > 0) {
-                        foreach (IFeedItem fi in enclosureItems) {
-                            if (itemDict.ContainsKey (fi.LocalID)) {
-                                pi = itemDict[fi.LocalID];
-                                pi.Item = fi;
-                                pi.Feed = feedDict[fi.Parent.LocalID];
-                                podcastItems.Add (pi);
-                            }
-                        }                    
-                    }                        
-                }
-            }
-            
-            itemModel.Add (podcastItems);
             InitializeInterface ();
 
-            importManager = new PodcastImportManager (podcastSource);
-
-            UpdateCount ();
+            //import_manager = new PodcastImportManager (source);
         }
         
         bool disposing;
@@ -194,41 +120,41 @@
             ServiceManager.PlayerEngine.StateChanged -= OnPlayerEngineStateChangedHandler;
 
             Log.Debug ("Disposing dmInterface");    
-            if (dmInterface != null) {
-                dmInterface.Dispose ();                
-                dmInterface = null;
+            if (download_manager_iface != null) {
+                download_manager_iface.Dispose ();                
+                download_manager_iface = null;
             }                
            
             Log.Debug ("Disposing feedsManager");
-            if (feedsManager != null) {   
-                feedsManager.Dispose ();
+            if (feeds_manager != null) {   
+                feeds_manager.Dispose ();
 
-                feedsManager.FeedAdded -= OnFeedAddedHandler;       
-                feedsManager.FeedDeleted -= OnFeedRemovedHandler;
-                feedsManager.FeedRenamed -= OnFeedRenamedHandler;
-                feedsManager.FeedUrlChanged -= OnFeedRenamedHandler;
+                feeds_manager.FeedAdded -= OnFeedAddedHandler;       
+                feeds_manager.FeedDeleted -= OnFeedRemovedHandler;
+                feeds_manager.FeedRenamed -= OnFeedRenamedHandler;
+                feeds_manager.FeedUrlChanged -= OnFeedRenamedHandler;
                                 
-                feedsManager.FeedItemAdded -= OnFeedItemAddedHandler;
-                feedsManager.FeedItemRemoved -= OnFeedItemRemovedHandler;
-                feedsManager.FeedItemCountChanged -= OnFeedItemCountChanged;                
-                
-                feedsManager.FeedDownloading -= OnFeedUpdatingHandler;
-                feedsManager.FeedDownloadCompleted -= OnFeedDownloadCompletedHandler;
-                feedsManager.FeedDownloadCountChanged -= OnFeedDownloadCountChangedHandler;
+                feeds_manager.FeedItemAdded -= OnFeedItemAddedHandler;
+                feeds_manager.FeedItemRemoved -= OnFeedItemRemovedHandler;
+                feeds_manager.FeedItemCountChanged -= OnFeedItemCountChanged;                
+                
+                feeds_manager.FeedDownloading -= OnFeedUpdatingHandler;
+                feeds_manager.FeedDownloadCompleted -= OnFeedDownloadCompletedHandler;
+                feeds_manager.FeedDownloadCountChanged -= OnFeedDownloadCountChangedHandler;
 
-                feedsManager = null;
+                feeds_manager = null;
             }
             
             Log.Debug ("Disposing dm");
-            if (dm != null) {            
-                dm.Dispose ();
+            if (download_manager != null) {            
+                download_manager.Dispose ();
             
-                dm.Group.TaskAssociated -= OnTaskAssociated;                        
-                dm.Group.TaskStatusChanged -= OnTaskStatusChanged;
+                download_manager.Group.TaskAssociated -= OnTaskAssociated;                        
+                download_manager.Group.TaskStatusChanged -= OnTaskStatusChanged;
                 
-                dm.Group.TaskStopped -= OnTaskStoppedHandler;                
-                dm.Group.TaskStarted -= TaskStartedHandler;                   
-                dm = null;
+                download_manager.Group.TaskStopped -= OnTaskStoppedHandler;                
+                download_manager.Group.TaskStarted -= TaskStartedHandler;                   
+                download_manager = null;
             }
             
             DisposeInterface ();            
@@ -237,176 +163,111 @@
                 disposing = false;            
                 disposed = true;
             }
-        }    
-
-        private void UpdateCount ()
-        {
-            lock (sync) {
-                if (!disposed || disposing) {
-                    long itemCount = feedsManager.TotalItemCount;
-                    long downloadedItems = itemCount - feedsManager.TotalUnreadItemCount;                  
-
-                    int count = Math.Min (
-                        (int)itemCount,
-                        ((downloadedItems > 0) ? (int)downloadedItems : 0)
-                    );
-                    
-                    podcastSource.CountSet = count;                    
-                }
-            }
         }
 
-        private void OnFeedAddedHandler (object sender, FeedEventArgs e)
+        private void OnFeedAddedHandler (object sender, FeedEventArgs args)
         {
             lock (sync) {
-                if (feedDict.ContainsKey (e.Feed.LocalID)) {
-                    PodcastFeed feed = feedDict[e.Feed.LocalID];
-                    feedModel.Add (feed);
-                    e.Feed.AsyncDownload ();                        
-                }
+                source.FeedModel.Add (args.Feed);
             }
         }
         
-        private void OnFeedRemovedHandler (object sender, FeedEventArgs e)
+        private void OnFeedRemovedHandler (object sender, FeedEventArgs args)
         {
             lock (sync) {
-                if (feedDict.ContainsKey (e.Feed.LocalID)) {
-                    PodcastFeed feed = feedDict[e.Feed.LocalID];
-                    feedDict.Remove (feed.FeedID);
-                    feedModel.Remove (feed);
-                    feed.Delete ();
-                }
+                source.FeedModel.Remove (args.Feed);
+                args.Feed.Delete ();
             }
         }        
 
-        private void OnFeedRenamedHandler (object sender, FeedEventArgs e)
+        private void OnFeedRenamedHandler (object sender, FeedEventArgs args)
         {
             lock (sync) {
-                feedModel.Sort ();
+                source.FeedModel.Sort ();
             }
         }
 
-        private void OnFeedUpdatingHandler (object sender, FeedEventArgs e)
+        private void OnFeedUpdatingHandler (object sender, FeedEventArgs args)
         {   
             lock (sync) {
-                feedModel.Reload ();
+                source.FeedModel.Reload ();
             }
         }
 
-        private void OnFeedDownloadCountChangedHandler (object sender, 
-                                                        FeedDownloadCountChangedEventArgs e)
+        private void OnFeedDownloadCountChangedHandler (object sender, FeedDownloadCountChangedEventArgs args)
         {
             lock (sync) {
-                feedModel.Reload ();                
+                source.FeedModel.Reload ();                
             }
         }
 
-        private void OnFeedItemAddedHandler (object sender, FeedItemEventArgs e) 
+        private void OnFeedItemAddedHandler (object sender, FeedItemEventArgs args) 
         {
-             lock (sync) {
-                if (e.Item != null) {
-                    if (e.Item.Enclosure != null) {
-                        PodcastItem pi = new PodcastItem (e.Item);
-                        pi.Feed = feedDict[e.Item.Parent.LocalID];                        
-                        itemDict.Add (e.Item.LocalID, pi);
-                        pi.Save ();
-                        
-                        itemModel.Add (pi);                            
-                    } else {
-                        e.Item.Delete ();                        
-                    }
-                } else if (e.Items != null) {
-                    IEnumerable<IFeedItem> items = e.Items;
-                    
-                    PodcastItem pi = null;                            
-                    List<PodcastItem> pis = new List<PodcastItem> ();
-
-                    ServiceManager.DbConnection.BeginTransaction ();
-
-                    try {      
-                        foreach (IFeedItem fi in items) {
-                            if (fi.Enclosure == null) {
-                    	    	fi.Delete ();
-                    	    } else {
-                                pi = new PodcastItem (fi);
-                                pi.Feed = feedDict[fi.Parent.LocalID];                                    
-                                itemDict.Add (fi.LocalID, pi);
-                                pis.Add (pi);
-                                pi.Save ();
-                            }
-                        }
-                        
-                        itemModel.Add (pis);
-                        ServiceManager.DbConnection.CommitTransaction ();
-                    } catch (Exception ex) {
-                        Console.WriteLine (ex.Message);
-                        ServiceManager.DbConnection.RollbackTransaction ();
-                        return;
+            lock (sync) {
+                if (args.Item != null) {
+                    AddFeedItem (args.Item);
+                } else if (args.Items != null) {
+                    foreach (FeedItem item in args.Items) {
+                        AddFeedItem (item);
                     }
                 }
             }
         }
+        
+        private void AddFeedItem (FeedItem item)
+        {
+            if (item.Enclosure != null) {
+                PodcastItem pi = new PodcastItem (item);
+                pi.PrimarySource = source;
+                pi.Save ();                       
+            } else {
+                item.Delete ();                        
+            }
+        }
 
         private void OnFeedItemRemovedHandler (object sender, FeedItemEventArgs e) 
         {
             lock (sync) {
-                PodcastItem pi = null;
-                
                 if (e.Item != null) {
-                    if (itemDict.ContainsKey (e.Item.LocalID)) {
-                        pi = itemDict[e.Item.LocalID];
-                        itemModel.Remove (pi);
-                        itemDict.Remove (pi.FeedItemID);
-                        pi.Delete ();
-                    }
+                    PodcastItem.DeleteWithFeedId (e.Item.DbId);
                 } else if (e.Items != null) {
-                    List<PodcastItem> pis = new List<PodcastItem> ();
-            
-                    foreach (IFeedItem fi in e.Items) {
-                        if (itemDict.ContainsKey (fi.LocalID)) {
-                            pi = itemDict[fi.LocalID];
-                            
-                            pis.Add (pi);
-                            itemDict.Remove (fi.LocalID);                            
-                        }
+                    foreach (FeedItem fi in e.Items) {
+                        PodcastItem.DeleteWithFeedId (fi.DbId);
                     }
-                    
-                    itemModel.Remove (pis);
-                    PodcastItem.Delete (pis);
                 }
                 
-                feedModel.Reload ();
+                source.Reload ();
             }
         } 
 
         private void OnFeedItemCountChanged (object sender, 
                                              FeedItemCountChangedEventArgs e)
         {
-            UpdateCount ();
+            //UpdateCount ();
         }
 
         private void OnFeedDownloadCompletedHandler (object sender, 
                                                      FeedDownloadCompletedEventArgs e) 
         {
-            lock (sync) {
-                PodcastFeed f = feedDict[e.Feed.LocalID]; 
+            /*lock (sync) {
+                Feed f = feedDict[e.Feed.DbId]; 
                 
                 if (e.Error == FeedDownloadError.None) {
                     if (String.IsNullOrEmpty(e.Feed.LocalEnclosurePath)) {
                         e.Feed.LocalEnclosurePath = Path.Combine (
-                            tmpEnclosurePath, SanitizeName (e.Feed.Name)
+                            tmp_enclosure_path, SanitizeName (e.Feed.Name)
                         );
                     }                    
                 
-                    if (f.SyncPreference != SyncPreference.None) {
-                        ReadOnlyCollection<IFeedItem> items = e.Feed.Items;
+                    if (f.AutoDownload != FeedAutoDownload.None) {
+                        ReadOnlyCollection<FeedItem> items = e.Feed.Items;
                         
                         if (items != null) {
-                            if (f.SyncPreference == SyncPreference.One && 
+                            if (f.AutoDownload == FeedAutoDownload.One && 
                                 items.Count > 0) {
                                 items[0].Enclosure.AsyncDownload ();
                             } else {
-                                foreach (IFeedItem fi in items) {
+                                foreach (FeedItem fi in items) {
                                     fi.Enclosure.AsyncDownload ();
                                 }
                             }
@@ -414,15 +275,14 @@
                     }
                 }
                 
-                feedModel.Reload ();                
-            }            
+                source.Reload ();                
+            }*/    
         }
         
         private void OnTaskAssociated (object sender, EventArgs e)
         {
             lock (sync) {
-                feedModel.Reload ();
-                itemModel.Reload ();
+                source.Reload ();
             }
         }        
         
@@ -430,8 +290,7 @@
         								  TaskStatusChangedEventArgs e)
         {
             lock (sync) {
-                feedModel.Reload ();
-                itemModel.Reload ();
+                source.Reload ();
             }
         }        
         
@@ -439,25 +298,27 @@
                                          TaskEventArgs<HttpFileDownloadTask> e)
         {
             lock (sync) {
-                feedModel.Reload ();
-                itemModel.Reload ();
+                source.Reload ();
             }
         }        
         
         private void OnTaskStoppedHandler (object sender, 
                                            TaskEventArgs<HttpFileDownloadTask> e)
         {
-            lock (sync) {
+            // TODO merge
+            /*lock (sync) {
                 if (e.Task != null && e.Task.Status == TaskStatus.Succeeded) {
                     FeedEnclosure enc = e.Task.UserState as FeedEnclosure;
                 
                     if (enc != null) {
-                        IFeedItem item = enc.Parent;
+                        FeedItem item = enc.Item;
                         DatabaseTrackInfo track = null;
                         
-                        if (itemDict.ContainsKey (item.LocalID)) {
-                            PodcastItem pi = itemDict[item.LocalID];
-                            track = importManager.ImportPodcast (enc.LocalPath);                            
+                        
+                        
+                        if (itemDict.ContainsKey (item.DbId)) {
+                            PodcastItem pi = itemDict[item.DbId];
+                            track = import_manager.ImportPodcast (enc.LocalPath);                            
 
                             if (track != null) {
                                 pi.Track = track;
@@ -470,51 +331,34 @@
                     }                    
                 }
                 
-                feedModel.Reload ();
-                itemModel.Reload ();
-            }
+                source.Reload ();
+            }*/
         }        
 
         private void OnPlayerEngineStateChangedHandler (object sender, EventArgs e)
         {
             lock (sync) {
-                itemModel.Reload ();
+                //source.Reload ();
             }
         }          
 
-        private void SubscribeToPodcast (Uri uri, SyncPreference syncPreference)
+        private void SubscribeToPodcast (Uri uri, FeedAutoDownload syncPreference)
         {                     
             lock (sync) {
-                IFeed feed = feedsManager.CreateFeed (uri.ToString ());
+                Feed feed = feeds_manager.CreateFeed (uri.ToString ());
                 
                 if (feed != null) {
-                    PodcastFeed pf = new PodcastFeed (feed);
-                    pf.SyncPreference = syncPreference;
-                    pf.Save ();
-                    
-                    feedDict.Add (pf.FeedID, pf);
+                    feed.AutoDownload = syncPreference;
+                    feed.Save ();
                 }
             }        
         }
 
-        private List<IFeedItem> GetEnclosureItems (IEnumerable<IFeedItem> items)
-        {            
-            List<IFeedItem> encs = new List<IFeedItem> ();                
-                
-            foreach (IFeedItem i in items) {
-                if (i.Enclosure != null) {                    
-                    encs.Add (i);
-                }
-            }    
-            
-            return encs;
-        }
-
         // Via Monopod
-        private string SanitizeName (string s)
+        /*private static string SanitizeName (string s)
         {
             // remove /, : and \ from names
             return s.Replace ('/', '_').Replace ('\\', '_').Replace (':', '_').Replace (' ', '_');
-        }        
+        }*/   
     }
 }

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastCore_Interface.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastCore_Interface.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastCore_Interface.cs	Mon Apr 28 21:42:18 2008
@@ -35,21 +35,19 @@
 using Mono.Unix;
 
 using Hyena.Data;
+using Hyena.Data.Gui;
+
+using Migo.Syndication;
 
 using Banshee.Web;
 using Banshee.Base;
 using Banshee.Sources;
 using Banshee.Streaming;
 using Banshee.ServiceStack;
-
 using Banshee.Gui;
 using Banshee.Widgets;
-
-using Hyena.Data.Gui;
-
 using Banshee.Collection;
 using Banshee.Collection.Database;
-
 using Banshee.Podcasting.Gui;
 using Banshee.Podcasting.Data;
 
@@ -61,23 +59,23 @@
         {
             BuildActions ();
 
-            podcastSource = new PodcastSource (tmpEnclosurePath, feedModel, itemModel);
+            source = new PodcastSource (tmp_enclosure_path);
             
-            podcastSource.FeedView.SelectionProxy.Changed += OnFeedSelectionChangedHandler;
-            podcastSource.ItemView.RowActivated += OnPodcastItemRowActivatedHandler;            
+            //source.FeedView.SelectionProxy.Changed += OnFeedSelectionChangedHandler;
+            //source.ItemView.RowActivated += OnPodcastItemRowActivatedHandler;            
             
-            ServiceManager.SourceManager.AddSource (podcastSource);
+            ServiceManager.SourceManager.AddSource (source);
         }         
         
         private void DisposeInterface ()
         {
-            if (podcastSource != null) {
-                podcastSource.FeedView.SelectionProxy.Changed -= OnFeedSelectionChangedHandler;
-                podcastSource.ItemView.RowActivated -= OnPodcastItemRowActivatedHandler;              
+            if (source != null) {
+                //source.FeedView.SelectionProxy.Changed -= OnFeedSelectionChangedHandler;
+                //source.ItemView.RowActivated -= OnPodcastItemRowActivatedHandler;              
                 
-                ServiceManager.SourceManager.RemoveSource (podcastSource);
-                podcastSource = null;
-            }              
+                ServiceManager.SourceManager.RemoveSource (source);
+                source = null;
+            }
         }     
         
         private void BuildActions ()
@@ -92,13 +90,13 @@
                     "PodcastUpdateAllAction", Stock.Refresh,
                      Catalog.GetString ("Update Podcasts"), null,//"<control><shift>U",
                      Catalog.GetString ("Update All Podcasts"), 
-                     OnPodcastUpdateAllAction
+                     OnPodcastUpdateAll
                 ),
                 new ActionEntry (
                     "PodcastAddAction", Stock.New,
                      Catalog.GetString ("Subscribe to Podcast"),"<control><shift>F", 
                      Catalog.GetString ("Subscribe to a new podcast feed"),
-                     OnPodcastAddAction
+                     OnPodcastAdd
                 )         
             });
             
@@ -107,51 +105,51 @@
                     "PodcastDeleteAction", Stock.Delete,
                      Catalog.GetString ("Delete"),
                      null, String.Empty, 
-                     OnPodcastDeleteAction
+                     OnPodcastDelete
                 ),
                 new ActionEntry (
                     "PodcastUpdateFeedAction", Stock.Refresh,
                      /* Translators: this is a verb used as a button name, not a noun*/
                      Catalog.GetString ("Update"),
                      null, String.Empty, 
-                     OnPodcastUpdateAction
+                     OnPodcastUpdate
                 ),
                 new ActionEntry (
                     "PodcastHomepageAction", Stock.JumpTo,
                      Catalog.GetString ("Homepage"),
                      null, String.Empty, 
-                     OnPodcastHomepageAction
+                     OnPodcastHomepage
                 ),
                 new ActionEntry (
                     "PodcastPropertiesAction", Stock.Properties,
                      Catalog.GetString ("Properties"),
                      null, String.Empty, 
-                     OnPodcastPropertiesAction
+                     OnPodcastProperties
                 ),
                 new ActionEntry (
                     "PodcastItemMarkNewAction", null,
                      Catalog.GetString ("Mark as New"), 
                      "<control><shift>N", String.Empty,
-                     OnPodcastItemMarkNewAction
+                     OnPodcastItemMarkNew
                 ),
                 new ActionEntry (
                     "PodcastItemMarkOldAction", null,
                      Catalog.GetString ("Mark as Old"),
                      "<control><shift>O", String.Empty,
-                     OnPodcastItemMarkOldAction
+                     OnPodcastItemMarkOld
                 ),
                 new ActionEntry (
                     "PodcastItemDownloadAction", Stock.GoDown,
                      /* Translators: this is a verb used as a button name, not a noun*/
                      Catalog.GetString ("Download"),
                      "<control><shift>D", String.Empty, 
-                     OnPodcastItemDownloadAction
+                     OnPodcastItemDownload
                 ),
                 new ActionEntry (
                     "PodcastItemCancelAction", Stock.Stop,
                      Catalog.GetString ("Cancel"),
                      "<control><shift>C", String.Empty, 
-                     OnPodcastItemCancelAction
+                     OnPodcastItemCancel
                 ),
                 new ActionEntry (
                     "PodcastItemDeleteAction", Stock.Remove,
@@ -163,13 +161,13 @@
                     "PodcastItemLinkAction", Stock.JumpTo,
                      Catalog.GetString ("Link"),
                      null, String.Empty, 
-                     OnPodcastItemLinkAction
+                     OnPodcastItemLink
                 ),
                 new ActionEntry (
                     "PodcastItemPropertiesAction", Stock.Properties,
                      Catalog.GetString ("Properties"),
                      null, String.Empty, 
-                     OnPodcastItemPropertiesAction
+                     OnPodcastItemProperties
                 )
             });            
 
@@ -180,7 +178,7 @@
         private void RunSubscribeDialog ()
         {        
             Uri feedUri = null;
-            SyncPreference syncPreference;
+            FeedAutoDownload syncPreference;
             
             PodcastSubscribeDialog subscribeDialog = new PodcastSubscribeDialog ();
             
@@ -279,18 +277,18 @@
             return ret;			
 		}
 
-        private void OnFeedSelectionChangedHandler (object sender, EventArgs e)
+        /*private void OnFeedSelectionChangedHandler (object sender, EventArgs e)
         {
             lock (sync) {
                 if (!disposed || disposing) {              
-                    if (feedModel.SelectedItems.Count == 0) {
-                        feedModel.Selection.Select (0);
+                    if (source.FeedModel.SelectedItems.Count == 0) {
+                        source.FeedModel.Selection.Select (0);
                     }
                     
-                    if (feedModel.Selection.Contains (0)) {
-                        itemModel.FilterOnFeed (PodcastFeed.All);
+                    if (source.FeedModel.Selection.Contains (0)) {
+                        itemModel.FilterOnFeed (Feed.All);
                     } else {
-                        itemModel.FilterOnFeeds (feedModel.CopySelectedItems ());
+                        itemModel.FilterOnFeeds (source.FeedModel.CopySelectedItems ());
                     }
                     
                     itemModel.Selection.Clear ();
@@ -302,18 +300,16 @@
                                                        RowActivatedArgs<PodcastItem> e)
         {
             lock (sync) {
-                if (!disposed || disposing) {         
-                    TrackInfo track = e.RowValue.Track;
-                    
-                    if (track != null) {
+                if (!disposed || disposing) {
+                    if (e.RowValue.Enclosure != null) {
                         e.RowValue.New = false;
-                        ServiceManager.PlayerEngine.OpenPlay (track);
+                        ServiceManager.PlayerEngine.OpenPlay (e.RowValue);
                     }
                 }
             }
-        }
+        }*/
 
-        private void OnPodcastAddAction (object sender, EventArgs e)
+        private void OnPodcastAdd (object sender, EventArgs e)
         {
             lock (sync) {
                 if (!disposed || disposing) {         
@@ -322,16 +318,16 @@
             }
         }
         
-        private void OnPodcastUpdateAction (object sender, EventArgs e)
+        private void OnPodcastUpdate (object sender, EventArgs e)
         {
             lock (sync) {
                 if (!disposed || disposing) {          
-                    ReadOnlyCollection<PodcastFeed> feeds = feedModel.CopySelectedItems ();
+                    ReadOnlyCollection<Feed> feeds = source.FeedModel.CopySelectedItems ();
                     
                     if (feeds != null) {
-                        foreach (PodcastFeed f in feeds) {
-                            if (f != PodcastFeed.All) {
-                                f.Feed.AsyncDownload ();                                
+                        foreach (Feed f in feeds) {
+                            if (f != Feed.All) {
+                                f.AsyncDownload ();                                
                             }
                         }            	
                     }
@@ -339,24 +335,24 @@
             }
         }        
         
-        private void OnPodcastUpdateAllAction (object sender, EventArgs e)
+        private void OnPodcastUpdateAll (object sender, EventArgs e)
         {
             lock (sync) {
                 if (!disposed || disposing) {
-                    foreach (PodcastFeed podcast in feedModel.Copy ()) {
-                        podcast.Feed.AsyncDownload ();
+                    foreach (Feed podcast in source.FeedModel.Copy ()) {
+                        podcast.AsyncDownload ();
                     }
                 }
             }
         }      
         
-        private void OnPodcastDeleteAction (object sender, EventArgs e)
+        private void OnPodcastDelete (object sender, EventArgs e)
         {
             lock (sync) {
                 if (!disposed || disposing) {
                     bool deleteFeed;
                     bool deleteFiles;                    
-                    ReadOnlyCollection<PodcastFeed> feeds = feedModel.CopySelectedItems ();
+                    ReadOnlyCollection<Feed> feeds = source.FeedModel.CopySelectedItems ();
                     
                     if (feeds != null) {                    
                         RunConfirmDeleteDialog (
@@ -365,11 +361,11 @@
                         
                         
                         if (deleteFeed) {
-                            feedModel.Selection.Clear ();
-                            itemModel.Selection.Clear ();
+                            source.FeedModel.Selection.Clear ();
+                            source.TrackModel.Selection.Clear ();
                             
-                            foreach (PodcastFeed f in feeds) {
-                                f.Feed.Delete (deleteFiles);   
+                            foreach (Feed f in feeds) {
+                                f.Delete (deleteFiles);   
                             }                                 
                         }                   
                     }                    
@@ -379,7 +375,7 @@
 
         private void OnPodcastItemRemoveAction (object sender, EventArgs e)
         {
-            lock (sync) {
+            /*lock (sync) {
                 if (!disposed || disposing) {
                     bool deleteItems;
                     bool deleteFiles;                    
@@ -401,17 +397,17 @@
                         }    
                     }   
                 }
-            }
+            }*/
         }  
 
-        private void OnPodcastHomepageAction (object sender, EventArgs e)
+        private void OnPodcastHomepage (object sender, EventArgs e)
         {
             lock (sync) {
                 if (!disposed || disposing) {
-                    ReadOnlyCollection<PodcastFeed> feeds = feedModel.CopySelectedItems ();
+                    ReadOnlyCollection<Feed> feeds = source.FeedModel.CopySelectedItems ();
                     
                     if (feeds != null && feeds.Count == 1) {
-           	            string link = feeds[0].Feed.Link;
+           	            string link = feeds[0].Link;
            	            
            	            if (!String.IsNullOrEmpty (link)) {
                             Banshee.Web.Browser.Open (link);           	                
@@ -421,11 +417,11 @@
             }       
         }   
 
-        private void OnPodcastPropertiesAction (object sender, EventArgs e)
+        private void OnPodcastProperties (object sender, EventArgs e)
         {
             lock (sync) {
                 if (!disposed || disposing) {
-                    ReadOnlyCollection<PodcastFeed> feeds = feedModel.CopySelectedItems ();
+                    ReadOnlyCollection<Feed> feeds = source.FeedModel.CopySelectedItems ();
                     
                     if (feeds != null && feeds.Count == 1) {
                         new PodcastFeedPropertiesDialog (feeds[0]).Run ();
@@ -434,25 +430,25 @@
             }  
         }  
 
-        private void OnPodcastItemPropertiesAction (object sender, EventArgs e)
+        private void OnPodcastItemProperties (object sender, EventArgs e)
         {
             lock (sync) {
                 if (!disposed || disposing) {
-                    ReadOnlyCollection<PodcastItem> items = itemModel.CopySelectedItems ();
+                    /*ReadOnlyCollection<PodcastItem> items = itemModel.CopySelectedItems ();
                     
                     if (items != null && items.Count == 1) {
                         new PodcastPropertiesDialog (items[0]).Run ();
-                    }                 
+                    } */                
                 }
             }  
         } 
 
-        private void OnPodcastItemMarkNewAction (object sender, EventArgs e)
+        private void OnPodcastItemMarkNew (object sender, EventArgs e)
         {
             MarkPodcastItemSelection (true);
         }
         
-        private void OnPodcastItemMarkOldAction (object sender, EventArgs e)
+        private void OnPodcastItemMarkOld (object sender, EventArgs e)
         {
             MarkPodcastItemSelection (false); 
         }     
@@ -461,7 +457,7 @@
         {
             lock (sync) {
                 if (!disposed || disposing) {                    
-                    ReadOnlyCollection<PodcastItem> items = itemModel.CopySelectedItems ();
+                    /*ReadOnlyCollection<PodcastItem> items = itemModel.CopySelectedItems ();
 
                     if (items != null) {
                         ServiceManager.DbConnection.BeginTransaction ();
@@ -480,14 +476,14 @@
                         }                        
                         
                         itemModel.Reload ();                        
-                    }                
+                    }*/
                 }
             }
         }
         
-        private void OnPodcastItemCancelAction (object sender, EventArgs e)
+        private void OnPodcastItemCancel (object sender, EventArgs e)
         {
-            lock (sync) {
+            lock (sync) {/*
                 if (!disposed || disposing) {                    
                     ReadOnlyCollection<PodcastItem> items = itemModel.CopySelectedItems ();
 
@@ -496,13 +492,13 @@
                             pi.Enclosure.CancelAsyncDownload ();
                         }
                     }                
-                }
+                }*/
             }
         }        
         
-        private void OnPodcastItemDownloadAction (object sender, EventArgs e)
+        private void OnPodcastItemDownload (object sender, EventArgs e)
         {
-            lock (sync) {
+            lock (sync) {/*
                 if (!disposed || disposing) {
                     ReadOnlyCollection<PodcastItem> items = itemModel.CopySelectedItems ();
 
@@ -511,13 +507,13 @@
                             pi.Enclosure.AsyncDownload ();
                         }            	
                     }                 
-                }
+                }*/
             }       
         }
         
-        private void OnPodcastItemLinkAction (object sender, EventArgs e)
+        private void OnPodcastItemLink (object sender, EventArgs e)
         {
-            lock (sync) {
+            lock (sync) {/*
                 if (!disposed || disposing) {
                     ReadOnlyCollection<PodcastItem> items = itemModel.CopySelectedItems ();
 
@@ -528,8 +524,8 @@
                             Banshee.Web.Browser.Open (link);           	                
            	            }
                     }                 
-                }
-            }       
+                }*/
+            }
         }   
     }
 }

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Makefile.am
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Makefile.am	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Makefile.am	Mon Apr 28 21:42:18 2008
@@ -4,7 +4,6 @@
 INSTALL_DIR = $(EXTENSIONS_INSTALL_DIR)
 
 SOURCES =  \
-	Banshee.Podcasting.Data/PodcastFeed.cs \
 	Banshee.Podcasting.Data/PodcastItem.cs \
 	Banshee.Podcasting.Gui/DownloadManager/DownloadManagerInterface.cs \
 	Banshee.Podcasting.Gui/DownloadManager/DownloadUserJob.cs \

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs	Mon Apr 28 21:42:18 2008
@@ -67,7 +67,7 @@
                 column_type = SqliteUtils.GetType (type);
             } catch (Exception e) {
                 throw new Exception(string.Format(
-                    "{0}.{1}: {3}", member_info.DeclaringType, member_info.Name, e.Message));
+                    "{0}.{1}: {2}", member_info.DeclaringType, member_info.Name, e.Message));
             }
             this.name = attribute.ColumnName ?? member_info.Name;
             this.type = type;
@@ -199,4 +199,4 @@
             DefaultValue = default_value;
         }
     }
-}
\ No newline at end of file
+}

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteCommand.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteCommand.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteCommand.cs	Mon Apr 28 21:42:18 2008
@@ -170,6 +170,8 @@
                 return String.Format ("'{0}'", (o as string).Replace ("'", "''"));
             } else if (o is DateTime) {
                 return DateTimeUtil.FromDateTime ((DateTime) o);
+            } else if (o is bool) {
+                return ((bool)o) ? "1" : "0";
             } else if (o == null) {
                 return "NULL";
             } else if (o is Array) {

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs	Mon Apr 28 21:42:18 2008
@@ -32,7 +32,9 @@
 
 namespace Hyena.Data.Sqlite
 {
-    public class SqliteModelCache<T> : DictionaryModelCache<T> where T : ICacheableItem
+    //public delegate void AggregatesUpdatedEventHandler (IDataReader reader);
+
+    public class SqliteModelCache<T> : DictionaryModelCache<T> where T : ICacheableItem, new ()
     {
         private HyenaSqliteConnection connection;
         private ICacheableDatabaseModel model;
@@ -53,8 +55,7 @@
         // private bool warm;
         private long first_order_id;
 
-        public delegate void AggregatesUpdatedEventHandler (IDataReader reader);
-        public event AggregatesUpdatedEventHandler AggregatesUpdated;
+        public event Action<IDataReader> AggregatesUpdated;
 
         public SqliteModelCache (HyenaSqliteConnection connection,
                            string uuid,
@@ -254,7 +255,7 @@
 
             using (IDataReader reader = connection.Query (get_single_command, args)) {
                 if (reader.Read ()) {
-                    T item = provider.Load (reader, 0);
+                    T item = provider.Load (reader);
                     item.CacheEntryId = Convert.ToInt64 (reader[reader.FieldCount - 1]);
                     item.CacheModelId = uid;
                     return item;
@@ -350,7 +351,7 @@
                     T item;
                     while (reader.Read ()) {
                         if (!ContainsKey (offset)) {
-                            item = provider.Load (reader, (int) offset);
+                            item = provider.Load (reader);
                             item.CacheEntryId = Convert.ToInt64 (reader[reader.FieldCount - 1]);
                             item.CacheModelId = uid;
                             Add (offset, item);
@@ -367,7 +368,7 @@
                 if (reader.Read ()) {
                     rows = Convert.ToInt64 (reader[0]);
 
-                    AggregatesUpdatedEventHandler handler = AggregatesUpdated;
+                    Action<IDataReader> handler = AggregatesUpdated;
                     if (handler != null) {
                         handler (reader);
                     }

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs	Mon Apr 28 21:42:18 2008
@@ -34,7 +34,7 @@
 
 namespace Hyena.Data.Sqlite
 {
-    public abstract class SqliteModelProvider<T>
+    public class SqliteModelProvider<T> where T : new ()
     {
         private readonly List<DatabaseColumn> columns = new List<DatabaseColumn> ();
         private readonly List<DatabaseColumn> select_columns = new List<DatabaseColumn> ();
@@ -46,10 +46,12 @@
         private HyenaSqliteCommand create_command;
         private HyenaSqliteCommand insert_command;
         private HyenaSqliteCommand update_command;
+        private HyenaSqliteCommand delete_command;
         private HyenaSqliteCommand select_command;
         private HyenaSqliteCommand select_range_command;
         private HyenaSqliteCommand select_single_command;
         
+        private string table_name;
         private string primary_key;
         private string select;
         private string from;
@@ -57,12 +59,24 @@
         
         private const string HYENA_DATABASE_NAME = "hyena_database_master";
 
-        public abstract string TableName { get; }
-        protected abstract int ModelVersion { get; }
-        protected abstract int DatabaseVersion { get; }
-        protected abstract void MigrateTable (int old_version);
-        protected abstract void MigrateDatabase (int old_version);
-        protected abstract T MakeNewObject (int offset);
+        public virtual string TableName { get { return table_name; } }
+
+        protected virtual int ModelVersion { get { return 1; } }
+
+        protected virtual int DatabaseVersion { get { return 1; } }
+
+        protected virtual void MigrateTable (int old_version)
+        {
+        }
+
+        protected virtual void MigrateDatabase (int old_version)
+        {
+        }
+
+        protected virtual T MakeNewObject ()
+        {
+            return new T ();
+        }
         
         protected virtual string HyenaTableName {
             get { return "HyenaModelVersions"; }
@@ -72,6 +86,12 @@
         {
             this.connection = connection;
         }
+        
+        public SqliteModelProvider (HyenaSqliteConnection connection, string table_name) : this (connection)
+        {
+            this.table_name = table_name;
+            Init ();
+        }
 
         protected void Init ()
         {
@@ -95,7 +115,6 @@
                     AddColumn (property, attribute);
                 }
             }
-            
             if (key == null) {
                 throw new Exception (String.Format ("The {0} table does not have a primary key", TableName));
             }
@@ -291,9 +310,9 @@
             connection.Execute (UpdateCommand);
         }
         
-        public T Load (IDataReader reader, int index)
+        public T Load (IDataReader reader)
         {
-            T item = MakeNewObject (index);
+            T item = MakeNewObject ();
             Load (reader, item);
             return item;
         }
@@ -328,10 +347,32 @@
         public IEnumerable<T> FetchAll ()
         {
             PrepareSelectCommand ();
-            int i = 1;
             using (IDataReader reader = connection.Query (SelectCommand)) {
                 while (reader.Read ()) {
-                    yield return Load (reader, i++);
+                    yield return Load (reader);
+                }
+            }
+        }
+
+        public T FetchFirstMatching (string condition)
+        {
+            PrepareSelectCommand ();
+            HyenaSqliteCommand fetch_matching_command = new HyenaSqliteCommand (String.Format ("{0} AND {1}", SelectCommand.Text, condition));
+            using (IDataReader reader = connection.Query (fetch_matching_command)) {
+                if (reader.Read ()) {
+                    return Load (reader);
+                }
+            }
+            return default(T);
+        }
+        
+        public IEnumerable<T> FetchAllMatching (string condition)
+        {
+            PrepareSelectCommand ();
+            HyenaSqliteCommand fetch_matching_command = new HyenaSqliteCommand (String.Format ("{0} AND {1}", SelectCommand.Text, condition));
+            using (IDataReader reader = connection.Query (fetch_matching_command)) {
+                while (reader.Read ()) {
+                    yield return Load (reader);
                 }
             }
         }
@@ -346,7 +387,7 @@
             PrepareSelectRangeCommand (offset, limit);
             using (IDataReader reader = connection.Query (SelectRangeCommand)) {
                 while (reader.Read ()) {
-                    yield return Load (reader, offset++);
+                    yield return Load (reader);
                 }
             }
         }
@@ -358,14 +399,48 @@
         
         public T FetchSingle (int id)
         {
+            return FetchSingle ((long) id);
+        }
+        
+        public T FetchSingle (long id)
+        {
             PrepareSelectSingleCommand (id);
             using (IDataReader reader = connection.Query (SelectSingleCommand)) {
                 if (reader.Read ()) {
-                    return Load (reader, id);
+                    return Load (reader);
                 }
             }
             return default(T);
         }
+        
+        protected long PrimaryKeyFor (T item)
+        {
+            return (long) key.GetValue (item);
+        }
+        
+        public void Delete (long id)
+        {
+            connection.Execute (delete_command.ApplyValues (id));
+        }
+        
+        public void Delete (T item)
+        {
+            Delete (PrimaryKeyFor (item));
+        }
+        
+        public void Delete (IEnumerable<T> items)
+        {
+            List<long> ids = new List<long> ();
+            long id;
+            foreach (T item in items) {
+                id = PrimaryKeyFor (item);
+                if (id > 0)
+                    ids.Add (id);
+            }
+            
+            if (ids.Count > 0)
+                connection.Execute (delete_command.ApplyValues (ids.ToArray ()));
+        }
 
         public bool Refresh (T item)
         {
@@ -379,7 +454,7 @@
             PrepareSelectSingleCommand (id);
             using (IDataReader reader = connection.Query (SelectSingleCommand)) {
                 if (reader.Read ()) {
-                    Load (reader, item);
+                    Load (reader);
                     return true;
                 }
             }
@@ -480,10 +555,8 @@
                 if (select_command == null) {
                     select_command = new HyenaSqliteCommand (
                         String.Format (
-                            "SELECT {0} FROM {1}{2}{3}",
-                            Select, From,
-                            (String.IsNullOrEmpty (Where) ? String.Empty : " WHERE "),
-                            Where
+                            "SELECT {0} FROM {1} WHERE {2}",
+                            Select, From, String.IsNullOrEmpty (Where) ? "1=1" : Where
                         )
                     );
                 }
@@ -523,6 +596,17 @@
             }
         }
         
+        protected virtual HyenaSqliteCommand DeleteCommand {
+            get {
+                if (delete_command == null) {
+                    delete_command = new HyenaSqliteCommand (String.Format (
+                        "DELETE FROM {0} WHERE {1} IN (?)", TableName, PrimaryKey
+                    ));
+                }
+                return delete_command;
+            }
+        }
+        
         public virtual string Select {
             get {
                 if (select == null) {
@@ -672,4 +756,4 @@
             );
         }
 	}
-}
\ No newline at end of file
+}

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteUtils.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteUtils.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteUtils.cs	Mon Apr 28 21:42:18 2008
@@ -38,7 +38,7 @@
         {
             if (type == typeof (string)) {
                 return "TEXT";
-            } else if (type == typeof (int) || type == typeof (long)
+            } else if (type == typeof (int) || type == typeof (long) || type == typeof (bool)
                 || type == typeof (DateTime) || type == typeof (TimeSpan) || type.IsEnum) {
                 return "INTEGER";
             } else {
@@ -59,6 +59,8 @@
                     : ((TimeSpan)value).TotalMilliseconds;
             } else if (type.IsEnum) {
                 return Convert.ChangeType (value, Enum.GetUnderlyingType (type));
+            } else if (type == typeof (bool)) {
+                return ((bool)value) ? 1 : 0;
             }
             
             return value;
@@ -82,6 +84,8 @@
                 }
             } else if (type.IsEnum) {
                 return Enum.ToObject (type, value);
+            } else if (type == typeof (bool)) {
+                return ((int)value == 1);
             } else {
                 return Convert.ChangeType (value, type);
             }

Modified: trunk/banshee/src/Libraries/Migo/Makefile.am
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Makefile.am	(original)
+++ trunk/banshee/src/Libraries/Migo/Makefile.am	Mon Apr 28 21:42:18 2008
@@ -33,30 +33,9 @@
 	Migo/Migo.Syndication/FeedItem.cs \
 	Migo/Migo.Syndication/FeedsManager.cs \
 	Migo/Migo.Syndication/FeedUpdateTask.cs \
-	Migo/Migo.Syndication/IFeed.cs \
-	Migo/Migo.Syndication/IFeedEnclosure.cs \
-	Migo/Migo.Syndication/IFeedItem.cs \
-	Migo/Migo.Syndication/IFeedsManager.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/EnclosuresTableManager.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/FeedsTableManager.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/ItemsTableManager.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/DatabaseManager.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/DataUtility.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/DbDefines.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/QueuedDbCommand.cs \
+	Migo/Migo.Syndication/Migo.Syndication.Data/RssParser.cs \
 	Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/Rfc822DateTime.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/SQLiteUtility.cs \
 	Migo/Migo.Syndication/Migo.Syndication.Data/Utilities/XmlUtils.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/DataWrapper.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/FeedDataWrapper.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/FeedEnclosureDataWrapper.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Db/FeedItemDataWrapper.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/IFeedEnclosureWrapper.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/IFeedItemWrapper.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/IFeedWrapper.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Rss/RssFeedEnclosureWrapper.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Rss/RssFeedItemWrapper.cs \
-	Migo/Migo.Syndication/Migo.Syndication.Data/Wrappers/Rss/RssFeedWrapper.cs \
 	Migo/Migo.TaskCore/AsyncCommandQueue/AsyncCommandQueue.cs \
 	Migo/Migo.TaskCore/AsyncCommandQueue/CommandDelegate.cs \
 	Migo/Migo.TaskCore/AsyncCommandQueue/CommandWrapper.cs \

Modified: trunk/banshee/src/Libraries/Migo/Migo.mdp
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo.mdp	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo.mdp	Mon Apr 28 21:42:18 2008
@@ -90,6 +90,7 @@
     <File name="Migo/Migo.TaskCore/GroupStatusManager.cs" subtype="Code" buildaction="Compile" />
     <File name="Migo/Migo.TaskCore/Task.cs" subtype="Code" buildaction="Compile" />
     <File name="Migo/Migo.TaskCore/TaskGroup.cs" subtype="Code" buildaction="Compile" />
+    <File name="Migo/Migo.Syndication/Migo.Syndication.Data/RssParser.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedDownloadCompletedEventArgs.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedDownloadCompletedEventArgs.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedDownloadCompletedEventArgs.cs	Mon Apr 28 21:42:18 2008
@@ -39,7 +39,7 @@
             get { return error; }   
         }
         
-        public FeedDownloadCompletedEventArgs (IFeed feed, 
+        public FeedDownloadCompletedEventArgs (Feed feed, 
                                                FeedDownloadError error) : base (feed) 
         {
             if (error < FeedDownloadError.None ||

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedDownloadCountChangedEventArgs.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedDownloadCountChangedEventArgs.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedDownloadCountChangedEventArgs.cs	Mon Apr 28 21:42:18 2008
@@ -37,7 +37,7 @@
             get { return flags; }   
         }
         
-        public FeedDownloadCountChangedEventArgs (IFeed feed, 
+        public FeedDownloadCountChangedEventArgs (Feed feed, 
                                                   FEEDS_EVENTS_DOWNLOAD_COUNT_FLAGS flags) : base (feed) 
         {
             this.flags = flags;

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedEventArgs.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedEventArgs.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedEventArgs.cs	Mon Apr 28 21:42:18 2008
@@ -32,14 +32,12 @@
 {    
     public class FeedEventArgs : EventArgs
     {
-        private readonly IFeed feed;
-        
-        public IFeed Feed
-        {
+        private readonly Feed feed;
+        public Feed Feed {
             get { return feed; }   
         }
         
-        public FeedEventArgs (IFeed feed) 
+        public FeedEventArgs (Feed feed) 
         {
             if (feed == null) {
             	throw new ArgumentNullException ("feed");

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedItemCountChangedEventArgs.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedItemCountChangedEventArgs.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedItemCountChangedEventArgs.cs	Mon Apr 28 21:42:18 2008
@@ -39,7 +39,7 @@
             get { return flags; }   
         }
         
-        public FeedItemCountChangedEventArgs (IFeed feed, 
+        public FeedItemCountChangedEventArgs (Feed feed, 
                                               FEEDS_EVENTS_ITEM_COUNT_FLAGS flags) : base (feed) 
         {
             this.flags = flags;

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedItemEventArgs.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedItemEventArgs.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/EventArgs/FeedItemEventArgs.cs	Mon Apr 28 21:42:18 2008
@@ -33,36 +33,34 @@
 {    
     public class FeedItemEventArgs : FeedEventArgs
     {
-        private readonly IFeedItem item;
-        private readonly IEnumerable<IFeedItem> items;
+        private readonly FeedItem item;
+        private readonly IEnumerable<FeedItem> items;
         
-        public IFeedItem Item
-        {
+        public FeedItem Item {
             get { return item; }
         }
         
-        public IEnumerable<IFeedItem> Items
-        {
+        public IEnumerable<FeedItem> Items {
             get { return items; }   
         }
         
-        public FeedItemEventArgs (IFeed feed, IFeedItem item) : this (feed, item, null) 
+        public FeedItemEventArgs (Feed feed, FeedItem item) : this (feed, item, null) 
         {
             if (item == null) {
             	throw new ArgumentNullException ("item");
             }        
         }
         
-        public FeedItemEventArgs (IFeed feed, IEnumerable<IFeedItem> items) : this (feed, null, items) 
+        public FeedItemEventArgs (Feed feed, IEnumerable<FeedItem> items) : this (feed, null, items) 
         {
             if (items == null) {
             	throw new ArgumentNullException ("items");
             }        
         }
         
-        private FeedItemEventArgs (IFeed feed, 
-                                   IFeedItem item, 
-                                   IEnumerable<IFeedItem> items) : base (feed)
+        private FeedItemEventArgs (Feed feed, 
+                                   FeedItem item, 
+                                   IEnumerable<FeedItem> items) : base (feed)
         {
             this.item = item;
             this.items = items;

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Feed.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Feed.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Feed.cs	Mon Apr 28 21:42:18 2008
@@ -35,15 +35,46 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 
+using Hyena;
+using Hyena.Data.Sqlite;
+
 using Migo.Net;
 using Migo.TaskCore;
 using Migo.DownloadCore;
 using Migo.Syndication.Data;
 
 namespace Migo.Syndication
-{    
-    public class Feed : IFeed
+{
+    public enum FeedAutoDownload : int 
+    {
+        All = 0,
+        One = 1,
+        None = 2
+    }
+
+    // TODO remove this, way too redundant with DownloadStatus
+    public enum PodcastFeedActivity : int {
+        Updating = 0,
+        UpdatePending = 1,        
+        UpdateFailed = 2,
+        ItemsDownloading = 4,        
+        ItemsQueued = 5,        
+        None = 6        
+    }
+
+    public class Feed
     {        
+        private static SqliteModelProvider<Feed> provider;
+        public static SqliteModelProvider<Feed> Provider {
+            get { return provider; }
+            set { provider = value; }
+        }
+
+        private static Feed all = new Feed ();
+        public static Feed All {
+            get { return all; }
+        }
+
         private bool canceled;
         private bool deleted; 
         private bool updating;
@@ -56,6 +87,10 @@
         private long queuedDownloadCount;
         private long activeDownloadCount;        
         
+        private List<FeedItem> items;
+        private List<FeedItem> inactive_items;
+        
+        private FeedAutoDownload auto_download;
         private string copyright;
         private string description;
         private bool downloadEnclosuresAutomatically;
@@ -63,11 +98,7 @@
         private string downloadUrl;
         private string image;        
         private long interval;
-        private List<FeedItem> inactiveItems;
         private bool isList;
-        private long itemCount;
-        private List<FeedItem> items;
-        private Dictionary<long,FeedItem> itemsByID;        
         private string language;
         private DateTime lastBuildDate;
         private FeedDownloadError lastDownloadError;
@@ -75,8 +106,8 @@
         private DateTime lastWriteTime;
         private string link;
         private string localEnclosurePath;
-        private long localID;
-        private long maxItemCount;
+        private long localID = -1;
+        private long maxItemCount = 200;
         private string name;
         private FeedsManager parent;        
         private DateTime pubDate;
@@ -95,156 +126,111 @@
         public event EventHandler<FeedEventArgs> FeedUrlChanged;
         
         public event EventHandler<FeedItemEventArgs> FeedItemAdded;
-        public event EventHandler<FeedItemEventArgs> FeedItemRemoved;        
+        public event EventHandler<FeedItemEventArgs> FeedItemRemoved;
         
-        public long ActiveDownloadCount 
-        { 
-            get { lock (sync) { return activeDownloadCount; } }
-        }
+#region Database-bound Properties
         
-        public long QueuedDownloadCount 
-        { 
-            get { lock (sync) { return queuedDownloadCount; } }             
-        }         
-        
-        public string Copyright 
-        { 
+        [DatabaseColumn]
+        public string Copyright { 
             get { lock (sync) { return copyright; } } 
+            set { copyright = value; }
         }
         
-        public string Description 
-        { 
+        [DatabaseColumn]
+        public string Description { 
             get { lock (sync) { return description; } } 
+            set { description = value; }
         }
         
-        public bool DownloadEnclosuresAutomatically 
-        { 
+        [DatabaseColumn]
+        public bool DownloadEnclosuresAutomatically { 
             get { lock (sync) { return downloadEnclosuresAutomatically; } }  
             set { lock (sync) { downloadEnclosuresAutomatically = value; } }
         }
         
-        public FeedDownloadStatus DownloadStatus 
-        { 
-            get { lock (sync) { return downloadStatus; } }
-        }
-        
-        public string DownloadUrl 
-        { 
+        [DatabaseColumn]
+        public string DownloadUrl {
             get { lock (sync) { return downloadUrl; } }
+            set { downloadUrl = value; }
         }     
         
-        public string Image 
-        { 
+        [DatabaseColumn]
+        public string Image {
             get { lock (sync) { return image; } }
+            set { image = value; }
         }
 
-        public long Interval        
-        { 
+        [DatabaseColumn]
+        public long Interval { 
             get { lock (sync) { return interval; } }
             set { 
                 lock (sync) { interval = (value < 15) ? 1440 : value; }
             } 
         }
         
-        public bool IsList 
-        { 
-            get { lock (sync) { return isList; } }
-        }
-        
-        public long ItemCount 
-        { 
-            get { lock (sync) { return itemCount; } }
-
-            internal set { 
-                lock (sync) {
-                    if (value < 0 /*|| value > maxItemCount*/) { // implement later
-                       	throw new ArgumentOutOfRangeException ("ItemCount:  Must be >= 0 and < MaxItemCount.");
-                    }   
-                }
-                
-                itemCount = value;
-            }             
-        }
-        
-        // I want LINQ -_-
-        public ReadOnlyCollection<IFeedItem> Items { 
-            get { 
-                lock (sync) {  
-                    List<IFeedItem> tmpItems = items.ConvertAll ( 
-                        new Converter<FeedItem,IFeedItem> (
-                            delegate (FeedItem fi) { return fi as IFeedItem; }
-                        )
-                    );
-                    
-                    tmpItems.Sort (
-                        delegate (IFeedItem lhs, IFeedItem rhs) {
-                            return DateTime.Compare (rhs.PubDate, lhs.PubDate);
-                        }
-                    );
-                    
-                    return tmpItems.AsReadOnly ();                                     
-                }
-            } 
-        }
-        
-        public string Language 
-        { 
+        [DatabaseColumn]
+        public string Language { 
             get { lock (sync) { return language; } }
+            set { language = value; }
         }
         
-        public DateTime LastBuildDate 
-        { 
+        [DatabaseColumn]
+        public DateTime LastBuildDate { 
             get { lock (sync) { return lastBuildDate; } }
+            set { lastBuildDate = value; }
         }
         
-        public FeedDownloadError LastDownloadError 
-        { 
+        [DatabaseColumn]
+        public FeedDownloadError LastDownloadError { 
             get { lock (sync) { return lastDownloadError; } }
+            set { lastDownloadError = value; }
         }
         
-        public DateTime LastDownloadTime 
-        { 
+        [DatabaseColumn]
+        public DateTime LastDownloadTime { 
             get { lock (sync) { return lastDownloadTime; } }
+            set { lastDownloadTime = value; }
         }
         
-        public DateTime LastWriteTime 
-        { 
+        [DatabaseColumn]
+        public DateTime LastWriteTime { 
             get { lock (sync) { return lastWriteTime; } }
+            set { lastWriteTime = value; }
         }
         
-        public string Link 
-        { 
+        [DatabaseColumn]
+        public string Link { 
             get { lock (sync) { return link; } }
+            set { link = value; }
         }
         
-        public string LocalEnclosurePath 
-        { 
+        [DatabaseColumn]
+        public string LocalEnclosurePath { 
             get { lock (sync) { return localEnclosurePath; } }
-            
             set { 
                 lock (sync) {
                     if (localEnclosurePath != value) {
                         localEnclosurePath = value;
-                        Commit ();                    	
+                        Save ();                    	
                     }
                 }
             }
         }
         
-        public long LocalID 
-        { 
+        [DatabaseColumn ("FeedID", Constraints = DatabaseColumnConstraints.PrimaryKey)]
+        public long DbId { 
             get { lock (sync) { return localID; } }
-            internal set { lock (sync) { localID = value; } }
+            set { lock (sync) { localID = value; } }
         }
 
-        public long MaxItemCount
-        { 
+        [DatabaseColumn]
+        public long MaxItemCount {
             get { lock (sync) { return maxItemCount; } }
             set { lock (sync) { maxItemCount = value; } }
         }
             
-        public string Name 
-        { 
+        [DatabaseColumn]
+        public string Name {
             get { lock (sync) { return name; } }
             
             private set {
@@ -258,7 +244,7 @@
                     if (value != name) {
                     	name = value;
                         renamed = true;
-                        Commit ();
+                        Save ();
                     }
                 }
                 
@@ -267,59 +253,44 @@
                 }
             }            
         }
-
-        public IFeedsManager Parent
-        {
-            get { lock (sync) { return parent; } }
-        }
         
-        public DateTime PubDate 
-        { 
+        [DatabaseColumn]
+        public DateTime PubDate {
             get { lock (sync) { return pubDate; } }
+            set { pubDate = value; }
         }
         
-		public FeedSyncSetting SyncSetting 
-		{ 
+        [DatabaseColumn]
+		public FeedSyncSetting SyncSetting {
             get { lock (sync) { return syncSetting; } } 
+            set { syncSetting = value; }
+        }
+
+        [DatabaseColumn]
+        public FeedAutoDownload AutoDownload {
+            get { return auto_download; }
+            set { auto_download = value; }
         }
         
-        public string Title 
-        { 
-            get { 
+        [DatabaseColumn]
+        public string Title {
+            get {
                 lock (sync) { 
-                    return String.IsNullOrEmpty (title) ?
-                        url : title; 
-                } 
+                    return String.IsNullOrEmpty (title) ? url : title; 
+                }
             }
+            set { title = value; }
         }
               
-        public long Ttl 
-        { 
+        [DatabaseColumn]
+        public long Ttl {
             get { lock (sync) { return ttl; } }
-        }  
-        
-        public long UnreadItemCount 
-        { 
-            get { lock (sync) { return unreadItemCount; } } 
-            
-            internal set {
-                if (value < 0 /*|| value > maxItemCount*/ || value > itemCount) {  
-                    // max item count not yet implemented
-                   	throw new ArgumentOutOfRangeException (
-                        "UnreadItemCount:  Must be >= 0 and < MaxItemCount and <= ItemCount."
-                    );
-                }   
-                
-                if (value != unreadItemCount) {
-                	unreadItemCount = value;
-                }  
-            }
-        }  
+            set { ttl = value; }
+        }
         
-        public string Url 
-        { 
+        [DatabaseColumn]
+        public string Url {
             get { lock (sync) { return url; } }
-            
             set {
                 if (String.IsNullOrEmpty (value)) {
                    	throw new ArgumentNullException ("Url");
@@ -334,7 +305,7 @@
                     	oldUrl = url;
                     	url = value;
                         updated = true;
-                        Commit ();
+                        Save ();
                     }
                 }
                 
@@ -345,7 +316,102 @@
             }
         }
         
-        internal Feed (FeedsManager parent, string url) : this (parent)
+#endregion
+
+#region Other Properties
+
+        public long ActiveDownloadCount { 
+            get { lock (sync) { return activeDownloadCount; } }
+        }
+        
+        public long QueuedDownloadCount { 
+            get { lock (sync) { return queuedDownloadCount; } }             
+        }         
+
+        // TODO remove this, way too redundant with DownloadStatus
+        public PodcastFeedActivity Activity {
+            get {
+                PodcastFeedActivity ret = PodcastFeedActivity.None;
+                
+                if (this == All) {
+                    return ret;
+                }
+                
+                switch (DownloadStatus) {
+                case FeedDownloadStatus.Pending: 
+                    ret = PodcastFeedActivity.UpdatePending;
+                    break;
+                case FeedDownloadStatus.Downloading: 
+                    ret = PodcastFeedActivity.Updating;
+                    break;    
+                case FeedDownloadStatus.DownloadFailed: 
+                    ret = PodcastFeedActivity.UpdateFailed;
+                    break;                         
+                }
+                
+                if (ret != PodcastFeedActivity.Updating) {
+                    if (ActiveDownloadCount > 0) {
+                        ret = PodcastFeedActivity.ItemsDownloading;
+                    } else if (QueuedDownloadCount > 0) {
+                        ret = PodcastFeedActivity.ItemsQueued;
+                    }
+                }
+
+                return ret;
+            }
+        }
+
+        public FeedsManager Parent {
+            get { lock (sync) { return parent; } }
+        }
+        
+        public FeedDownloadStatus DownloadStatus { 
+            get { lock (sync) { return downloadStatus; } }
+        }
+        
+        public bool IsList {
+            get { lock (sync) { return isList; } }
+        }
+        
+        public long ItemCount {
+            get { lock (sync) { return Items.Count; } }         
+        }
+        
+        private bool items_loaded = false;
+        
+        private ReadOnlyCollection<FeedItem> ro_items;
+        public ReadOnlyCollection<FeedItem> Items {
+            get {
+                lock (sync) {
+                    if (!items_loaded) {
+                        LoadItems ();
+                    }
+                    return ro_items ?? ro_items = new System.Collections.ObjectModel.ReadOnlyCollection<FeedItem> (items);                                
+                }
+            }
+        }
+        
+        public long UnreadItemCount {
+            get { lock (sync) { return unreadItemCount; } } 
+            internal set {
+                if (value < 0 /*|| value > maxItemCount*/ || value > ItemCount) {  
+                    // max item count not yet implemented
+                   	throw new ArgumentOutOfRangeException (
+                        "UnreadItemCount:  Must be >= 0 and < MaxItemCount and <= ItemCount."
+                    );
+                }   
+                
+                if (value != unreadItemCount) {
+                	unreadItemCount = value;
+                }
+            }
+        }
+        
+#endregion
+
+#region Constructors
+
+        public Feed (string url) : this ()
         {
             Uri uri;
             if (String.IsNullOrEmpty (url)) {
@@ -358,49 +424,21 @@
                 throw new ArgumentException ("url:  Scheme must be either http or https.");                
             }
 
-            this.url = url;  
+            this.url = url;
         }
-        
-        internal Feed (FeedsManager parent)
-        {
-            if (parent == null) {
-                throw new ArgumentNullException ("parent");
-            }
-            
-            this.parent = parent;
 
-            downloadStatus = FeedDownloadStatus.None;  
-            inactiveItems = new List<FeedItem> ();
-            interval = parent.DefaultInterval; 
-            isList = false;            
-            itemCount = 0;            
+        public Feed ()
+        {
+            parent = FeedsManager.Instance;
+            downloadStatus = FeedDownloadStatus.None;
+            inactive_items = new List<FeedItem> ();
+            interval = parent.DefaultInterval;
             items = new List<FeedItem> ();
-            itemsByID = new Dictionary<long,FeedItem> ();
-            localID = -1;   
-            maxItemCount = 200; //parent.ItemCountLimit;        IGNORED FOR NOW     
-            syncSetting = FeedSyncSetting.Default;            
-            unreadItemCount = 0;       
-            copyright = String.Empty;
-            description = String.Empty;
-            downloadUrl = String.Empty;
-            image = String.Empty;      
-            language = String.Empty;
-            link = String.Empty;
-            localEnclosurePath = String.Empty;
-            name = String.Empty;
-            title = String.Empty;
-            url = String.Empty;
         }
+        
+#endregion
 
-        internal Feed (FeedsManager parent, IFeedWrapper wrapper) : this (parent)
-        {
-            if (wrapper == null) {
-                throw new ArgumentNullException ("wrapper");
-            }
-            
-            url = wrapper.Url;                
-            Update (wrapper, true);  
-        }
+#region Internal Methods
 
         internal long DecrementActiveDownloadCount ()
         {
@@ -484,7 +522,140 @@
                 
                 return queuedDownloadCount;                  
             }            
-        }   
+        }
+        
+        // Should ***ONLY*** be called by 'FeedUpdateTask'
+        internal bool AsyncDownloadImpl ()
+        {              
+            bool ret = false;            
+
+            lock (sync) {
+                if (!(updating || SetUpdating ())) {                
+                    return ret;                   
+                }             
+            }      
+            
+            OnFeedDownloading (); 
+            
+			try {                                                                       
+				wc = new AsyncWebClient ();                  
+				wc.Timeout = (30 * 1000); // 30 Seconds  
+				wc.IfModifiedSince = lastDownloadTime.ToUniversalTime ();
+				
+				downloadStatus = FeedDownloadStatus.Downloading;                    
+				wc.DownloadStringCompleted += OnDownloadStringCompleted;
+				wc.DownloadStringAsync (new Uri (url));
+                
+				ret = true;
+			} catch {
+                downloadStatus = FeedDownloadStatus.DownloadFailed;                                                            
+
+                if (wc != null) {
+                    wc.DownloadStringCompleted -= OnDownloadStringCompleted;
+                    wc = null;
+                }
+                
+                lock (sync) {
+                    ResetUpdating ();
+                    OnFeedDownloadCompleted (
+                        FeedDownloadError.DownloadFailed
+                    );                     
+                }  
+			}
+    
+            return ret;
+        }
+        
+        internal void SetItems (IEnumerable<FeedItem> itms)
+        {
+            if (itms == null) {
+            	throw new ArgumentNullException ("itms");
+            }
+
+            lock (sync) {
+                ClearItemsImpl ();
+                Add (itms);
+            }
+        }
+        
+        
+        internal void CancelDownload (FeedEnclosure enc) 
+        {
+            parent.CancelDownload (enc);
+        }        
+
+        internal HttpFileDownloadTask QueueDownload (FeedEnclosure enc) 
+        {
+            return parent.QueueDownload (enc);
+        }
+
+        internal void StopDownload (FeedEnclosure enc)
+        {
+            parent.StopDownload (enc);
+        }
+        
+        internal void Remove (FeedItem item)
+        {
+            if (item == null) {
+                throw new ArgumentNullException ("item");
+            }
+            
+            lock (sync) {
+                if (items.Remove (item)) {
+                    inactive_items.Add (item);
+                    OnFeedItemRemoved (item);
+                    UpdateItemCountsImpl (-1, (!item.IsRead) ? -1 : 0);
+                }
+            }
+        }
+        
+        internal void Remove (IEnumerable<FeedItem> itms)
+        {
+            if (items == null) {
+                throw new ArgumentNullException ("items");
+            }
+            
+            long totalDelta = 0;            
+            long unreadDelta = 0;
+            
+            List<FeedItem> removedItems = new List<FeedItem> ();                    
+                    
+            lock (sync) {            
+                foreach (FeedItem i in itms) {
+                    if (i != null) {
+                        if (items.Remove (i)) {
+                            --totalDelta;
+                            
+                            if (!i.IsRead) {
+                                --unreadDelta;
+                            }                  
+                            
+                            removedItems.Add (i);
+                            inactive_items.Add (i);
+                        }   
+                    }
+                }
+                
+                if (removedItems.Count > 0) {
+                    OnFeedItemsRemoved (removedItems);
+                }                
+                
+                if (totalDelta != 0) {
+                    UpdateItemCountsImpl (totalDelta, unreadDelta);
+                }                
+            }
+        }
+        
+        internal void UpdateItemCounts (long totalDelta, long unreadDelta)
+        {
+            lock (sync) {
+                UpdateItemCountsImpl (totalDelta, unreadDelta);                    
+            }
+        }
+        
+#endregion
+        
+        // TODO remove, unused?
 /*        
         private void Add (FeedItem item)
         {
@@ -500,7 +671,7 @@
             item.Parent = this;            
             
             if (commit) {
-                item.Commit ();
+                item.Save ();
             }
                         
             if (item.LocalID == -1) {
@@ -516,6 +687,28 @@
             }
         }
 */        
+
+#region Private Methods
+
+        private void LoadItems ()
+        {
+            if (DbId > 0 && !items_loaded) {
+                Console.WriteLine ("Loading items");
+                IEnumerable<FeedItem> items = FeedItem.Provider.FetchAllMatching (String.Format (
+                    "{0}.FeedID = {1}", FeedItem.Provider.TableName, DbId
+                ));
+                
+                foreach (FeedItem item in items) {
+                    item.Feed = this;
+                    item.LoadEnclosure ();
+                }
+                
+                this.items.AddRange (items);
+                Console.WriteLine ("Done loading items");
+                items_loaded = true;
+            }
+        }
+
         private void Add (IEnumerable<FeedItem> itms)
         {
             Add (itms, false);
@@ -530,19 +723,19 @@
             long totalCountDelta = 0;
             long unreadCountDelta = 0;
             
-            List<IFeedItem> newItems = new List<IFeedItem> ();
+            List<FeedItem> newItems = new List<FeedItem> ();
             
             if (commit) {
-                ItemsTableManager.Commit (itms);
+                foreach (FeedItem item in itms)
+                    item.Save ();
             }
             
             foreach (FeedItem i in itms) {
-                i.Parent = this;                
+                i.Feed = this;             
 
-                if (i.LocalID == -1) {
+                if (i.DbId == -1) {
                     continue;
                 } else if (i.Active) {
-                    itemsByID.Add (i.LocalID, i);                        
                     ++totalCountDelta;
                             
                     if (!i.IsRead) {
@@ -552,7 +745,7 @@
                     items.Add (i); 
                     newItems.Add (i);
                 } else {
-                    inactiveItems.Add (i);   
+                    inactive_items.Add (i);   
                 }
             }
 
@@ -561,64 +754,174 @@
             }
             
             UpdateItemCountsImpl (totalCountDelta, unreadCountDelta);
-        }         
+        }
         
-        public void AsyncDownload ()
+        private void ClearItemsImpl ()
         {
-            bool update = false;
+            items.Clear ();
+            UnreadItemCount = 0;            
+        }
+        
+        private void Update (IEnumerable<FeedItem> new_items, bool init)
+        {
+            if (init) {
+                SetItems (new_items);
+            } else {
+                UpdateItems (new_items);         
+            }
+        }
+        
+        private void UpdateItems (IEnumerable<FeedItem> new_items)
+        {
+            ICollection<FeedItem> tmpNew = null;         
+            List<FeedItem> zombies = new List<FeedItem> ();
+         
+            if (items.Count == 0 && inactive_items.Count == 0) {
+                tmpNew = new List<FeedItem> (new_items);
+            } else {
+                // Get remote items that aren't in the items list
+                tmpNew = Diff (items, new_items);
+                
+                // Of those, remove the ones that are in our inactive list
+                tmpNew = Diff (inactive_items, tmpNew);
+                
+                // Get a list of inactive items that aren't in the remote list any longer
+                ICollection<FeedItem> doubleKilledZombies = Diff (
+                    new_items, inactive_items
+                );
+
+                foreach (FeedItem zombie in doubleKilledZombies) {
+                    inactive_items.Remove (zombie);
+                }
+                
+                zombies.AddRange (doubleKilledZombies);                    
+                
+                foreach (FeedItem fi in Diff (new_items, items)) {
+                    if (fi.Enclosure != null &&
+                        !String.IsNullOrEmpty (fi.Enclosure.LocalPath)) {
+                        // A hack for the podcast plugin, keeps downloaded items 
+                        // from being deleted when they are no longer in the feed.
+                        continue;
+                    }
+                    
+                    zombies.Add (fi);
+                }
+            }
             
-            lock (sync) {
-                if (SetUpdating ()) {
-                    update = true;
-                    downloadStatus = FeedDownloadStatus.Pending;
+            if (tmpNew.Count > 0) {
+                Add (tmpNew, true);                
+            }
+            
+            if (zombies.Count > 0) {
+                foreach (FeedItem zombie in zombies) {
+                    if (zombie.Active) {
+                        zombie.Delete ();                        
+                    } 
                 }
-            }            
+                
+                // TODO merge
+                //ItemsTableManager.Delete (zombies);
+            }
+        }    
+
+        // Written before LINQ, will update.
+        private ICollection<FeedItem> Diff (IEnumerable<FeedItem> baseSet, 
+                                            IEnumerable<FeedItem> overlay) {
+            bool found;
+            List<FeedItem> diff = new List<FeedItem> ();
             
-            if (update) {
-                parent.QueueUpdate (this);                
+            foreach (FeedItem opi in overlay) {
+                found = false;
+                
+                foreach (FeedItem bpi in baseSet) {
+                    if (opi.Title == bpi.Title &&
+                        opi.Description == bpi.Description) {
+                        found = true;
+                        break;
+                    }
+                }
+
+                if (!found) {  
+                    diff.Add (opi);
+                }
             }
+
+            return diff;
         }
         
-        // Should ***ONLY*** be called by 'FeedUpdateTask'
-        internal bool AsyncDownloadImpl ()
-        {              
-            bool ret = false;            
+        private void UpdateItemCountsImpl (long totalDelta, long unreadDelta)
+        {
+            //ItemCount += totalDelta;                
+            UnreadItemCount += unreadDelta;
+            FEEDS_EVENTS_ITEM_COUNT_FLAGS flags = 0;
+            
+            if (totalDelta != 0) {   
+                flags |= FEEDS_EVENTS_ITEM_COUNT_FLAGS.FEICF_TOTAL_ITEM_COUNT_CHANGED;                  
+            }             
 
-            lock (sync) {
-                if (!(updating || SetUpdating ())) {                
-                    return ret;                   
-                }             
-            }      
+            if (unreadDelta != 0) {
+                flags |= FEEDS_EVENTS_ITEM_COUNT_FLAGS.FEICF_UNREAD_ITEM_COUNT_CHANGED;
+            }
+                    
+            if (flags != 0) {
+                OnFeedItemCountChanged (flags);  
+            }             
+        }
+        
+        private bool SetDeleted ()
+        {
+            bool ret = false;
             
-            OnFeedDownloading (); 
+            if (!deleted) {
+                ret = deleted = true;
+            }
             
-			try {                                                                       
-				wc = new AsyncWebClient ();                  
-				wc.Timeout = (30 * 1000); // 30 Seconds  
-				wc.IfModifiedSince = lastDownloadTime.ToUniversalTime ();
-				
-				downloadStatus = FeedDownloadStatus.Downloading;                    
-				wc.DownloadStringCompleted += OnDownloadStringCompleted;
-				wc.DownloadStringAsync (new Uri (url));
-                
-				ret = true;
-			} catch {
-                downloadStatus = FeedDownloadStatus.DownloadFailed;                                                            
+            return ret;
+        }
+        
+        private bool SetUpdating ()
+        {
+            bool ret = false;
+            
+            if (!updating && !deleted) {
+                updatingHandle.Reset ();
+                ret = updating = true;
+            }
+            
+            return ret;
+        }        
+        
+        private bool ResetUpdating ()
+        {
+            bool ret = false;
+            
+            if (updating) {
+                updating = false;
+                ret = true;
+                updatingHandle.Set ();                
+            }
+            
+            return ret;    
+        }
+        
+#endregion
 
-                if (wc != null) {
-                    wc.DownloadStringCompleted -= OnDownloadStringCompleted;
-                    wc = null;
+#region Public Methods
+        
+        public void AsyncDownload ()
+        {
+            bool update = false;
+            
+            lock (sync) {
+                if (SetUpdating ()) {
+                    update = true;
+                    downloadStatus = FeedDownloadStatus.Pending;
                 }
-                
-                lock (sync) {
-                    ResetUpdating ();
-                    OnFeedDownloadCompleted (
-                        FeedDownloadError.DownloadFailed
-                    );                     
-                }  
-			}
-    
-            return ret;
+            }            
+            
+            if (update) {
+                parent.QueueUpdate (this);                
+            }
         }
         
         public bool CancelAsyncDownload ()
@@ -641,16 +944,7 @@
             return ret;
         }
         
-        private void ClearItemsImpl ()
-        {
-            items.Clear ();                
-            itemsByID.Clear ();
-                
-            ItemCount = 0;
-            UnreadItemCount = 0;            
-        }
-        
-        public int CompareTo (IFeed right)
+        public int CompareTo (Feed right)
         {
             return title.CompareTo (right.Title);
         }        
@@ -678,7 +972,7 @@
 
                     Remove (itms);                    
                   
-                    FeedsTableManager.Delete (this);   
+                    Provider.Delete (this);   
                     del = true;
                 }
             }
@@ -709,12 +1003,12 @@
             }
         }
         
-        public void Delete (IFeedItem item)
+        public void Delete (FeedItem item)
         {
             Delete (item, true);
         }
         
-        public void Delete (IFeedItem item, bool deleteEncFile)
+        public void Delete (FeedItem item, bool deleteEncFile)
         {
             if (item == null) {
                 throw new ArgumentNullException ("item");     
@@ -722,17 +1016,17 @@
             
             FeedItem feedItem = item as FeedItem;
             
-            if (feedItem != null && feedItem.Parent == this) {
+            if (feedItem != null && feedItem.Feed == this) {
                 feedItem.Delete (deleteEncFile);
             }
         }        
         
-        public void Delete (IEnumerable<IFeedItem> items)
+        public void Delete (IEnumerable<FeedItem> items)
         {
             Delete (items, true);
         }
         
-        public void Delete (IEnumerable<IFeedItem> items, bool deleteEncFiles)
+        public void Delete (IEnumerable<FeedItem> items, bool deleteEncFiles)
         {
             if (items == null) {
                 throw new ArgumentNullException ("items");     
@@ -742,17 +1036,18 @@
             List<FeedItem> deletedItems = new List<FeedItem> ();
             
             lock (sync) {
-                foreach (IFeedItem item in items) {
+                foreach (FeedItem item in items) {
                     tmpItem = item as FeedItem;
 
-                    if (tmpItem != null && tmpItem.Parent == this) {
+                    if (tmpItem != null && tmpItem.Feed == this) {
                         tmpItem.DeleteImpl (false, deleteEncFiles);
                         deletedItems.Add (tmpItem);
+
+                        tmpItem.Active = false;
+                        tmpItem.Save ();
                     }
                 }
                 
-                ItemsTableManager.Deactivate (deletedItems);            
-                
                 if (deletedItems.Count > 0) {
                     Remove (deletedItems);
                 }
@@ -764,19 +1059,20 @@
             throw new NotImplementedException ("Download");
         }
 
-        public IFeedItem GetItem (long itemID)
+        // TODO remove, unused
+        /*public FeedItem GetItem (long itemID)
         {
             lock (sync) { 
                 FeedItem item;
-                itemsByID.TryGetValue (itemID, out item);
-                return item as IFeedItem;
+                item_id_map.TryGetValue (itemID, out item);
+                return item as FeedItem;
             }
-        }
+        }*/
 
         public void MarkAllItemsRead ()
         {
             lock (sync) {
-                foreach (IFeedItem i in items) {
+                foreach (FeedItem i in items) {
                     i.IsRead = true;
                 }
             }
@@ -788,237 +1084,13 @@
                 "Title:  {0} - Url:  {1}",
                 Title, Url                                  
             );   
-        }   
-        
-        internal void SetItems (IEnumerable<FeedItem> itms)
-        {
-            if (itms == null) {
-            	throw new ArgumentNullException ("itms");
-            }
-
-            lock (sync) {
-                ClearItemsImpl ();
-                Add (itms);
-            }
-        }
-
-        private void Update (IFeedWrapper wrapper, bool init)
-        {
-            if (wrapper == null) {
-                throw new ArgumentNullException ("wrapper");
-            }
-            
-            copyright = wrapper.Copyright;
-            description = wrapper.Description;
-            downloadUrl = wrapper.DownloadUrl;
-            image = wrapper.Image;
-            Interval = wrapper.Interval;
-            isList = wrapper.IsList;
-            language = wrapper.Language;
-            lastBuildDate = wrapper.LastBuildDate;
-            lastDownloadTime = wrapper.LastDownloadTime;                      
-            lastWriteTime = lastBuildDate;  // This is not correct!!!!!
-            link = wrapper.Link;
-            localEnclosurePath = wrapper.LocalEnclosurePath;            
-            pubDate = wrapper.PubDate;
-            title = wrapper.Title;
-            ttl = wrapper.Ttl;
-            
-            List<FeedItem> itms = new List<FeedItem> ();
-            
-            if (wrapper.Items != null) {            
-                FeedItem tmpItem = null;
-
-                foreach (IFeedItemWrapper i in wrapper.Items) {
-                    try {
-                        tmpItem = CreateFeedItem (i);                    
-                        
-                        if (tmpItem != null) {
-                            itms.Add (tmpItem);
-                        }
-                    } catch {}
-                }                            
-            }            
-            
-            if (init) {
-                SetItems (itms);
-                localID = wrapper.LocalID;
-                name = wrapper.Name;
-            } else {
-                Name = wrapper.Name;
-                UpdateItems (itms);         
-            }
         }
-        
-        private void UpdateItems (ICollection<FeedItem> remoteItems)
-        {            
-            ICollection<FeedItem> tmpNew = null;         
-            List<FeedItem> zombies = new List<FeedItem> ();         
-         
-            if (items.Count == 0 && inactiveItems.Count == 0) {
-                tmpNew = remoteItems;            
-            } else {
-                tmpNew = Diff (items, remoteItems);
-                tmpNew = Diff (inactiveItems, tmpNew);
-                
-                ICollection<FeedItem> doubleKilledZombies = Diff (
-                    remoteItems, inactiveItems
-                );                 
-                
-                foreach (FeedItem zombie in doubleKilledZombies) {
-                    inactiveItems.Remove (zombie);
-                }
-                
-                zombies.AddRange (doubleKilledZombies);                    
-                
-                foreach (FeedItem fi in Diff (remoteItems, items)) {
-                    if (fi.Enclosure != null &&
-                        !String.IsNullOrEmpty (fi.Enclosure.LocalPath)) {
-                        // A hack for the podcast plugin, keeps downloaded items 
-                        // from being deleted when they are no longer in the feed.
-                        continue;
-                    }
-                    
-                    zombies.Add (fi);
-                }
-            }
-            
-            if (tmpNew.Count > 0) {
-                Add (tmpNew, true);                
-            }
-            
-            if (zombies.Count > 0) {
-                foreach (FeedItem zombie in zombies) {
-                    if (zombie.Active) {
-                        zombie.Delete ();                        
-                    } 
-                }
-                
-                // ZombieRifle.Polish ();
-                ItemsTableManager.Delete (zombies);
-            }
-        }        
-
-        // Written before LINQ, will update.
-        private ICollection<FeedItem> Diff (IEnumerable<FeedItem> baseSet, 
-                                            IEnumerable<FeedItem> overlay) {
-            bool found;
-            List<FeedItem> diff = new List<FeedItem> ();
-            
-            foreach (FeedItem opi in overlay) {
-                found = false;
-                
-                foreach (FeedItem bpi in baseSet) {
-                    if (opi.Title == bpi.Title &&
-                        opi.Description == bpi.Description) {
-                        found = true;
-                        break;
-                    }
-                }
-
-                if (!found) {  
-                    diff.Add (opi);
-                }
-            }
-
-            return diff;
-        }        
 
-        internal void Commit ()
+        public void Save ()
         {
-            if (localID <= 0) {
-                localID = FeedsTableManager.Insert (this);
-            } else {
-                try {
-                    FeedsTableManager.Update (this);
-                } catch {
-                    //Console.WriteLine (e.StackTrace);
-                    throw;
-                }
-            }
+            Provider.Save (this);
         }   
-        
-        private FeedItem CreateFeedItem (IFeedItemWrapper wrapper)
-        {
-            FeedItem ret = null;
-            
-            try {
-                ret = new FeedItem (this, wrapper);
-            } catch {}
-            
-            return ret; 
-        }
 
-        internal void CancelDownload (FeedEnclosure enc) 
-        {
-            parent.CancelDownload (enc);
-        }        
-
-        internal HttpFileDownloadTask QueueDownload (FeedEnclosure enc) 
-        {
-            return parent.QueueDownload (enc);
-        }
-
-        internal void StopDownload (FeedEnclosure enc)
-        {
-            parent.StopDownload (enc);
-        }
-        
-        internal void Remove (FeedItem item)
-        {
-            if (item == null) {
-                throw new ArgumentNullException ("item");
-            }
-            
-            lock (sync) {
-                if (items.Remove (item)) {
-                    inactiveItems.Add (item);                    
-                    itemsByID.Remove (item.LocalID);
-                    
-                    OnFeedItemRemoved (item);
-                    UpdateItemCountsImpl (-1, (!item.IsRead) ? -1 : 0);
-                }
-            }
-        }
-        
-        internal void Remove (IEnumerable<FeedItem> itms)
-        {
-            if (items == null) {
-                throw new ArgumentNullException ("items");
-            }
-            
-            long totalDelta = 0;            
-            long unreadDelta = 0;
-            
-            List<IFeedItem> removedItems = new List<IFeedItem> ();                    
-                    
-            lock (sync) {            
-                foreach (FeedItem i in itms) {
-                    if (i != null) {
-                        if (items.Remove (i)) {
-                            --totalDelta;
-                            
-                            if (!i.IsRead) {
-                                --unreadDelta;
-                            }                  
-                            
-                            removedItems.Add (i);
-                            inactiveItems.Add (i);                            
-                            itemsByID.Remove (i.LocalID);
-                        }   
-                    }
-                }
-                
-                if (removedItems.Count > 0) {
-                    OnFeedItemsRemoved (removedItems);
-                }                
-                
-                if (totalDelta != 0) {
-                    UpdateItemCountsImpl (totalDelta, unreadDelta);
-                }                
-            }
-        }
-        
         private bool SetCanceled ()
         {
             bool ret = false;
@@ -1028,83 +1100,25 @@
             }
             
             return ret;
-        }        
-        
-        private bool SetDeleted ()
-        {
-            bool ret = false;
-            
-            if (!deleted) {
-                ret = deleted = true;
-            }
-            
-            return ret;
-        }
-        
-        private bool SetUpdating ()
-        {
-            bool ret = false;
-            
-            if (!updating && !deleted) {
-                updatingHandle.Reset ();
-                ret = updating = true;
-            }
-            
-            return ret;
-        }        
-        
-        private bool ResetUpdating ()
-        {
-            bool ret = false;
-            
-            if (updating) {
-                updating = false;
-                ret = true;
-                updatingHandle.Set ();                
-            }
-            
-            return ret;    
-        }
-        
-        internal void UpdateItemCounts (long totalDelta, long unreadDelta)
-        {
-            lock (sync) {
-                UpdateItemCountsImpl (totalDelta, unreadDelta);                    
-            }
         }
         
-        private void UpdateItemCountsImpl (long totalDelta, long unreadDelta)
-        {
-            ItemCount += totalDelta;                
-            UnreadItemCount += unreadDelta;
-            FEEDS_EVENTS_ITEM_COUNT_FLAGS flags = 0;
-            
-            if (totalDelta != 0) {   
-                flags |= FEEDS_EVENTS_ITEM_COUNT_FLAGS.FEICF_TOTAL_ITEM_COUNT_CHANGED;                  
-            }             
+#endregion
 
-            if (unreadDelta != 0) {
-                flags |= FEEDS_EVENTS_ITEM_COUNT_FLAGS.FEICF_UNREAD_ITEM_COUNT_CHANGED;
-            }
-                    
-            if (flags != 0) {
-                OnFeedItemCountChanged (flags);  
-            }             
-        }        
+#region Private Event Handlers
         
         // Wow, this sucks, see the header FeedsManager Header. 
         private void OnDownloadStringCompleted (object sender, 
-                                                Migo.Net.DownloadStringCompletedEventArgs e) 
+                                                Migo.Net.DownloadStringCompletedEventArgs args) 
         {
             FeedDownloadError error = FeedDownloadError.None;            
 
             try {
                 lock (sync) {                              
                     try { 
-                        if (e.Error != null) {
+                        if (args.Error != null) {
                             error = FeedDownloadError.DownloadFailed;                                                        
                             
-                            WebException we = e.Error as WebException;   
+                            WebException we = args.Error as WebException;   
 
                             if (we != null) {
                                 HttpWebResponse resp = we.Response as HttpWebResponse;
@@ -1131,17 +1145,18 @@
                             error = FeedDownloadError.Canceled;                        
                         } else {
                             try {
-                                IFeedWrapper wrapper = new RssFeedWrapper (Url, e.Result);                             
-                                Update (wrapper, false);
-                            } catch (FormatException) {
-                                //Console.WriteLine ("FormatException:  {0}", fe.Message);
+                                RssParser parser = new RssParser (Url, args.Result);
+                                parser.UpdateFeed (this);
+                                Update (parser.GetFeedItems (), false);
+                            } catch (FormatException e) {
+                                Log.Exception (e);
                                 error = FeedDownloadError.InvalidFeedFormat;
                             }                          
                         }                        
-                    } catch (Exception e2) {
+                    } catch (Exception e) {
                         //Console.WriteLine ("Update error");
-                        Console.WriteLine (e2.Message);
-                        Console.WriteLine (e2.StackTrace);                        
+                        Console.WriteLine (e.Message);
+                        Console.WriteLine (e.StackTrace);                        
                         throw;
                     } finally {  
                         canceled = updating = false;
@@ -1159,7 +1174,7 @@
                         downloadStatus = FeedDownloadStatus.DownloadFailed;                                                    
                     }
                         
-                    Commit ();
+                    Save ();
                     
                     OnFeedDownloadCompleted (error);
                 } finally {                
@@ -1169,7 +1184,7 @@
         }
 
 /*      May add support for individual add in the future, but right now IEnumerables work           
-        private void OnFeedItemAdded (IFeedItem item)
+        private void OnFeedItemAdded (FeedItem item)
         {
             if (item == null) {
                 throw new ArgumentNullException ("item");
@@ -1186,7 +1201,8 @@
             }));  
         }
 */        
-        private void OnFeedItemsAdded (IEnumerable<IFeedItem> items)
+
+        private void OnFeedItemsAdded (IEnumerable<FeedItem> items)
         {
             if (items == null) {
                 throw new ArgumentNullException ("items");
@@ -1203,7 +1219,7 @@
             }));               
         }    
         
-        private void OnFeedItemRemoved (IFeedItem item)
+        private void OnFeedItemRemoved (FeedItem item)
         {
             if (item == null) {
                 throw new ArgumentNullException ("item");
@@ -1220,7 +1236,7 @@
             }));                        
         }
         
-        private void OnFeedItemsRemoved (IEnumerable<IFeedItem> items)
+        private void OnFeedItemsRemoved (IEnumerable<FeedItem> items)
         {
             if (items == null) {
                 throw new ArgumentNullException ("items");
@@ -1324,6 +1340,9 @@
             if (handlerCpy != null) {
                 handlerCpy (this, new FeedEventArgs (this));
             }
-        } 
+        }
+
+#endregion        
+
     }
 }    

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedEnclosure.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedEnclosure.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedEnclosure.cs	Mon Apr 28 21:42:18 2008
@@ -1,98 +1,92 @@
-/*************************************************************************** 
- *  FeedEnclosure.cs
- *
- *  Copyright (C) 2007 Michael C. Urbanski
- *  Written by Mike Urbanski <michael c urbanski gmail com>
- ****************************************************************************/
- 
-/*  THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: 
- *
- *  Permission is hereby granted, free of charge, to any person obtaining a
- *  copy of this software and associated documentation files (the "Software"),  
- *  to deal in the Software without restriction, including without limitation  
- *  the rights to use, copy, modify, merge, publish, distribute, sublicense,  
- *  and/or sell copies of the Software, and to permit persons to whom the  
- *  Software is furnished to do so, subject to the following conditions:
- *
- *  The above copyright notice and this permission notice shall be included in 
- *  all copies or substantial portions of the Software.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
- *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
- *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
- *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
- *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
- *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
- *  DEALINGS IN THE SOFTWARE.
- */
+//
+// FeedEnclosure.cs
+//
+// Authors:
+//   Mike Urbanski  <michael c urbanski gmail com>
+//   Gabriel Burt  <gburt novell com>
+//
+// Copyright (C) 2007 Michael C. Urbanski
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 
 using System;
 using System.IO;
 
+using Hyena;
+using Hyena.Data.Sqlite;
+
 using Migo.Syndication.Data;
 
 namespace Migo.Syndication
 {
-    public class FeedEnclosure : IFeedEnclosure 
+    public class FeedEnclosure
     {
+        private static SqliteModelProvider<FeedEnclosure> provider;
+        public static SqliteModelProvider<FeedEnclosure> Provider {
+            get { return provider; }
+            set { provider = value; }
+        }
+        
         private bool canceled;
         private bool downloading;
         private bool stopped;
         
-        private string downloadMimeType;
-        private FeedDownloadStatus downloadStatus;        
-        private string downloadUrl;
+        private string mimetype;
+        private FeedDownloadStatus download_status;        
         private bool active;
-        private FeedDownloadError lastDownloadError;
+        private FeedDownloadError last_download_error;
         private long length;
-        private long localID;
-        private string localPath;
-        private FeedItem parent;
-        private string type;
+        
+        private string local_path;
+        private FeedItem item;
         private string url;     
         
         private readonly object sync = new object ();
         
-        internal bool Active 
+#region Constructors
+
+        public FeedEnclosure ()
         {
-            get { 
-                lock (sync) {                
-                    return active; 
-                }
-            }
-            
-            set {
-                lock (sync) {
-                    active = value;
-                }
-            }
-        }
-       
-        public string DownloadMimeType 
-        { 
-            get {
-                lock (sync) { 
-                    return downloadMimeType; 
-                }
-            }
         }
+        
+#endregion
+
+#region Public Properties
 
-        public FeedDownloadStatus DownloadStatus 
-        { 
+        public FeedDownloadStatus DownloadStatus { 
             get { 
                 lock (sync) {
-                    return downloadStatus;
+                    return download_status;
                 }
             }
             
             internal set { 
                 lock (sync) {
-                    downloadStatus = value;
+                    download_status = value;
                     //Console.WriteLine ("Enclosure:  DownloadStatus:  {0}", downloadStatus);
                     switch (value) {
                     case FeedDownloadStatus.DownloadFailed: goto case FeedDownloadStatus.None;
                     case FeedDownloadStatus.Downloaded: 
-                        Commit ();
+                        Save ();
                         goto case FeedDownloadStatus.None;
                     case FeedDownloadStatus.None:
                         ResetDownloading ();
@@ -100,100 +94,38 @@
                     }
                 }
             }             
-        }        
-        
-        public string DownloadUrl 
-        { 
-            get { lock (sync) { return downloadUrl; } } 
         }
 
-        public FeedDownloadError LastDownloadError
-        {
-            get { 
-                lock (sync) {
-                    return lastDownloadError; 
-                }
-            }
-            
-            internal set {
-                lock (sync) {
-                    lastDownloadError = value;                
-                }
-            }
-        }
-        
-        public long Length 
-        { 
-            get { lock (sync) { return length; } } 
-        }
-        
-        public long LocalID 
-        { 
-            get { return localID; }
-            internal set { localID = value; }
-        }
-        
-        public string LocalPath 
-        { 
-            get { lock (sync) { return localPath; } } 
-        }
-        
-        public IFeedItem Parent 
-        { 
-            get { return parent; } 
+        public FeedItem Item { 
+            get { return item; } 
             internal set {          
                 if (value == null) {
                 	throw new ArgumentNullException ("Parent");
                 }
 
-                parent = value as FeedItem;
+                item = value as FeedItem;
                 
-                if (parent == null) {
+                if (item == null) {
                     throw new ArgumentException (
                         "Parent must be of type FeedItem"
                     );
                 }
             }
         }
+
+#endregion
+
+#region Public Methods
         
-        public string Type 
-        { 
-            get { lock (sync) { return type; } } 
+        public void Save ()
+        {
+            Provider.Save (this);
         }
         
-        public string Url 
-        { 
-            get { lock (sync) { return url; } } 
-        }
- 
-        internal FeedEnclosure (IFeedEnclosureWrapper wrapper) : this (null, wrapper) {}
-        internal FeedEnclosure (FeedItem parent, IFeedEnclosureWrapper wrapper)
-        {
-            if (wrapper == null) {
-                throw new ArgumentNullException ("wrapper");            	
-            }
-            
-            active = wrapper.Active;
-            localID = wrapper.LocalID;
-            downloadMimeType = wrapper.DownloadMimeType;
-            downloadUrl = wrapper.DownloadUrl;
-            length = wrapper.Length;
-            lastDownloadError = wrapper.LastDownloadError;
-            localPath = wrapper.LocalPath;
-            type = wrapper.Type;
-            url = wrapper.Url;    
-
-            if (!String.IsNullOrEmpty (localPath)) {
-                downloadStatus = FeedDownloadStatus.Downloaded;
-            }            
-            
-            this.parent = parent;
-        }        
-
         public void AsyncDownload ()
         {            
             if (SetDownloading ()) {
-                if (!parent.QueueDownload (this)) {
+                if (!item.QueueDownload (this)) {
                     ResetDownloading ();
                 }
             }
@@ -206,31 +138,10 @@
             }
         }
 
-        private void CancelAsyncDownloadImpl ()      
-        {
-            parent.CancelDownload (this);            
-        }
-
         public void StopAsyncDownload ()
         {
             if (SetStopped ()) {
-                parent.StopDownload (this);
-            }
-        }
-        
-        private void CheckActive ()
-        {
-            if (!active) {
-                throw new InvalidOperationException ("Enclosure previously deleted");                    
-            }
-        }
-        
-        internal void Commit ()
-        {
-            if (localID < 0) {
-                localID = EnclosuresTableManager.Insert (this);
-            } else {
-                EnclosuresTableManager.Update (this);
+                item.StopDownload (this);
             }
         }
         
@@ -241,23 +152,90 @@
             lock (sync) {                
                 CheckActive ();            
                 
-                if (!String.IsNullOrEmpty (localPath) && File.Exists (localPath)) {
+                if (!String.IsNullOrEmpty (local_path) && File.Exists (local_path)) {
                 	try {
                         FileAttributes attributes = 
-                                File.GetAttributes (localPath) | FileAttributes.ReadOnly;
+                                File.GetAttributes (local_path) | FileAttributes.ReadOnly;
 
                         if (attributes == FileAttributes.ReadOnly) {
-                            File.Delete (localPath);	
+                            File.Delete (local_path);	
                         }
                         
-                        Directory.Delete (Path.GetDirectoryName (localPath));
+                        Directory.Delete (Path.GetDirectoryName (local_path));
                 	} catch {}
                 }
                 
-                localPath = String.Empty;
-                downloadStatus = FeedDownloadStatus.None;                                
+                local_path = String.Empty;
+                download_status = FeedDownloadStatus.None;                                
                 
-                Commit ();
+                Save ();
+            }
+        }
+        
+#endregion
+
+#region Database Columns
+
+        [DatabaseColumn]
+        public long Length { 
+            get { lock (sync) { return length; } } 
+            set { length = value; }
+        }
+        
+        [DatabaseColumn ("EnclosureID", Constraints = DatabaseColumnConstraints.PrimaryKey)]
+        private long dbid;
+        public long DbId { 
+            get { return dbid; }
+            internal set { dbid = value; }
+        }
+        
+        [DatabaseColumn ("ParentID")]
+        private long parent_id;
+        public long ParentId {
+            get { return parent_id; }
+        }
+        
+        [DatabaseColumn]
+        public string LocalPath { 
+            get { lock (sync) { return local_path; } }
+            set { local_path = value; }
+        }
+        
+        [DatabaseColumn]
+        public string Url { 
+            get { lock (sync) { return url; } } 
+            set { url = value; }
+        }
+        
+        [DatabaseColumn]
+        public string MimeType {
+            get { return mimetype; }
+            set {
+                mimetype = value;
+                if (String.IsNullOrEmpty (mimetype)) {
+                    mimetype = "application/octet-stream";
+                }
+            }
+        }
+        
+        [DatabaseColumn]
+        public FeedDownloadError LastDownloadError {
+            get { lock (sync) { return last_download_error;  } }
+            internal set { lock (sync) { last_download_error = value; } }
+        }
+        
+        [DatabaseColumn]
+        internal bool Active {
+            get { lock (sync) { return active; } }
+            set { lock (sync) { active = value; } }
+        }
+
+#endregion
+
+        private void CheckActive ()
+        {
+            if (!active) {
+                throw new InvalidOperationException ("Enclosure previously deleted");                    
             }
         }
 
@@ -280,7 +258,7 @@
                 //Console.WriteLine ("Status - SetCanceled:  canceled:  {0} - downloading:  {1}", canceled, downloading);
                 if (!canceled && !stopped && downloading) {
                     ret = canceled = true;
-                    lastDownloadError = FeedDownloadError.Canceled;
+                    last_download_error = FeedDownloadError.Canceled;
                 }   
             }
                 //Console.WriteLine ("Status - SetCanceled:  ret:  {0}", ret);
@@ -293,13 +271,13 @@
             
             lock (sync) {
                 if (!downloading && 
-                    downloadStatus != FeedDownloadStatus.Downloaded) {
+                    download_status != FeedDownloadStatus.Downloaded) {
                     canceled = false;
                     stopped = false;
                     ret = downloading = true;    
                     
-                    downloadStatus = FeedDownloadStatus.Pending;                    
-                    lastDownloadError = FeedDownloadError.None;
+                    download_status = FeedDownloadStatus.Pending;                    
+                    last_download_error = FeedDownloadError.None;
                 }            
             }
             
@@ -313,23 +291,23 @@
             lock (sync) {
                 if (!canceled && !stopped && downloading) {
                     ret = stopped = true;
-                    lastDownloadError = FeedDownloadError.Canceled;
+                    last_download_error = FeedDownloadError.Canceled;
                 }            
             }
             
             return ret;            
         }
-
-        public void SetFile (string url, string path, string mimeType, string filename)
+        
+        private void CancelAsyncDownloadImpl ()      
         {
-            
+            item.CancelDownload (this);            
         }
-        
+
         internal void SetFileImpl (string url, string path, string mimeType, string filename)
         {      
             string tmpLocalPath;
             string fullPath = path;
-            string localEnclosurePath = parent.Parent.LocalEnclosurePath;
+            string localEnclosurePath = item.Feed.LocalEnclosurePath;
             
             lock (sync) {   
                 CheckActive ();                
@@ -382,20 +360,20 @@
                         Directory.Delete (path);
                     } catch {}
                 } catch { 
-                    lastDownloadError = FeedDownloadError.DownloadFailed;
-                    downloadStatus = FeedDownloadStatus.DownloadFailed;
+                    last_download_error = FeedDownloadError.DownloadFailed;
+                    download_status = FeedDownloadStatus.DownloadFailed;
                     throw;
                 }
                 
-                localPath = tmpLocalPath;
+                local_path = tmpLocalPath;
                 
-                this.downloadUrl = url;
-                this.downloadMimeType = mimeType;
+                this.url = url;
+                this.mimetype = mimeType;
                                 
-                downloadStatus = FeedDownloadStatus.Downloaded;
-                lastDownloadError = FeedDownloadError.None;                    
+                download_status = FeedDownloadStatus.Downloaded;
+                last_download_error = FeedDownloadError.None;                    
 
-                Commit ();
+                Save ();
             }
         }
     }

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedItem.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedItem.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedItem.cs	Mon Apr 28 21:42:18 2008
@@ -1,39 +1,51 @@
-/*************************************************************************** 
- *  FeedItem.cs
- *
- *  Copyright (C) 2007 Michael C. Urbanski
- *  Written by Mike Urbanski <michael c urbanski gmail com>
- ****************************************************************************/
- 
-/*  THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: 
- *
- *  Permission is hereby granted, free of charge, to any person obtaining a
- *  copy of this software and associated documentation files (the "Software"),  
- *  to deal in the Software without restriction, including without limitation  
- *  the rights to use, copy, modify, merge, publish, distribute, sublicense,  
- *  and/or sell copies of the Software, and to permit persons to whom the  
- *  Software is furnished to do so, subject to the following conditions:
- *
- *  The above copyright notice and this permission notice shall be included in 
- *  all copies or substantial portions of the Software.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
- *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
- *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
- *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
- *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
- *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
- *  DEALINGS IN THE SOFTWARE.
- */
+//
+// FeedItem.cs
+//
+// Authors:
+//   Mike Urbanski  <michael c urbanski gmail com>
+//   Gabriel Burt  <gburt novell com>
+//
+// Copyright (C) 2007 Michael C. Urbanski
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 
 using System;
+using System.Collections.Generic;
+
+using Hyena;
+using Hyena.Data.Sqlite;
 
 using Migo.Syndication.Data;
 
 namespace Migo.Syndication
 {
-    public class FeedItem : IFeedItem
+    public class FeedItem
     {
+        private static SqliteModelProvider<FeedItem> provider;
+        public static SqliteModelProvider<FeedItem> Provider {
+            get { return provider; }
+            set { provider = value; }
+        }
+
         private bool active;
         private string author;
         private string comments;
@@ -43,27 +55,23 @@
         private bool isRead;
         private DateTime lastDownloadTime;  
         private string link;
-        private long localID;
+        private long dbid;
         private DateTime modified;     
-        private Feed parent;
+        private Feed feed;
         private DateTime pubDate;       
         private string title;        
         
         public readonly object sync = new object ();
+
+#region Database-backed Properties
                 
-        internal bool Active 
-        {
-            get { 
-                lock (sync) {
-                    return active; 
-                }
-            }
-            
+        [DatabaseColumn]
+        internal bool Active {
+            get { lock (sync) { return active; } }
             set { 
                 lock (sync) {                
                     if (value != active) {
                         active = value;
-                    
                         if (enclosure != null) {
                             enclosure.Active = value;
                         }
@@ -72,78 +80,33 @@
             }
         }
         
-        public string Author 
-        { 
-            get { 
-                lock (sync) {
-                    return author; 
-                } 
-            }
+        [DatabaseColumn]
+        public string Author {
+            get { lock (sync) { return author; } }
+            set { author = value; }
         }
         
-        public string Comments 
-        { 
-            get { 
-                lock (sync) {
-                    return comments; 
-                }
-            } 
+        [DatabaseColumn]
+        public string Comments {
+            get { lock (sync) { return comments; } } 
+            set { comments = value; }
         }
         
-        public string Description 
-        { 
-            get { 
-                lock (sync) {
-                    return description; 
-                }
-            } 
+        [DatabaseColumn]
+        public string Description {
+            get { lock (sync) { return description; }} 
+            set { description = value; }
         }
         
-        public IFeedEnclosure Enclosure 
-        { 
-            get { 
-                lock (sync) {
-                    return enclosure;
-                }
-            }
-            
-            internal set {
-                lock (sync) {
-                    if (value == null) {
-                        throw new ArgumentNullException ("Enclosure");
-                    }
-                        
-                    FeedEnclosure tmp = value as FeedEnclosure;
-            
-                    if (tmp == null) {
-                        throw new ArgumentException (
-                            "Enclosure must be derived from 'FeedEnclosure'"
-                        );
-                    }
-                        
-                    enclosure = tmp;
-                    enclosure.Parent = this;
-                }
-            }            
+        [DatabaseColumn]
+        public string Guid {
+            get { lock (sync) { return guid; } }
+            set { guid = value; }
         }
 
-        public string Guid 
-        { 
-            get { 
-                lock (sync) {
-                    return guid; 
-                } 
-            }
-        }
-        
-        public bool IsRead 
-        { 
-            get { 
-                lock (sync) {
-                    return isRead;
-                }
-            } 
-            
+        [DatabaseColumn]
+        public bool IsRead {
+            get { lock (sync) { return isRead; } }
             set { 
                 int delta = 0;                
                 
@@ -152,149 +115,127 @@
                         isRead = value;
                         delta = value ? -1 : 1;    
                         
-                        if (parent == null) {
+                        if (feed == null) {
                             return;
                         }
                                 
-                        CommitImpl ();
+                        Save ();
                     }
                 }
                 
                 if (delta != 0) {
-                    parent.UpdateItemCounts (0, delta);                            
+                    feed.UpdateItemCounts (0, delta);                            
                 }                                            
             }
         }
         
-        public DateTime LastDownloadTime 
-        { 
-            get { 
-                lock (sync) {
-                    return lastDownloadTime;
-                }
-            } 
+        [DatabaseColumn]
+        public DateTime LastDownloadTime {
+            get { lock (sync) { return lastDownloadTime; } } 
+            set { lastDownloadTime = value; }
         }  
         
-        public string Link 
-        { 
-            get { 
-                lock (sync) {
-                    return link; 
-                } 
-            }
+        [DatabaseColumn]
+        public string Link {
+            get { lock (sync) { return link; } }
+            set { link = value; }
         }
         
-        public long LocalID 
-        { 
-            get { 
-                lock (sync) {   
-                    return localID; 
-                }
-            }
-            
+        [DatabaseColumn ("ItemID", Constraints = DatabaseColumnConstraints.PrimaryKey)]
+        public long DbId {
+            get { lock (sync) { return dbid; } }
             internal set { 
                 lock (sync) { 
-                    localID = value; 
+                    dbid = value; 
                 }
             }
         }
         
-        public DateTime Modified 
-        { 
-            get { 
-                lock (sync) {
-                    return modified;
-                }
-            } 
+        [DatabaseColumn]
+        public DateTime Modified { 
+            get { lock (sync) { return modified; } } 
+            set { modified = value; }
         }      
         
-        public IFeed Parent 
-        { 
-            get { lock (sync) { return parent; } }
+        [DatabaseColumn]
+        public DateTime PubDate {
+            get { lock (sync) { return pubDate; } } 
+            set { pubDate = value; }
+        }       
+        
+        [DatabaseColumn]
+        public string Title {
+            get { lock (sync) { return title; } } 
+            set { title = value; }
+        }
+
+#endregion
+
+        public Feed Feed {
+            get { lock (sync) { return feed; } }
             
             internal set {
                 if (value == null) {
-                	throw new ArgumentNullException ("Parent");              	
+                    throw new ArgumentNullException ("Feed");
                 }
                 
                 lock (sync) {  
-                    Feed feed = value as Feed;
-                    
-                    if (feed == null) {
-                        throw new ArgumentException ("Parent must be of type 'Feed'");
-                    }
-                    
-                    parent = feed;
+                    feed = value;
                 }
             }
         }
         
-        public DateTime PubDate 
-        { 
-            get { lock (sync) { return pubDate; } } 
-        }       
-        
-        public string Title 
-        { 
-            get { lock (sync) { return title; } } 
-        }      
-
-        internal FeedItem (IFeedItemWrapper wrapper) : this (null, wrapper) {}
-        internal FeedItem (Feed parent, IFeedItemWrapper wrapper)
+        private bool enclosure_loaded;
+        public void LoadEnclosure ()
         {
-            if (wrapper == null) {
-                throw new ArgumentNullException ("wrapper");            	
-            }    
-
-            this.parent = parent; 
-            
-            active = wrapper.Active;
-            author = wrapper.Author;
-            comments = wrapper.Comments;
-            description = wrapper.Description;
-            guid = wrapper.Guid;
-            isRead = wrapper.IsRead;
-            lastDownloadTime = wrapper.LastDownloadTime;  
-            link = wrapper.Link;
-            localID = wrapper.LocalID;
-            modified = wrapper.Modified;
-            pubDate = wrapper.PubDate;       
-            title = wrapper.Title;
-            
-            if (wrapper.Enclosure != null) {
-                CreateEnclosure (wrapper.Enclosure);  
-            }            
-        }        
-
-        internal void Commit ()
-        {
-            lock (sync) {
-                CommitImpl ();
+            if (!enclosure_loaded && DbId > 0) {
+                Console.WriteLine ("Loading item enclosures");
+                IEnumerable<FeedEnclosure> enclosures = FeedEnclosure.Provider.FetchAllMatching (String.Format (
+                    "{0}.ItemID = {1}", FeedEnclosure.Provider.TableName, DbId
+                ));
+                
+                foreach (FeedEnclosure enclosure in enclosures) {
+                    enclosure.Item = this;
+                    this.enclosure = enclosure;
+                    break; // should only have one
+                }
+                Console.WriteLine ("Done loading item enclosures");
+                enclosure_loaded = true;
             }
         }
-        
-        private void CommitImpl ()
-        {
-            if (localID < 0) {
-                localID = ItemsTableManager.Insert (this);
-            } else {
-                ItemsTableManager.Update (this);   
-            }
+
+        public FeedEnclosure Enclosure {
+            get { lock (sync) { return enclosure; } }
+            internal set {
+                lock (sync) {
+                    if (value == null) {
+                        throw new ArgumentNullException ("Enclosure");
+                    }
                         
-            if (enclosure != null) {
-                enclosure.Commit ();
+                    FeedEnclosure tmp = value as FeedEnclosure;
+            
+                    if (tmp == null) {
+                        throw new ArgumentException (
+                            "Enclosure must be derived from 'FeedEnclosure'"
+                        );
+                    }
+                        
+                    enclosure = tmp;
+                    enclosure.Item = this;
+                }
             }            
         }
-        
-        private void CreateEnclosure (IFeedEnclosureWrapper wrapper)
-        {   
-            enclosure = new FeedEnclosure (this, wrapper);
+ 
+        public FeedItem ()
+        {
         }
-        
-        internal void DBDelete ()
+
+        public void Save ()
         {
-            ItemsTableManager.Delete (this);   
-        }        
+            Provider.Save (this);
+            if (enclosure != null)
+                enclosure.Save ();
+        }
       
         public void Delete ()
         {
@@ -315,26 +256,27 @@
                 
                 if (delEncFile) {
                     if (enclosure != null && delEncFile) {
-                        enclosure.RemoveFile ();                	
+                        enclosure.RemoveFile ();
                     }                
                 }                   
                 
                 Active = false;
                 
                 if (removeFromParent) {
-                    CommitImpl ();    
+                    // TODO should this be Provider.Delete ?
+                    //CommitImpl ();    
                 }                
             }
 
             if (removeFromParent) {
-                parent.Remove (this);       
+                feed.Remove (this);       
             }            
         }
         
         internal void CancelDownload (FeedEnclosure enc)
         {
-            if (parent != null) {
-                parent.CancelDownload (enc);
+            if (feed != null) {
+                feed.CancelDownload (enc);
             }
         }
         
@@ -342,8 +284,8 @@
         {
             bool queued = false;
         
-            if (parent != null) {
-                queued = parent.QueueDownload (enc) != null;	
+            if (feed != null) {
+                queued = feed.QueueDownload (enc) != null;	
             }
         
             return queued;
@@ -351,8 +293,8 @@
 
         internal void StopDownload (FeedEnclosure enc)
         {
-            if (parent != null) {
-                parent.StopDownload (enc);
+            if (feed != null) {
+                feed.StopDownload (enc);
             }
         }
     }

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedUpdateTask.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedUpdateTask.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedUpdateTask.cs	Mon Apr 28 21:42:18 2008
@@ -41,13 +41,11 @@
 	    private bool disposed;	 
 	    private ManualResetEvent mre;
 
-        public Feed Feed 
-        {
+        public Feed Feed {
             get { return feed; }
         }
 
-	    public override WaitHandle WaitHandle 
-	    {
+	    public override WaitHandle WaitHandle {
 	        get {
 	            lock (SyncRoot) {
 	                if (mre == null) {

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedsManager.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedsManager.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedsManager.cs	Mon Apr 28 21:42:18 2008
@@ -42,41 +42,41 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 
-using Migo.DownloadCore;
+using Hyena;
+using Hyena.Data.Sqlite;
 
+using Migo.DownloadCore;
 using Migo.TaskCore;
 using Migo.TaskCore.Collections;
-
 using Migo.Syndication.Data;
 
 namespace Migo.Syndication
 {
-    public class FeedsManager : IFeedsManager, IDisposable
+    public class FeedsManager : IDisposable
     {        
         private bool disposed;        
         
-        private bool ticDirty;
+        private bool ticDirty = true;
         private long totalItemCount;
         
-        private bool tuicDirty;
+        private bool tuicDirty = true;
         private long totalUnreadItemCount;
         
         private List<Feed> feeds;
-        private List<Feed> queuedFeeds;
+        private List<Feed> queued_feeds;
 
-        private IDbConnection conn;
-        private AsyncCommandQueue<ICommand> commandQueue;
+        private AsyncCommandQueue<ICommand> command_queue;
         
-        private Dictionary<long,Feed> idFeedDict;
-        private Dictionary<string,Feed> urlFeedDict;
+        private Dictionary<long, Feed> id_feed_map;
+        private Dictionary<string, Feed> url_feed_map;
         
-        private Dictionary<FeedEnclosure,HttpFileDownloadTask> queuedDownloads;
+        private Dictionary<FeedEnclosure, HttpFileDownloadTask> queued_downloads;
         
-        private ManualResetEvent downloadHandle;
-        private DownloadManager downloadManager;
+        private ManualResetEvent download_handle;
+        private DownloadManager download_manager;
         
-        private TaskList<FeedUpdateTask> updateList;
-        private TaskGroup<FeedUpdateTask> updateGroup;
+        private TaskList<FeedUpdateTask> update_list;
+        private TaskGroup<FeedUpdateTask> update_group;
         
         private readonly object sync = new object (); 
         
@@ -92,10 +92,17 @@
         public event EventHandler<FeedEventArgs> FeedUrlChanged;        
         
         public event EventHandler<FeedItemEventArgs> FeedItemAdded;
-        public event EventHandler<FeedItemEventArgs> FeedItemRemoved;           
+        public event EventHandler<FeedItemEventArgs> FeedItemRemoved;
         
-        public FeedBackgroundSyncStatus BackgroundSyncStatus 
-        {
+        internal static FeedsManager Instance;
+        
+        internal AsyncCommandQueue<ICommand> CommandQueue {
+            get { return command_queue; }
+        }
+        
+#region Public Properties
+
+        public FeedBackgroundSyncStatus BackgroundSyncStatus {
             get {
                 lock (sync) {
                     return FeedBackgroundSyncStatus.Disabled;
@@ -103,44 +110,36 @@
             }
         }        
         
-        public long DefaultInterval 
-        {
+        // TODO interval for what, and in what unit?
+        public long DefaultInterval {
             get { lock (sync) { return 15; } }
             set { throw new NotImplementedException ("DefaultInterval"); }
         }
 
-        public DownloadManager DownloadManager
-        {
-            get { return downloadManager; }
+        public DownloadManager DownloadManager {
+            get { return download_manager; }
         }
         
-        public ReadOnlyCollection<IFeed> Feeds 
-        {             
+        private ReadOnlyCollection<Feed> ro_feeds;
+        public ReadOnlyCollection<Feed> Feeds {             
             get { 
                 lock (sync) {
-                    // My god, would you look at that abortion.  No wonder 
-                    // they wrapped LINQ around it.
-                    // UPDATE to use LINQ ASAP.
-                    return feeds.ConvertAll (
-                        new Converter<Feed,IFeed> (delegate (Feed f) { return f as IFeed; })
-                    ).AsReadOnly ();
+                    return ro_feeds ?? ro_feeds = new ReadOnlyCollection<Feed> (feeds);
                 }
-            } 
+            }
         }
 
-        public long ItemCountLimit 
-        {
+        public long ItemCountLimit {
             get { lock (sync) { return -1; } }
         }        
         
-        public long TotalItemCount
-        { 
+        public long TotalItemCount { 
             get {
                 lock (sync) {
                     if (ticDirty) {
                     	totalItemCount = 0;
                         
-                        foreach (IFeed f in feeds) {
+                        foreach (Feed f in feeds) {
                             totalItemCount += f.ItemCount;
                     	}
                         
@@ -152,14 +151,13 @@
             }
         }
                 
-        public long TotalUnreadItemCount 
-        { 
+        public long TotalUnreadItemCount {
             get {        
                 lock (sync) {
                     if (tuicDirty) {
                     	totalUnreadItemCount = 0;
                         
-                        foreach (IFeed f in feeds) {
+                        foreach (Feed f in feeds) {
                             totalUnreadItemCount += f.UnreadItemCount;
                     	}
                         
@@ -171,110 +169,179 @@
             }
         }
         
-        internal AsyncCommandQueue<ICommand> CommandQueue {
-            get { return commandQueue; }
-        }
+#endregion
+
+#region Constructor
         
-        public FeedsManager (string dbPath, DownloadManager manager)
+        public FeedsManager (HyenaSqliteConnection connection, DownloadManager manager)
         {
-            if (String.IsNullOrEmpty (dbPath)) {
-                throw new ArgumentException ("dbPath is null or empty.");
+            if (connection == null) {
+                throw new ArgumentException ("connection is null");
             } else if (manager == null) {
                 throw new ArgumentNullException ("manager");
             }
-                        
-            try {
-                conn = SQLiteUtility.GetNewConnection (dbPath);
-                conn.Open ();
-                
-                DatabaseManager.Init (conn);
-                
-                EnclosuresTableManager.Init ();
-                ItemsTableManager.Init ();
-                FeedsTableManager.Init ();                
+            
+            // Hack to work around Feeds being needy and having to call all our internal methods, instead
+            // of us just listening for their events.
+            Instance = this;
+            
+            download_manager = manager;
 
-                feeds = new List<Feed> ();
-                queuedFeeds = new List<Feed> ();
-                
-                idFeedDict = new Dictionary<long,Feed> ();
-                urlFeedDict = new Dictionary<string,Feed> ();
-                
-                ticDirty = tuicDirty = true;  
+            FeedEnclosure.Provider = new SqliteModelProvider<FeedEnclosure> (connection, "PodcastEnclosures");
+            FeedItem.Provider = new SqliteModelProvider<FeedItem> (connection, "PodcastItems");
+            Migo.Syndication.Feed.Provider = new SqliteModelProvider<Migo.Syndication.Feed> (connection, "PodcastSyndications");
+            
+            feeds = new List<Feed> ();
+            queued_feeds = new List<Feed> ();
+            id_feed_map = new Dictionary<long, Feed> ();
+            url_feed_map = new Dictionary<string, Feed> ();
 
-                downloadHandle = new ManualResetEvent (true);
-                
-                downloadManager = manager;
+            download_handle = new ManualResetEvent (true);
 
-                downloadManager.Tasks.TaskAdded += OnDownloadTaskAdded;
-                downloadManager.Tasks.TaskRemoved += OnDownloadTaskRemoved;
-                
-                downloadManager.Group.TaskStatusChanged += OnDownloadTaskStatusChangedHandler;
+            download_manager.Tasks.TaskAdded += OnDownloadTaskAdded;
+            download_manager.Tasks.TaskRemoved += OnDownloadTaskRemoved;            
+            download_manager.Group.TaskStatusChanged += OnDownloadTaskStatusChangedHandler;
 
-                queuedDownloads = new Dictionary<FeedEnclosure,HttpFileDownloadTask> ();
-                
-                updateList = new TaskList<FeedUpdateTask> ();
-                updateGroup = new TaskGroup<FeedUpdateTask> (4, updateList);
-                
-                updateGroup.TaskStopped += TaskStoppedHandler;
-                updateGroup.TaskAssociated += TaskAssociatedHandler;
-                
-                foreach (Feed f in FeedsTableManager.GetAllFeeds (this)) {
-                    Associate (f);
-                }
-                
-                commandQueue = new AsyncCommandQueue<ICommand> ();
-            } catch (Exception e) {
-                Console.WriteLine (e.Message);
-                Console.WriteLine (e.StackTrace);
-                throw new ApplicationException ("Unable to initialize FeedsManager");   
-            } 
-            Console.WriteLine ("FM - CON - END");
+            queued_downloads = new Dictionary<FeedEnclosure, HttpFileDownloadTask> ();
+            update_list = new TaskList<FeedUpdateTask> ();
+            update_group = new TaskGroup<FeedUpdateTask> (4, update_list);
+            update_group.TaskStopped += TaskStoppedHandler;
+            update_group.TaskAssociated += TaskAssociatedHandler;
+            
+            /*foreach (Feed feed in Feed.Provider.FetchAll ()) {
+                Console.WriteLine ("Adding feed {0}", feed.Url);
+                AddFeed (feed);
+            }*/
+            
+            command_queue = new AsyncCommandQueue<ICommand> ();
         }
         
-        public void AsyncSyncAll ()
+#endregion
+
+#region Public Methods
+
+        public Feed CreateFeed (string url)
         {
-            List<Feed> allFeeds = null;
-            
-            lock (sync) {
-                if (feeds.Count > 0) {
-                    allFeeds = new List<Feed> (this.feeds);
-                }
-            }
+            Feed feed = null;
+            url = url.Trim ().TrimEnd ('/');
 
-            if (allFeeds != null) {
-                foreach (IFeed f in allFeeds) {
-                    f.AsyncDownload ();
+            lock (sync) {   
+                if (!url_feed_map.ContainsKey (url)) {
+                    feed = new Feed (url);
+                    feed.Save ();
+                    AddFeed (feed);
+                    OnFeedAdded (feed);
                 }
             }
+            
+            return feed;
         }
         
-        public void BackgroundSync (FeedBackgroundSyncAction action)
+        public HttpFileDownloadTask QueueDownload (FeedEnclosure enclosure) 
         {
-            throw new NotImplementedException ("BackgroundSync");
+            return QueueDownload (enclosure, true);         
         }
-                
-        public IFeed CreateFeed (string url)
+           
+        public HttpFileDownloadTask QueueDownload (FeedEnclosure enclosure, bool queue)
         {
-            Feed feed = null;
-            string url_ = url.Trim ().TrimEnd ('/');
+            if (enclosure == null) {
+                throw new ArgumentNullException ("enc");
+            }
+            
+            HttpFileDownloadTask task = null;       
+            
+            lock (sync) {
+                if (disposed) {
+                    return null;
+                }
+                
+                if (!queued_downloads.ContainsKey (enclosure)) {                    
+                    Feed parentFeed = enclosure.Item.Feed;                    
+                    
+                    if (parentFeed != null && !IsFeedOurs (parentFeed)) {                        
+                        task = download_manager.CreateDownloadTask (enclosure.Url, enclosure);
+                        //Console.WriteLine ("Task DL path:  {0}", task.LocalPath);
+                        task.Name = String.Format ("{0} - {1}", parentFeed.Title, enclosure.Item.Title);
+                        
+                        task.Completed += OnDownloadTaskCompletedHandler;                    
+                        
+                        // Race condition...
+                        // Should only be added when the task is associated or 
+                        // it can be canceled before it is added to the progress manager.
+                        
+                        // Add a pre-association dict and move tasks to the 
+                        // queued dict once they've been offically added.
+                        
+                        queued_downloads.Add (enclosure, task);
+                    }                    
+                }
 
+                if (task != null && queue) {
+                    download_manager.QueueDownload (task);                                                                    	
+                }      
+            }
+                       
+            return task;        
+        }
+        
+        public IEnumerable<HttpFileDownloadTask> QueueDownloads (IEnumerable<FeedEnclosure> encs)
+        {
+            if (encs == null) {
+                throw new ArgumentNullException ("encs");
+            }
+            
+            ICollection<HttpFileDownloadTask> encsCol = encs as ICollection<HttpFileDownloadTask>;
+            
+            List<HttpFileDownloadTask> tasks = (encsCol == null) ?
+                new List<HttpFileDownloadTask> () : 
+                new List<HttpFileDownloadTask> (encsCol.Count);
+            
+            HttpFileDownloadTask tmpTask = null;
+            
             lock (sync) {   
-                if (!urlFeedDict.ContainsKey (url_)) {
-                    feed = new Feed (this, url_);
-                    feed.Commit ();
-                    Associate (feed);
-                    OnFeedAdded (feed);
+                if (disposed) {
+                    return tasks;
+                }
+                
+                foreach (FeedEnclosure enc in encs) {
+                    if (enc.SetDownloading ()) {
+                        tmpTask = QueueDownload (enc, false);
+                        
+                        if (tmpTask == null) {
+                            enc.ResetDownloading ();
+                            continue;
+                        }
+                        
+                        tasks.Add (tmpTask);
+                    }
+                }
+                
+                if (tasks.Count > 0) {
+                    download_manager.QueueDownload (tasks);
                 }
             }
             
-            return feed;
+            return tasks;
         }
-        
-        public IFeed CreateFeed (string feedName, string feedUrl)
+
+        // TODO remove these? not used
+        /*public void AsyncSyncAll ()
         {
-            return null;   
-        }
+            List<Feed> allFeeds = null;
+            
+            lock (sync) {
+                if (feeds.Count > 0) {
+                    allFeeds = new List<Feed> (feeds);
+                }
+            }
 
+            if (allFeeds != null) {
+                foreach (Feed f in allFeeds) {
+                    f.AsyncDownload ();
+                }
+            }
+        }
+        
         public void DeleteFeed (long feedID)
         {
             Feed feed = null;
@@ -288,16 +355,16 @@
             }                
         }   
           
-        public void DeleteFeed (IFeed feed)
+        public void DeleteFeed (Feed feed)
         {
             if (feed == null) {
                 throw new ArgumentNullException ("feed");      	
-            } else if (!IsCuckoosEgg (feed)) {
+            } else if (!IsFeedOurs (feed)) {
                 feed.Delete ();
             }
         }
-/*        
-        public void DequeueDownloads (IEnumerable<IFeedEnclosure> enclosures) 
+      
+        public void DequeueDownloads (IEnumerable<FeedEnclosure> enclosures) 
         {
             if (enclosures == null) {
                 throw new ArgumentNullException ("enclosures");
@@ -308,92 +375,7 @@
                 
             downloadManager.RemoveDownload (tasks);
         }
-*/
-        public void Dispose () 
-        {
-            if (SetDisposed ()) {               
-                AutoResetEvent disposeHandle = new AutoResetEvent (false);
-                Console.WriteLine ("FM - Dispose - 000");
-    
-                List<HttpFileDownloadTask> tasks = null;
-    
-                lock (sync) {
-                    if (queuedDownloads.Count > 0) {
-                        tasks = new List<HttpFileDownloadTask> (queuedDownloads.Values);
-                    }
-                }
-
-                if (tasks != null) {
-                    foreach (HttpFileDownloadTask t in tasks) {
-                        t.Stop ();
-                    }
-                    
-                    Console.WriteLine ("downloadHandle - WaitOne ()");
-                    downloadHandle.WaitOne ();
-                }
-
-                if (updateGroup != null) {
-                    updateGroup.CancelAsync ();                
-                    
-                    Console.WriteLine ("FM - Dispose - 000.5");
-                    
-                    updateGroup.Handle.WaitOne ();
-                    
-                    Console.WriteLine ("FM - Dispose - 001");
-                    
-                    updateGroup.Dispose (disposeHandle);
-                    
-                    Console.WriteLine ("FM - Dispose - 002");
-                    
-                    disposeHandle.WaitOne ();
-                    
-                    updateGroup.TaskStopped -= TaskStoppedHandler;
-                    updateGroup.TaskAssociated -= TaskAssociatedHandler;
-                    
-                    updateGroup = null;
-                    
-                    Console.WriteLine ("FM - Dispose - 003");
-                }
-               
-                updateList = null;
-                
-                Console.WriteLine ("FM - Dispose - 008");    
-                                 
-                if (downloadHandle != null) {
-                    downloadHandle.Close ();
-                    downloadHandle = null;
-                }                
-                
-                Console.WriteLine ("FM - Dispose - 007");                    
-                
-                if (downloadManager != null) {
-                    downloadManager.Tasks.TaskAdded -= OnDownloadTaskAdded;
-                    downloadManager.Tasks.TaskRemoved -= OnDownloadTaskRemoved; 
-                    downloadManager = null;
-                }                          
-
-                Console.WriteLine ("FM - Dispose - 004");                  
-
-                if (commandQueue != null) {
-                    commandQueue.Dispose ();
-                    commandQueue = null;
-                }
-                
-                Console.WriteLine ("FM - Dispose - 005");
-                
-                DatabaseManager.Dispose ();
-                
-                if (conn != null) {
-                    conn.Close ();
-                    conn = null;
-                }              
-                
-                Console.WriteLine ("FM - Dispose - 006");                    
-                
-                disposeHandle.Close ();
-            }
-        }
-
+        
         public bool ExistsFeed (string url)
         {
             lock (sync) {
@@ -408,7 +390,7 @@
             }
         }
         
-        public IFeed GetFeed (long feedID)
+        public Feed GetFeed (long feedID)
         {
             Feed ret = null;
             
@@ -419,7 +401,7 @@
             return ret;
         }
             
-        public IFeed GetFeedByUrl (string url)
+        public Feed GetFeedByUrl (string url)
         {
             Feed ret = null;
             
@@ -435,255 +417,140 @@
             lock (sync) {
                 return urlFeedDict.ContainsKey (url); 
             }
-        }
+        }*/
 
-        private void Associate (Feed feed)
-        {
-            if (feed != null && !idFeedDict.ContainsKey (feed.LocalID)) {
-                idFeedDict.Add (feed.LocalID, feed);
-                urlFeedDict.Add (feed.Url, feed);
-                feeds.Add (feed);                
-            }                 
-        }
-
-        private void Disassociate (Feed feed)
-        {
-            if (feed != null &&
-                feeds.Remove (feed)) {				
-                urlFeedDict.Remove (feed.Url);            
-                idFeedDict.Remove (feed.LocalID);                
-            }
-        }           
-        
-        private bool IsCuckoosEgg (IFeed feed)
-        {
-            bool ret = true;
-            Feed f = feed as Feed;
-            
-            if (f != null && f.Parent == this) {
-                ret = false;
-            }
-            
-            return ret;
-        }
-        
-        internal void CancelDownload (IFeedEnclosure enc)
-        {
-            lock (sync) {
-                HttpFileDownloadTask task = FindDownloadTask (enc);            
-                        
-                if (task != null) {
-                    // Look into multi-cancel later      
-                    task.CancelAsync ();
-                }            
-            }
-        }
-        
-        internal void StopDownload (IFeedEnclosure enc)
-        {   
-            lock (sync) {
-                HttpFileDownloadTask task = FindDownloadTask (enc);            
-                        
-                if (task != null) {
-                    task.Stop ();
-                }   
-            }
-        }        
-        
-        private HttpFileDownloadTask FindDownloadTask (IFeedEnclosure enc)
-        {
-            if (enc == null) {
-                throw new ArgumentNullException ("enc");
-            }
-            
-            return FindDownloadTaskImpl ((FeedEnclosure)enc);
-        }
-        
-        private HttpFileDownloadTask FindDownloadTaskImpl (FeedEnclosure enc) 
+        public void Dispose () 
         {
-            HttpFileDownloadTask task = null;
-            Feed parentFeed = enc.Parent.Parent as Feed;                               
-            
-            if (parentFeed != null && 
-                !IsCuckoosEgg (parentFeed) && 
-                queuedDownloads.ContainsKey (enc)) {
-                task = queuedDownloads[enc];
-            }
-            
-            return task;
-        }        
-/*        
-        private IEnumerable<HttpFileDownloadTask> FindDownloadTasks (IEnumerable<IFeedEnclosure> enclosures)
-        {            
-            ICollection<HttpFileDownloadTask> encsCol = 
-                enclosures as ICollection<HttpFileDownloadTask>;
-            
-            List<HttpFileDownloadTask> ret = (encsCol == null) ?
-                new List<HttpFileDownloadTask> () : 
-                new List<HttpFileDownloadTask> (encsCol.Count);
-            
-            HttpFileDownloadTask tmpTask = null;
-            
-            lock (sync) {
-                foreach (IFeedEnclosure enc in enclosures) {
-                    tmpTask = FindDownloadTaskImpl ((FeedEnclosure)enc);
-                    
-                    if (tmpTask != null) {
-                        ret.Add (tmpTask);
+            if (SetDisposed ()) {               
+                AutoResetEvent disposeHandle = new AutoResetEvent (false);
+                Console.WriteLine ("FM - Dispose - 000");
+    
+                List<HttpFileDownloadTask> tasks = null;
+    
+                lock (sync) {
+                    if (queued_downloads.Count > 0) {
+                        tasks = new List<HttpFileDownloadTask> (queued_downloads.Values);
                     }
                 }
-            }
-            
-            return ret;
-        }
-*/
-        public HttpFileDownloadTask QueueDownload (IFeedEnclosure enc) 
-        {
-            return QueueDownload (enc, true);         
-        }
-           
-        public HttpFileDownloadTask QueueDownload (IFeedEnclosure enc, bool queue)
-        {
-            if (enc == null) {
-                throw new ArgumentNullException ("enc");
-            }
-         
-            FeedEnclosure fenc = enc as FeedEnclosure;
-            
-            if (fenc == null) {
-                throw new ArgumentException ("Must be derived from FeedEnclosure", "enc");
-            }
-            
-            HttpFileDownloadTask task = null;       
-            
-            lock (sync) {
-                if (disposed) {
-                    return null;
-                }
-                
-                if (!queuedDownloads.ContainsKey (fenc)) {                    
-                    Feed parentFeed = enc.Parent.Parent as Feed;                    
+
+                if (tasks != null) {
+                    foreach (HttpFileDownloadTask t in tasks) {
+                        t.Stop ();
+                    }
                     
-                    if (parentFeed != null && !IsCuckoosEgg (parentFeed)) {                        
-                        task = downloadManager.CreateDownloadTask (fenc.Url, fenc);
-                        //Console.WriteLine ("Task DL path:  {0}", task.LocalPath);
-                        task.Name = String.Format (
-                            "{0} - {1}", parentFeed.Title, fenc.Parent.Title
-                        );
-                        
-                        task.Completed += OnDownloadTaskCompletedHandler;                    
-                        
-                        // Race condition...
-                        // Should only be added when the task is associated or 
-                        // it can be canceled before it is added to the progress manager.
-                        
-                        // Add a pre-association dict and move tasks to the 
-                        // queued dict once they've been offically added.
-                        
-                        queuedDownloads.Add (fenc, task);
-                    }                    
+                    Console.WriteLine ("downloadHandle - WaitOne ()");
+                    download_handle.WaitOne ();
                 }
 
-                if (task != null && queue) {
-                    downloadManager.QueueDownload (task);                                                                    	
-                }      
-            }
-                       
-            return task;        
-        }
-        
-        public IEnumerable<HttpFileDownloadTask> QueueDownloads (IEnumerable<IFeedEnclosure> encs)
-        {
-            if (encs == null) {
-                throw new ArgumentNullException ("encs");
-            }
-            
-            ICollection<HttpFileDownloadTask> encsCol = encs as ICollection<HttpFileDownloadTask>;
-            
-            List<HttpFileDownloadTask> tasks = (encsCol == null) ?
-                new List<HttpFileDownloadTask> () : 
-                new List<HttpFileDownloadTask> (encsCol.Count);
-            
-            HttpFileDownloadTask tmpTask = null;
-            
-            lock (sync) {   
-                if (disposed) {
-                    return tasks;
+                if (update_group != null) {
+                    update_group.CancelAsync ();                
+                    
+                    Console.WriteLine ("FM - Dispose - 000.5");
+                    
+                    update_group.Handle.WaitOne ();
+                    
+                    Console.WriteLine ("FM - Dispose - 001");
+                    
+                    update_group.Dispose (disposeHandle);
+                    
+                    Console.WriteLine ("FM - Dispose - 002");
+                    
+                    disposeHandle.WaitOne ();
+                    
+                    update_group.TaskStopped -= TaskStoppedHandler;
+                    update_group.TaskAssociated -= TaskAssociatedHandler;
+                    
+                    update_group = null;
+                    
+                    Console.WriteLine ("FM - Dispose - 003");
                 }
+               
+                update_list = null;
                 
-                foreach (FeedEnclosure enc in encs) {
-                    if (enc.SetDownloading ()) {
-                        tmpTask = QueueDownload (enc, false);
-                        
-                        if (tmpTask == null) {
-                            enc.ResetDownloading ();
-                            continue;
-                        }
-                        
-                        tasks.Add (tmpTask);
-                    }
-                }
+                Console.WriteLine ("FM - Dispose - 008");    
+                                 
+                if (download_handle != null) {
+                    download_handle.Close ();
+                    download_handle = null;
+                }                
                 
-                if (tasks.Count > 0) {
-                    downloadManager.QueueDownload (tasks);
+                Console.WriteLine ("FM - Dispose - 007");                    
+                
+                if (download_manager != null) {
+                    download_manager.Tasks.TaskAdded -= OnDownloadTaskAdded;
+                    download_manager.Tasks.TaskRemoved -= OnDownloadTaskRemoved; 
+                    download_manager = null;
+                }                          
+
+                Console.WriteLine ("FM - Dispose - 004");                  
+
+                if (command_queue != null) {
+                    command_queue.Dispose ();
+                    command_queue = null;
                 }
+                
+                disposeHandle.Close ();
             }
-            
-            return tasks;
         }
+
+#endregion
+
+#region Private Methods
+
+        private void AddFeed (Feed feed)
+        {
+            if (feed != null && !id_feed_map.ContainsKey (feed.DbId)) {
+                id_feed_map[feed.DbId] = feed;
+                url_feed_map[feed.Url] = feed;
+                feeds.Add (feed);
+            }                 
+        }
+
+        private void RemoveFeed (Feed feed)
+        {
+            if (feed != null && feeds.Remove (feed)) {
+                url_feed_map.Remove (feed.Url);            
+                id_feed_map.Remove (feed.DbId);                
+            }
+        }           
         
-        internal void QueueUpdate (Feed feed)
+        private bool IsFeedOurs (Feed feed)
         {
-            if (feed == null) {
-                throw new ArgumentNullException ("feed");
+            bool ret = true;
+            Feed f = feed as Feed;
+            
+            if (f != null && f.Parent == this) {
+                ret = false;
             }
+            
+            return ret;
+        }
 
-            lock (sync) {
-                if (disposed) {
-                    return;
-                }
-                
-                if (!queuedFeeds.Contains (feed)) {
-                    queuedFeeds.Add (feed);
-                    lock (updateList.SyncRoot) { 
-                        updateList.Add (new FeedUpdateTask (feed));
-                    }
-                }            
-            }             
+       
+        private HttpFileDownloadTask FindDownloadTask (FeedEnclosure enc)
+        {
+            if (enc == null) {
+                throw new ArgumentNullException ("enc");
+            }
+            
+            return FindDownloadTaskImpl ((FeedEnclosure)enc);
         }
         
-        internal void QueueUpdate (ICollection<Feed> feeds)
+        private HttpFileDownloadTask FindDownloadTaskImpl (FeedEnclosure enc) 
         {
-            if (feeds == null) {
-                throw new ArgumentNullException ("feeds");
-            }
+            HttpFileDownloadTask task = null;
+            Feed parentFeed = enc.Item.Feed as Feed;                               
             
-            lock (sync) {      
-                if (disposed) {
-                    return;
-                }
-                
-                List<FeedUpdateTask> tasks = null;
-                
-                if (feeds.Count > 0) {
-                    tasks = new List<FeedUpdateTask> (feeds.Count);
-                        
-                    foreach (Feed f in feeds) {
-                        if (!queuedFeeds.Contains (f)) {
-                            queuedFeeds.Add (f);
-                            tasks.Add (new FeedUpdateTask (f));
-                        }
-                    }
-                }
-                
-                if (tasks != null && tasks.Count > 0) {
-                    lock (updateList.SyncRoot) {
-                        updateList.AddRange (tasks);                  
-                    }   
-                }
+            if (parentFeed != null && 
+                !IsFeedOurs (parentFeed) && 
+                queued_downloads.ContainsKey (enc)) {
+                task = queued_downloads[enc];
             }
+            
+            return task;
         }        
-        
+
+
         private bool SetDisposed ()
         {
             bool ret = false;
@@ -704,12 +571,12 @@
                     
             if (enc != null) {
                 lock (sync) { 
-                    parentFeed = enc.Parent.Parent as Feed;                  
+                    parentFeed = enc.Item.Feed;                  
                     
-                    if (parentFeed != null && !IsCuckoosEgg (parentFeed) &&
-                        queuedDownloads.ContainsKey (enc)) {
-                        if (queuedDownloads.Count == 0) {
-                            downloadHandle.Reset ();
+                    if (parentFeed != null && !IsFeedOurs (parentFeed) &&
+                        queued_downloads.ContainsKey (enc)) {
+                        if (queued_downloads.Count == 0) {
+                            download_handle.Reset ();
                         }                        
                                                     
                         enc.DownloadStatus = FeedDownloadStatus.Pending;                        
@@ -763,17 +630,17 @@
                                           HttpFileDownloadTask task,
                                           bool decQueuedCount)
         {
-            if (queuedDownloads.ContainsKey (enc)) {
-                queuedDownloads.Remove (enc);    
+            if (queued_downloads.ContainsKey (enc)) {
+                queued_downloads.Remove (enc);    
                 task.Completed -= OnDownloadTaskCompletedHandler;                                            
                 
                 if (decQueuedCount) {
-                    ((Feed)enc.Parent.Parent).DecrementQueuedDownloadCount ();
+                    enc.Item.Feed.DecrementQueuedDownloadCount ();
                 }
                 
-                if (queuedDownloads.Count == 0) {
-                	if (downloadHandle != null) {
-                	    downloadHandle.Set ();                	    
+                if (queued_downloads.Count == 0) {
+                	if (download_handle != null) {
+                	    download_handle.Set ();
                 	}
                 }
             }
@@ -803,7 +670,7 @@
                         tmpEnclosure = t.UserState as FeedEnclosure;
                         
                         if (tmpEnclosure != null) {
-                            tmpParent = ((Feed)tmpEnclosure.Parent.Parent);
+                            tmpParent = tmpEnclosure.Item.Feed;
                             
                             if (!feedDict.TryGetValue (tmpParent, out tmpList)) {
                                 tmpList = new List<FeedEnclosure> ();
@@ -853,13 +720,13 @@
                 break;
             case TaskStatus.Running:
                 enc.DownloadStatus = FeedDownloadStatus.Downloading;
-                ((Feed)enc.Parent.Parent).IncrementActiveDownloadCount ();                    
+                enc.Item.Feed.IncrementActiveDownloadCount ();                    
                 break;  
             case TaskStatus.Stopped: goto case TaskStatus.Cancelled;
             }
 
             if (statusInfo.OldStatus == TaskStatus.Running) {
-                ((Feed)enc.Parent.Parent).DecrementActiveDownloadCount ();                    
+                enc.Item.Feed.DecrementActiveDownloadCount ();                    
             }
         }
 
@@ -882,8 +749,8 @@
         private void TaskAssociatedHandler (object sender, 
                                             TaskEventArgs<FeedUpdateTask> e)
         {   
-            lock (updateGroup.SyncRoot) {
-                updateGroup.Execute ();
+            lock (update_group.SyncRoot) {
+                update_group.Execute ();
             }
         }        
         
@@ -892,18 +759,170 @@
         {
             lock (sync) {
                 FeedUpdateTask fut = e.Task as FeedUpdateTask;
-                queuedFeeds.Remove (fut.Feed);
+                queued_feeds.Remove (fut.Feed);
+                
+                lock (update_list.SyncRoot) {
+                    update_list.Remove (e.Task);
+                }
+            }
+        }
+        
+        private void OnFeedItemEvent (EventHandler<FeedItemEventArgs> handler, 
+                                      FeedItemEventArgs e)
+        {
+            if (handler == null) {
+                return;
+            } else if (e == null) {
+                throw new ArgumentNullException ("e");
+            }
+            
+            command_queue.Register (
+                new EventWrapper<FeedItemEventArgs> (handler, this, e)
+            );            
+            
+            //handler (this, e);           
+        }        
+        
+        private void OnFeedEventRaised (Feed feed, EventHandler<FeedEventArgs> handler)
+        {
+            if (feed == null) {
+                throw new ArgumentNullException ("feed");	
+            }
+            
+            EventHandler<FeedEventArgs> handlerCpy = handler;
+            
+            if (handlerCpy != null) {
+                command_queue.Register (
+                    new EventWrapper<FeedEventArgs> (
+                        handler, this, new FeedEventArgs (feed)
+                    )
+                );              	
+            	//handler (this, new FeedEventArgs (feed));
+            }
+        }  
+        
+        private void OnEnclosureDownloadCompleted (HttpFileDownloadTask task)
+        {
+            EventHandler<TaskEventArgs<HttpFileDownloadTask>> handler = EnclosureDownloadCompleted;
+        
+            if (handler != null) {
+                AsyncCommandQueue<ICommand> cmdQCpy = command_queue;
                 
-                lock (updateList.SyncRoot) {
-                    updateList.Remove (e.Task);
+                if (cmdQCpy != null) {
+                    cmdQCpy.Register (new EventWrapper<TaskEventArgs<HttpFileDownloadTask>> (
+                	    handler, this, new TaskEventArgs<HttpFileDownloadTask> (task))
+                	);
+                }        
+            }                         
+        }  
+
+        /*private IEnumerable<HttpFileDownloadTask> FindDownloadTasks (IEnumerable<FeedEnclosure> enclosures)
+        {            
+            ICollection<HttpFileDownloadTask> encsCol = 
+                enclosures as ICollection<HttpFileDownloadTask>;
+            
+            List<HttpFileDownloadTask> ret = (encsCol == null) ?
+                new List<HttpFileDownloadTask> () : 
+                new List<HttpFileDownloadTask> (encsCol.Count);
+            
+            HttpFileDownloadTask tmpTask = null;
+            
+            lock (sync) {
+                foreach (FeedEnclosure enc in enclosures) {
+                    tmpTask = FindDownloadTaskImpl ((FeedEnclosure)enc);
+                    
+                    if (tmpTask != null) {
+                        ret.Add (tmpTask);
+                    }
                 }
             }
+            
+            return ret;
+        }*/
+
+#endregion
+
+#region Internal Methods
+        
+        internal void CancelDownload (FeedEnclosure enc)
+        {
+            lock (sync) {
+                HttpFileDownloadTask task = FindDownloadTask (enc);            
+                        
+                if (task != null) {
+                    // Look into multi-cancel later      
+                    task.CancelAsync ();
+                }            
+            }
+        }
+        
+        internal void StopDownload (FeedEnclosure enc)
+        {   
+            lock (sync) {
+                HttpFileDownloadTask task = FindDownloadTask (enc);            
+                        
+                if (task != null) {
+                    task.Stop ();
+                }   
+            }
+        }     
+        
+        internal void QueueUpdate (Feed feed)
+        {
+            if (feed == null) {
+                throw new ArgumentNullException ("feed");
+            }
+
+            lock (sync) {
+                if (disposed) {
+                    return;
+                }
+                
+                if (!queued_feeds.Contains (feed)) {
+                    queued_feeds.Add (feed);
+                    lock (update_list.SyncRoot) { 
+                        update_list.Add (new FeedUpdateTask (feed));
+                    }
+                }            
+            }             
         }
         
+        internal void QueueUpdate (ICollection<Feed> feeds)
+        {
+            if (feeds == null) {
+                throw new ArgumentNullException ("feeds");
+            }
+            
+            lock (sync) {      
+                if (disposed) {
+                    return;
+                }
+                
+                List<FeedUpdateTask> tasks = null;
+                
+                if (feeds.Count > 0) {
+                    tasks = new List<FeedUpdateTask> (feeds.Count);
+                        
+                    foreach (Feed f in feeds) {
+                        if (!queued_feeds.Contains (f)) {
+                            queued_feeds.Add (f);
+                            tasks.Add (new FeedUpdateTask (f));
+                        }
+                    }
+                }
+                
+                if (tasks != null && tasks.Count > 0) {
+                    lock (update_list.SyncRoot) {
+                        update_list.AddRange (tasks);                  
+                    }   
+                }
+            }
+        }        
+        
         // Should only be called by 'Feed'
         internal void RegisterCommand (ICommand command)
         {
-             AsyncCommandQueue<ICommand> cmdQCpy = commandQueue;
+             AsyncCommandQueue<ICommand> cmdQCpy = command_queue;
             
             if (cmdQCpy != null && command != null) {
             	cmdQCpy.Register (command);
@@ -912,7 +931,7 @@
         
         private void OnFeedAdded (Feed feed)
         {
-            AsyncCommandQueue<ICommand> cmdQCpy = commandQueue;
+            AsyncCommandQueue<ICommand> cmdQCpy = command_queue;
             
             if (cmdQCpy != null) {            
                 cmdQCpy.Register (new CommandWrapper (delegate {
@@ -925,7 +944,7 @@
         {      
             try {
                 lock (sync) {                        
-                    Disassociate (feed);
+                    RemoveFeed (feed);
                 }
             } finally {
                 OnFeedEventRaised (feed, FeedDeleted);                
@@ -941,7 +960,7 @@
             EventHandler<FeedDownloadCompletedEventArgs> handler = FeedDownloadCompleted;
                 
             if (handler != null) {
-                commandQueue.Register (
+                command_queue.Register (
                     new EventWrapper<FeedDownloadCompletedEventArgs> (
                         handler, this, 
                         new FeedDownloadCompletedEventArgs (feed, error)
@@ -955,7 +974,7 @@
             EventHandler<FeedDownloadCountChangedEventArgs> handler = FeedDownloadCountChanged;
                      
             if (handler != null) {             
-                commandQueue.Register (
+                command_queue.Register (
                     new EventWrapper<FeedDownloadCountChangedEventArgs> (
                         handler, this, 
                         new FeedDownloadCountChangedEventArgs (feed, flags)
@@ -969,7 +988,7 @@
             OnFeedEventRaised (feed, FeedDownloading);
         }
         
-        internal void OnFeedItemAdded (IFeed feed, IFeedItem item)
+        internal void OnFeedItemAdded (Feed feed, FeedItem item)
         {
             if (feed == null) {
                 throw new ArgumentNullException ("feed");
@@ -984,7 +1003,7 @@
             }                           
         }
         
-        internal void OnFeedItemsAdded (IFeed feed, IEnumerable<IFeedItem> items)
+        internal void OnFeedItemsAdded (Feed feed, IEnumerable<FeedItem> items)
         {
             if (feed == null) {
                 throw new ArgumentNullException ("feed");
@@ -999,7 +1018,7 @@
             }               
         }        
 
-        internal void OnFeedItemRemoved (IFeed feed, IFeedItem item)
+        internal void OnFeedItemRemoved (Feed feed, FeedItem item)
         {
             if (feed == null) {
                 throw new ArgumentNullException ("feed");
@@ -1013,7 +1032,7 @@
                 lock (sync) {
                     HttpFileDownloadTask task;                
                          
-                    if (queuedDownloads.TryGetValue ((FeedEnclosure)item.Enclosure, out task)) {
+                    if (queued_downloads.TryGetValue ((FeedEnclosure)item.Enclosure, out task)) {
                         task.CancelAsync ();
                     }
                 }
@@ -1024,7 +1043,7 @@
             }                 
         }
         
-        internal void OnFeedItemsRemoved (IFeed feed, IEnumerable<IFeedItem> items)
+        internal void OnFeedItemsRemoved (Feed feed, IEnumerable<FeedItem> items)
         {
             if (feed == null) {
                 throw new ArgumentNullException ("feed");
@@ -1039,7 +1058,7 @@
                 
                 foreach (FeedItem item in items) {                
                     if (item.Enclosure != null) {                    
-                        if (queuedDownloads.TryGetValue ((FeedEnclosure)item.Enclosure, out task)) {
+                        if (queued_downloads.TryGetValue ((FeedEnclosure)item.Enclosure, out task)) {
                             task.CancelAsync ();
                         }
                     }
@@ -1051,22 +1070,6 @@
             }               
         }              
         
-        private void OnFeedItemEvent (EventHandler<FeedItemEventArgs> handler, 
-                                      FeedItemEventArgs e)
-        {
-            if (handler == null) {
-                return;
-            } else if (e == null) {
-                throw new ArgumentNullException ("e");
-            }
-            
-            commandQueue.Register (
-                new EventWrapper<FeedItemEventArgs> (handler, this, e)
-            );            
-            
-            //handler (this, e);           
-        }        
-        
         internal void OnFeedItemCountChanged (Feed feed, FEEDS_EVENTS_ITEM_COUNT_FLAGS flags)
         {
             lock (sync) {
@@ -1085,7 +1088,7 @@
                 EventHandler<FeedItemCountChangedEventArgs> handler = FeedItemCountChanged;                
                 
                 if (handler != null) {
-                    commandQueue.Register (
+                    command_queue.Register (
                         new EventWrapper<FeedItemCountChangedEventArgs> (
                             handler, this, 
                             new FeedItemCountChangedEventArgs (feed, flags)
@@ -1103,8 +1106,8 @@
         internal void UpdateFeedUrl (string oldUrl, Feed feed)
         {
             lock (sync) {
-                urlFeedDict.Remove (oldUrl);
-                urlFeedDict.Add (feed.Url, feed);
+                url_feed_map.Remove (oldUrl);
+                url_feed_map.Add (feed.Url, feed);
             }        
         }
         
@@ -1112,38 +1115,7 @@
         {
             OnFeedEventRaised (feed, FeedUrlChanged);
         }
-
-        private void OnFeedEventRaised (Feed feed, EventHandler<FeedEventArgs> handler)
-        {
-            if (feed == null) {
-                throw new ArgumentNullException ("feed");	
-            }
-            
-            EventHandler<FeedEventArgs> handlerCpy = handler;
-            
-            if (handlerCpy != null) {
-                commandQueue.Register (
-                    new EventWrapper<FeedEventArgs> (
-                        handler, this, new FeedEventArgs (feed)
-                    )
-                );              	
-            	//handler (this, new FeedEventArgs (feed));
-            }
-        }  
-        
-        private void OnEnclosureDownloadCompleted (HttpFileDownloadTask task)
-        {
-            EventHandler<TaskEventArgs<HttpFileDownloadTask>> handler = EnclosureDownloadCompleted;
         
-            if (handler != null) {
-                AsyncCommandQueue<ICommand> cmdQCpy = commandQueue;
-                
-                if (cmdQCpy != null) {
-                    cmdQCpy.Register (new EventWrapper<TaskEventArgs<HttpFileDownloadTask>> (
-                	    handler, this, new TaskEventArgs<HttpFileDownloadTask> (task))
-                	);
-                }        
-            }                         
-        }        
+#endregion 
     }   
 }    

Added: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/RssParser.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/RssParser.cs	Mon Apr 28 21:42:18 2008
@@ -0,0 +1,172 @@
+//
+// RssParser.cs
+//
+// Authors:
+//   Mike Urbanski <michael c urbanski gmail com>
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2007 Mike Urbanski
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Xml;
+using System.Collections.Generic;
+
+using Migo.Syndication;
+
+namespace Migo.Syndication.Data
+{
+    public class RssParser
+    {
+        private XmlDocument doc;
+        
+        public RssParser (string url, string xml)
+        {
+            doc = new XmlDocument ();
+            try {
+                doc.LoadXml (xml);
+            } catch (XmlException) {
+                throw new FormatException ("Invalid xml document.");                                  
+            }
+            CheckRss ();
+        }
+        
+        public RssParser (string url, XmlDocument doc)
+        {
+            this.doc = doc;
+            CheckRss ();
+        }
+    
+        public Feed CreateFeed ()
+        {
+            return UpdateFeed (new Feed ());
+        }
+        
+        public Feed UpdateFeed (Feed feed)
+        {
+            try {
+                feed.Copyright        = XmlUtils.GetXmlNodeText (doc, "/rss/channel/copyright");
+                feed.Image            = XmlUtils.GetXmlNodeText (doc, "/rss/channel/image/url");
+                feed.Description      = XmlUtils.GetXmlNodeText (doc, "/rss/channel/description");
+                feed.Interval         = XmlUtils.GetInt64 (doc, "/rss/channel/interval"); 
+                feed.Language         = XmlUtils.GetXmlNodeText (doc, "/rss/channel/language");
+                feed.LastBuildDate    = XmlUtils.GetRfc822DateTime (doc, "/rss/channel/lastBuildDate");
+                feed.Link             = XmlUtils.GetXmlNodeText (doc, "/rss/channel/link"); 
+                feed.PubDate          = XmlUtils.GetRfc822DateTime (doc, "/rss/channel/pubDate");
+                feed.Title            = XmlUtils.GetXmlNodeText (doc, "/rss/channel/title");
+                feed.Ttl              = XmlUtils.GetInt64 (doc, "/rss/channel/ttl");
+                feed.LastWriteTime    = DateTime.MinValue;
+                feed.LastDownloadTime = DateTime.Now;
+
+                return feed;
+            } catch (Exception e) {
+                 Hyena.Log.Exception (e);
+            }
+             
+            return null;
+        }
+        
+        public IEnumerable<FeedItem> GetFeedItems ()
+        {
+            XmlNodeList nodes = null;
+            try {
+                nodes = doc.SelectNodes ("//item");
+            } catch (Exception e) {
+                Hyena.Log.Exception (e);
+            }
+            
+            if (nodes != null) {
+                foreach (XmlNode node in nodes) {
+                    FeedItem item = null;
+                    
+                    try {
+                        item = ParseItem (node);
+                    } catch (Exception e) {
+                        Hyena.Log.Exception (e);
+                    }
+                    
+                    if (item != null) {
+                        yield return item;
+                    }
+                }
+            }
+        }
+        
+        public static FeedItem ParseItem (XmlNode node)
+        {
+            try {
+                FeedItem item = new FeedItem ();
+                item.Description = XmlUtils.GetXmlNodeText (node, "description");                        
+                item.Title = XmlUtils.GetXmlNodeText (node, "title");                        
+            
+                if (String.IsNullOrEmpty (item.Description) && String.IsNullOrEmpty (item.Title)) {
+                    throw new FormatException ("node:  Either 'title' or 'description' node must exist.");
+                }
+                
+                item.Author            = XmlUtils.GetXmlNodeText (node, "author");
+                item.Comments          = XmlUtils.GetXmlNodeText (node, "comments");
+                item.Guid              = XmlUtils.GetXmlNodeText (node, "guid");
+                item.Link              = XmlUtils.GetXmlNodeText (node, "link");
+                item.Modified          = XmlUtils.GetRfc822DateTime (node, "dcterms:modified");
+                item.PubDate           = XmlUtils.GetRfc822DateTime (node, "pubDate");
+                item.LastDownloadTime  = DateTime.Now;
+                
+                item.Enclosure = ParseEnclosure (node);
+                
+                return item;
+             } catch (Exception e) {
+                 Hyena.Log.Exception (e);
+             }
+             
+             return null;
+        }
+        
+        public static FeedEnclosure ParseEnclosure (XmlNode node)
+        {
+            try {
+                FeedEnclosure enclosure = new FeedEnclosure ();
+                enclosure.Url = XmlUtils.GetXmlNodeText (node, "enclosure/@url");
+                enclosure.Length = Math.Max (0, XmlUtils.GetInt64 (node, "enclosure/@length"));
+                enclosure.MimeType = XmlUtils.GetXmlNodeText (node, "enclosure/@type");
+                return enclosure;
+             } catch (Exception e) {
+                 Hyena.Log.Exception (e);
+             }
+             
+             return null;
+        }
+        
+        private void CheckRss ()
+        {            
+            if (doc.SelectSingleNode ("/rss") == null) {
+                throw new FormatException ("Invalid rss document.");                                  
+            }
+            
+            if (XmlUtils.GetXmlNodeText (doc, "/rss/channel/title") == String.Empty) {
+                throw new FormatException (
+                    "node: 'title', 'description', and 'link' nodes must exist."
+                );                
+            }
+        }
+    }
+}

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/EnclosuresTableManager.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/EnclosuresTableManager.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/EnclosuresTableManager.cs	Mon Apr 28 21:42:18 2008
@@ -33,7 +33,7 @@
 
 namespace Migo.Syndication.Data
 {    
-    static class EnclosuresTableManager
+    /*static class EnclosuresTableManager
     {        
         private const string initQuery = @"
             CREATE TABLE IF NOT EXISTS enclosures (
@@ -130,7 +130,7 @@
                 DatabaseManager.Enqueue (enclosureCommandPairs.Keys);
                 
                 foreach (KeyValuePair<QueuedDbCommand,FeedEnclosure> kvp in enclosureCommandPairs) {
-                    kvp.Value.LocalID = Convert.ToInt64 (kvp.Key.ScalarResult);
+                    kvp.Value.DbId = Convert.ToInt64 (kvp.Key.ScalarResult);
                 }  
             } catch {}
         
@@ -155,7 +155,7 @@
                 DbDefines.EnclosuresTableColumns.Active,
                 (enclosure.Active) ? "1" : "0",                                               
                 DbDefines.EnclosuresTableColumns.DownloadMimeType, 
-                enclosure.DownloadMimeType,
+                enclosure.MimeType,
                 DbDefines.EnclosuresTableColumns.DownloadUrl, 
                 enclosure.DownloadUrl,
                 DbDefines.EnclosuresTableColumns.LastDownloadError,
@@ -220,13 +220,13 @@
             DatabaseManager.ExecuteNonQuery (
                 updateEnclosuresQuery, 
                 DbDefines.EnclosuresTableColumns.LocalID, 
-                enclosure.LocalID.ToString (),
+                enclosure.DbId.ToString (),
                 DbDefines.EnclosuresTableColumns.ParentID, 
                 (enclosure.Parent != null) ? enclosure.Parent.LocalID.ToString () : "-1",
                 DbDefines.EnclosuresTableColumns.Active,
                 (enclosure.Active) ? "1" : "0",                                                                                            
                 DbDefines.EnclosuresTableColumns.DownloadMimeType, 
-                enclosure.DownloadMimeType,
+                enclosure.MimeType,
                 DbDefines.EnclosuresTableColumns.DownloadUrl, 
                 enclosure.DownloadUrl,
                 DbDefines.EnclosuresTableColumns.LastDownloadError,
@@ -260,5 +260,5 @@
             
             return ret;
         }           
-    }
+    }*/
 }

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/FeedsTableManager.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/FeedsTableManager.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/FeedsTableManager.cs	Mon Apr 28 21:42:18 2008
@@ -35,7 +35,7 @@
 
 namespace Migo.Syndication.Data
 {    
-    class FeedsTableManager
+    /*class FeedsTableManager
     {     
         public static readonly string initQuery = @" 
             CREATE TABLE IF NOT EXISTS feeds (
@@ -428,5 +428,5 @@
             
             return ret;
         }    
-    }
+    }*/
 }

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/ItemsTableManager.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/ItemsTableManager.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Migo.Syndication.Data/TablesManagers/ItemsTableManager.cs	Mon Apr 28 21:42:18 2008
@@ -33,7 +33,7 @@
 
 namespace Migo.Syndication.Data
 {    
-    static class ItemsTableManager
+    /*static class ItemsTableManager
     {        
         public static readonly string initQuery = @" 
             CREATE TABLE IF NOT EXISTS items (
@@ -334,5 +334,5 @@
             
             return ret;
         }        
-    }
+    }*/
 }

Modified: trunk/banshee/tests/Hyena/SqliteCommandTests.cs
==============================================================================
--- trunk/banshee/tests/Hyena/SqliteCommandTests.cs	(original)
+++ trunk/banshee/tests/Hyena/SqliteCommandTests.cs	Mon Apr 28 21:42:18 2008
@@ -51,6 +51,8 @@
         Assert.AreEqual ("select foo from bar where baz = 555.55", GetGeneratedSql (cmd.ApplyValues (555.55f)));
         Assert.AreEqual ("select foo from bar where baz = 555.55", GetGeneratedSql (cmd.ApplyValues (555.55)));
         Assert.AreEqual ("select foo from bar where baz = 555", GetGeneratedSql (cmd.ApplyValues (555)));
+        Assert.AreEqual ("select foo from bar where baz = 1", GetGeneratedSql (cmd.ApplyValues (true)));
+        Assert.AreEqual ("select foo from bar where baz = 0", GetGeneratedSql (cmd.ApplyValues (false)));
 
         HyenaSqliteCommand cmd2 = new HyenaSqliteCommand ("select foo from bar where baz = ?, bar = ?, boo = ?");
         Assert.AreEqual ("select foo from bar where baz = NULL, bar = NULL, boo = 22", GetGeneratedSql (cmd2.ApplyValues (null, null, 22)));



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]