using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.Xml.Linq;
using WindowsPhone.Recipes.Push.Messasges;
using WindowsPhone.Recipes.Push.Server.Services;
using WindowsPhone.Recipes.Push.Server.Models;
namespace WindowsPhone.Recipes.Push.Server.ViewModels
{
///
/// Represents the Counter push notification pattern.
///
///
/// Send a tile push notification message with a counter value.
/// Each time a push notification message is sent the counter value
/// increases by one, unless user is running the application and notifies
/// the server.
///
[Export(typeof(PushPatternViewModel)), PartCreationPolicy(CreationPolicy.Shared)]
internal sealed class CounterPushPatternViewModel : PushPatternViewModel
{
#region Fields
/// A dictionary for tracking tile message count while phone-application is not running.
private readonly Dictionary _messageCounter = new Dictionary();
/// Synchronizes access to the message counter collection.
private readonly object MessageCounterSync = new object();
#endregion
#region Ctor
///
/// Initialize new instance of this type with defaults.
///
public CounterPushPatternViewModel()
{
InitializeDefaults();
}
#endregion
#region Overrides
///
/// Send raw message to all subscribers. In case that the phone-application
/// is not running, send tile update and increase tile counter.
///
protected override void OnSend()
{
// Notify phone for having waiting messages.
var rawMsg = new RawPushNotificationMessage(MessageSendPriority.High)
{
RawData = Encoding.ASCII.GetBytes(RawMessage)
};
foreach (var subscriber in PushService.Subscribers)
{
rawMsg.SendAsync(
subscriber.ChannelUri,
result =>
{
Log(result);
OnRawSent(subscriber.UserName, result);
},
Log);
}
}
///
/// On subscription change, reset the subscriber tile counter if exist.
///
protected override void OnSubscribed(SubscriptionEventArgs e)
{
// Create a tile message to reset tile count.
var tileMsg = new TilePushNotificationMessage(MessageSendPriority.High)
{
Count = 0,
BackgroundImageUri = BackgroundImageUri,
Title = Title
};
tileMsg.SendAsync(e.Subscription.ChannelUri, Log, Log);
ResetCounter(e.Subscription.UserName);
}
#endregion
#region Privates
private void OnRawSent(string userName, MessageSendResult result)
{
// In case that the device is disconnected, no need to send a tile message.
if (result.DeviceConnectionStatus == DeviceConnectionStatus.TempDisconnected)
{
return;
}
// Checking these three flags we can know what's the state of both the device and apllication.
bool isApplicationRunning =
result.SubscriptionStatus == SubscriptionStatus.Active &&
result.NotificationStatus == NotificationStatus.Received &&
result.DeviceConnectionStatus == DeviceConnectionStatus.Connected;
// In case that the application is not running, send a tile update with counter increase.
if (!isApplicationRunning)
{
var tileMsg = new TilePushNotificationMessage(MessageSendPriority.High)
{
Count = IncreaseCounter(userName),
BackgroundImageUri = BackgroundImageUri,
Title = Title
};
tileMsg.SendAsync(result.ChannelUri, Log, Log);
}
}
private void ResetCounter(string userName)
{
lock (MessageCounterSync)
{
_messageCounter.Remove(userName);
}
}
private int IncreaseCounter(string userName)
{
lock (MessageCounterSync)
{
int counter;
if (_messageCounter.TryGetValue(userName, out counter))
{
++counter;
}
else
{
counter = 1;
}
_messageCounter[userName] = counter;
return counter;
}
}
private void InitializeDefaults()
{
DisplayName = "Counter";
Description = "Send push notification message of Tile type, with a counter value. Each time a push notification message is sent, the counter value increases by one, unless user is running the application and notifies the server.";
BackgroundImageUri = TileImages.Length > 1 ? TileImages[1] : TileImages.FirstOrDefault();
RawMessage = "Game Update";
Count = 0;
Title = "Updates";
}
#endregion
}
}