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; } } }