using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;

using Banshee.Collection.Indexer.RemoteHelper;

using DAAP;
using NDesk.DBus;
using Nini;
using log4net;

[assembly: Tangerine.Plugin ("banshee", typeof (Tangerine.Plugins.BansheePlugin))]

namespace Tangerine.Plugins 
{
    class BansheePlugin : SimpleIndexerClient
	{
		int count;
		bool running;
		bool indexing;
		DateTime last_change;
		object indexing_mutex;
        List<IDictionary<string, object>> indexed_items;

		readonly string [] export_fields = new [] {"name", "artist", "genre", "year", "album", "local-path", "URI", 
			"media-attributes", "track-number", "track-count", "bitrate"};
        
        public BansheePlugin () : base ()
		{
			BusG.Init ();
	
			count = 0;
			running = true;
			indexing = false;
			indexing_mutex = new object ();
		    last_change = DateTime.MinValue;
			indexed_items = new List<IDictionary<string, object>> ();
			
			AddExportField (export_fields);
			IndexWhenCollectionChanged = false;
			
			Start ();
        }
		
		Server Server { get { return Daemon.Server; } }
		Database Database { get { return Daemon.DefaultDatabase; } }
		
		protected override void IndexResult (IDictionary<string, object> result)
		{
			if (indexing)
				indexed_items.Add (result);
		}
		
		protected override void OnStarted ()
		{
			Console.Error.WriteLine ("Indexer started");
		}

		protected override void OnBeginUpdateIndex ()
		{
			Console.Error.WriteLine ("Reading Banshee index results from DBus");
			lock (indexing_mutex) {
				indexing = true;
			}
		}
		
		protected override void OnEndUpdateIndex ()
		{
			lock (indexing_mutex) {
				indexing = false;
			}
			
			ProcessList ();
			Server.Commit ();
			indexed_items.Clear ();
		}
		
		protected override void OnShutdownWhileIndexing ()
		{
			Console.Error.WriteLine ("need to quit");
		}
		
		protected override int CollectionCount {
			get { return count; }
		}
		
		protected override DateTime CollectionLastModified {
			get { return last_change; }
		}
		
		void ProcessList ()
		{
			if (indexing)
				return;
			
			int tmpCount = 0;
			
			foreach (IDictionary<string, object> result in indexed_items)
			{
				Track track;
				short bitrate;
				string path, mediaType;
				Dictionary<string, string> tags;
				int year, trackCount, trackNumber;
				
				tags = SetupTags ();
				foreach (string tag in export_fields) {
					object objTag;
					
					result.TryGetValue (tag, out objTag);
					tags [tag] = (objTag == null) ? "" : objTag.ToString ();
				}
				
				mediaType = tags ["media-attributes"];				
				
				// ignore videos or podcasts in the collection since they're not shared over DAAP.
				// TODO check if this is actually true for podcasts
				if (mediaType.Contains ("VideoStream") || mediaType.Contains ("Podcast"))
					continue;
				
				// some items dont have a local-path, we need to use the URI in this case.
				try {
					path = string.IsNullOrEmpty (tags ["local-path"]) ? tags ["URI"] : tags ["local-path"];					
					Uri uri = new Uri (path);
					track = new Track ();
					track.FileName = uri.LocalPath;
					track.Title = tags ["name"];
					track.Album = tags ["album"];
					track.Genre = tags ["genre"];
					track.Artist = tags ["artist"];
					
					if (int.TryParse (tags ["year"], out year))
						track.Year = year;
					if (short.TryParse (tags ["bitrate"], out bitrate))
						track.BitRate = bitrate;
					if (int.TryParse (tags ["track-count"], out trackCount))
						track.TrackCount = trackCount;
					if (int.TryParse (tags ["track-number"], out trackNumber))
						track.TrackNumber = trackNumber;
					
					track.Format = Path.GetExtension (track.FileName).Substring (1); // the 1 cuts off the .
					
					Daemon.DefaultDatabase.AddTrack (track);
					tmpCount++;
				} catch (Exception e) {
					Console.WriteLine ("{0}\n{1}", e.Message, e.StackTrace);
				}
			}
			
			count = tmpCount;
		}
		
		Dictionary<string, string> SetupTags ()
		{
			Dictionary<string, string> tags = new Dictionary<string, string> ();
			foreach (string tag in export_fields) {
				tags.Add (tag, "");
			}

			return tags;
		}
    }
}
