using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Xml.Linq;
using Fibre.WP7.Threading;
using GalaSoft.MvvmLight.Messaging;
using MahTweets.Mobile.Core.Extensions;
using MahTweets.Mobile.Core.Interfaces;
namespace MahTweets.Mobile.Core
{
public class StatusManager : IStatusUpdatesManager
{
private readonly object LockCollection = new object();
private System.Windows.Threading.DispatcherTimer pulseTimer;
///
/// Key = string (from IUpdateType.ID), Value = List of IStatusUpdate
///
private readonly Dictionary> StatusesById =
new Dictionary>();
private ThreadSafeObservableCollection StatusList =
new ThreadSafeObservableCollection();
public StatusManager()
{
Messenger.Default.Register(this, PauseTimerHandler);
Messenger.Default.Register(this, ResumeTimerHandler);
Start();
}
private void PauseTimerHandler(PauseTimerEvent e)
{
pulseTimer.Stop();
}
private void ResumeTimerHandler(ResumeTimerEvent e)
{
Start();
}
public void Start()
{
pulseTimer = new System.Windows.Threading.DispatcherTimer();
pulseTimer.Interval = new TimeSpan(0, 0, 1);
pulseTimer.Tick += new EventHandler(Each_Tick);
pulseTimer.Start();
}
public void Each_Tick(object o, EventArgs sender)
{
foreach (var s in StatusList)
s.Pulse();
}
#region IStatusUpdatesManager Members
public ThreadSafeObservableCollection Collection
{
get { return StatusList; }
set { StatusList = value; }
}
//public Action OnUpdate { get; set; }
public void Reset()
{
lock (LockCollection)
{
StatusesById.Clear();
StatusList.Clear();
}
}
public void Send(IEnumerable updates)
{
ThreadPool.QueueUserWorkItem(state =>
{
foreach (IStatusUpdate update in updates)
{
SendStatusUpdateInternal(update);
}
});
}
public void Send(IStatusUpdate update)
{
new AsyncWork().AddWork(() => SendStatusUpdateInternal(update)).PerformWork();
//ThreadPool.QueueUserWorkItem(state => { bool result = SendStatusUpdateInternal(update); });
}
public bool UpdateOrCreateStatus(string id, Func createNew, Func updateExisting)
where T : class, IStatusUpdate
{
// See if we can return the ID if it already exists before trying to get a lock
if (StatusesById.ContainsKey(id))
{
var listUpdates = StatusesById[id] as IList;
if (listUpdates == null) return false; // default(T);
//if (listUpdates.Count(s => s.GetType() == typeof(T)) >= 0)
//{
// BF - potential concurrency issue here when using .Single() with multiple items
T existing = listUpdates.OfType().FirstOrDefault();
lock (existing)
{
updateExisting(existing);
return false;
}
//}
}
// Doesn't exist, so lock
lock (LockCollection)
{
List listUpdates;
if (!StatusesById.ContainsKey(id))
{
listUpdates = new List();
StatusesById.Add(id, listUpdates);
}
else
{
listUpdates = StatusesById[id];
}
// Check: Was it already created before we got the lock?
if (listUpdates.Count(s => s.GetType() == typeof (T)) == 1)
{
var existing = (T) listUpdates.Single(s => s.GetType() == typeof (T));
lock (existing)
{
updateExisting(existing);
return false;
}
}
// No, so, go add it to the hashtable
T newStatusUpdate = createNew(id);
listUpdates.Add(newStatusUpdate);
// queue a background worker to update the ObservableCollection
//ThreadPool.QueueUserWorkItem(state => StatusList.Add(newStatusUpdate));
//Deployment.Current.Dispatcher.BeginInvoke(() => StatusList.Add(newStatusUpdate));
new AsyncWork().AddWork(() => StatusList.Add(newStatusUpdate)).PerformWork();
return true; // newStatusUpdate;
}
}
public T GetById(string id, T defaultIfNotFound) where T : class, IStatusUpdate
{
if (StatusesById.ContainsKey(id))
{
List listUpdates = StatusesById[id];
if (listUpdates.Count(s => s.GetType() == typeof (T)) == 1)
{
var existing = (T) listUpdates.Single(s => s.GetType() == typeof (T));
return existing;
}
}
return defaultIfNotFound;
}
public T GetById(string id) where T : class, IStatusUpdate
{
return GetById(id, null);
}
#endregion
private bool SendStatusUpdateInternal(IStatusUpdate update)
{
IStatusUpdate u = update;
bool y = UpdateOrCreateStatus(update.ID,
id => u,
existing =>
{
u.Types.Where(t => !existing.Types.Contains(t)).ForEach(
type => existing.Types.Add(type));
u.Parents.Where(p => !existing.Parents.Contains(p)).ForEach(
parent => existing.Parents.Add(parent));
return existing;
});
//if (OnUpdate != null)
//OnUpdate(u);
return y;
}
}
}