using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml.Linq;
using System.Web;
using System.Drawing;
using System.Threading;
using System.Concurrency;
using System.IO;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace Aqua877.WinApp.IronLivetube.LSchedule
{
	public class LiveData
	{
		public event Action OnGetThumbnailFinished;

		public string Title { get; set; }
		public string Author { get; set; }
		public DateTime Start { get; set; }
		public Uri Url { get; set; }
		public string[] Tags { get; set; }
		public int Listeners { get; set; }
		public int Visitors { get; set; }
		public int Comments { get; set; }
		public Uri ThumbnailUrl { get; set; }
		public Image Thumbnail { get; set; }

		public void BeginGetThumbnail()
		{
			Observable.Start(() =>
			{
				using (var connector = new WebClient())
				{
					try
					{
						using (var stream = connector.OpenRead(this.ThumbnailUrl))
						{
							this.Thumbnail = Image.FromStream(stream);
						}
					}
					catch(WebException)
					{
						return;
					}
				}
			}, Scheduler.ThreadPool)
			.ObserveOnDispatcher()
			.Subscribe(_ => this.NotifyOnGetThumbnailFinished());
		}

		protected virtual void NotifyOnGetThumbnailFinished()
		{
			if (this.OnGetThumbnailFinished != null)
			{
				this.OnGetThumbnailFinished();
			}
		}

		public override bool Equals(object obj)
		{
			var o = obj as LiveData;

			if (o == null)
			{
				return false;
			}

			return this.Title == o.Title && this.Author == o.Author;
		}

		public override int GetHashCode()
		{
			return this.Title.GetHashCode() ^ this.Author.GetHashCode();
		}
	}

	public class LiveDataBase
	{
		private List<LiveData> _LiveCollection = new List<LiveData>();
		public IDisposable GetDataTimer;

		public event Action<IEnumerable<LiveData>, IEnumerable<LiveData>> OnGetLiveDataFinished;
		public event Action<string> OnStatusTextChanged;
		public event Action<LiveData> OnGetThumbnailFinished;

		public List<LiveData> LiveCollection
		{
			get
			{
				return this._LiveCollection;
			}
			set
			{
				this._LiveCollection = value;
			}
		}

		public LiveDataBase()
		{
		}

		public void BeginGetLiveSchedule()
		{
			this.GetDataTimer = Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(60)).ObserveOnDispatcher()
			.Subscribe(
				s =>
				{
					this.NotifyOnStatusTextChanged("配信情報取得開始...");
					var connector = new WebClient() { Encoding = Encoding.UTF8 };
					connector.DownloadStringCompleted += this.OnGetLiveFeedFinished;
#if DEBUG
					connector.DownloadStringAsync(new Uri("http://192.168.1.3/ltagg/ltapi.xml"));
#else
					connector.DownloadStringAsync(new Uri("http://aqua-s.ddo.jp/ltagg/ltapi.xml"));
#endif
				}
			);
		}

		private void OnGetLiveFeedFinished(object sender, DownloadStringCompletedEventArgs e)
		{
			if (e.Error != null)
			{
				this.NotifyOnStatusTextChanged("配信情報取得中にエラーが発生しました");
			}
			else
			{
				var document = XElement.Parse(e.Result);

				var current = document.Descendants("Live")
					.Select(xs =>
						new LiveData()
						{
							Title = HttpUtility.HtmlDecode(xs.Element("Title").Value),
							Author = HttpUtility.HtmlDecode(xs.Element("Author").Value),
							Url = new Uri(xs.Element("Url").Value),
							ThumbnailUrl = new Uri(xs.Element("ThumbnailUrl").Value),
							Tags = xs.Element("Tags").Elements("Tag").Select(es => es.Value).ToArray(),
							Listeners = int.Parse(xs.Element("Listeners").Value),
							Visitors = int.Parse(xs.Element("Visitors").Value),
							Comments = int.Parse(xs.Element("Comments").Value),
							Start = DateTime.Parse(xs.Element("Start").Value)
						}
					)
					.OrderBy(xs => xs.Start, (a, b) => DateTime.Compare(a, b));

				var added = current.Except(this._LiveCollection);
				added.ForEach(xs => {
					xs.OnGetThumbnailFinished += () => this.NotifyOnGetThumbnailFinished(xs);
					xs.BeginGetThumbnail();
				});

				var removed = this._LiveCollection.Except(current);

				this._LiveCollection = current.ToList();

				this.NotifyOnStatusTextChanged("取得成功");
				this.NotifyOnGetLiveDataFinished(added, removed);
			}
		}

		public void EndGetLiveSchedule()
		{
			this.GetDataTimer.Dispose();
		}

		protected virtual void NotifyOnGetLiveDataFinished(IEnumerable<LiveData> added, IEnumerable<LiveData> removed)
		{
			if (this.OnGetLiveDataFinished != null)
			{
				this.OnGetLiveDataFinished(added, removed);
			}
		}

		protected virtual void NotifyOnStatusTextChanged(string text)
		{
			if (this.OnStatusTextChanged != null)
			{
				this.OnStatusTextChanged(text);
			}
		}

		protected virtual void NotifyOnGetThumbnailFinished(LiveData data)
		{
			if(this.OnGetThumbnailFinished != null)
			{
				this.OnGetThumbnailFinished(data);
			}
		}
	}

	public static class Extensions
	{
		public static void ForEach<T>(this IEnumerable<T> array, Action<T> action)
		{
			foreach (T item in array)
			{
				action(item);
			}
		}

		public static void ForEach<T>(this IEnumerable<T> array, Action<T, int> action)
		{
			int count = 0;
			foreach (T item in array)
			{
				action(item, count);
				count++;
			}
		}

		public static TRet Let<TArg, TRet>(this TArg obj, Func<TArg, TRet> action)
		{
			return action(obj);
		}

		public static T Do<T>(this T obj, Action<T> action)
		{
			action(obj);
			return obj;
		}
	}
}
