/// <summary>
        /// Initilizes the push broker instance and creates a new DbContext, checks for both if there is no instance, if so creates a new one.
        /// </summary>
        private void InitBroker()
        {
            _broker          = _broker ?? new PushBroker();
            _databaseContext = _databaseContext ?? new PushSharpDatabaseContext();

            // subscribe to the push brokers API events
            _broker.OnNotificationSent          += broker_OnNotificationSent;
            _broker.OnNotificationFailed        += broker_OnNotificationFailed;
            _broker.OnServiceException          += broker_OnServiceException;
            _broker.OnNotificationRequeue       += broker_OnNotificationRequeue;
            _broker.OnDeviceSubscriptionExpired += broker_OnDeviceSubscriptionExpired;
            _broker.OnDeviceSubscriptionChanged += broker_OnDeviceSubscriptionChanged;
            _broker.OnChannelCreated            += broker_OnChannelCreated;
            _broker.OnChannelDestroyed          += broker_OnChannelDestroyed;
            _broker.OnChannelException          += broker_OnChannelException;

            _broker.RegisterGcmService(new GcmPushChannelSettings(_googlePushNotificationAuthToken));

            // NOTE: in this case we are skipping apple stuff,
            // if you wish to use apple iOS notifications uncomment below and use the proper cert i.e. dev/prod
            // _broker.RegisterAppleService(new ApplePushChannelSettings(false, _applePushNotificationCertificate, "Password"));

            _broker.RegisterWindowsService(_windowsPushNotificationChannelSettings);

            On(DisplayMessage, "Push Broker successfully initialized.");
        }
        /// <summary>
        /// A processor method used to process multiple notifications at once.
        /// </summary>
        /// <param name="databaseContext">The current database context to be used for processing to the database.</param>
        /// <param name="pushNotifications">A list of push notifitcation entities to be processed and saved.</param>
        /// <returns>True if all OK, false if sth. goes wrong.</returns>
        public bool ProcessNotificationsImmediately(PushSharpDatabaseContext dbContext, IList <PushNotification> pushNotifications)
        {
            try
            {
                // runs the broker during the loop, then stops
                InitBroker();

                _immediatePushCounter = pushNotifications.Count;

                foreach (var pushNotification in pushNotifications)
                {
                    if (!ProcessNotification(dbContext, pushNotification, false))
                    {
                        throw new Exception("INTERNAL EX. ERROR: Error on processing a single notification in ProcessNotifications method!");
                    }
                }

                // the broker can be stopped by the counter only, all should be processed...
                // KillBroker(_databaseContext);
                return(true);
            }
            catch (Exception ex)
            {
                On(DisplayErrorMessage, "EX. ERROR: Saving and pushing multiple notifications: " + ex.Message);
                SimpleErrorLogger.LogError(ex);
                return(false);
            }
        }
 private void DisposeContext(PushSharpDatabaseContext ctx, bool disposeContext)
 {
     if (disposeContext)
     {
         ctx.Dispose();
         ctx = null;
         _databaseContext = null;
         On(DisplayMessage, "Database context sucessfully disposed.");
     }
 }
        /// <summary>
        /// Kills the push broker instance by frist stoping it's services and unhooking the event handlers, then disposes the sent DbContext.
        /// </summary>
        /// <param name="dbContext">The current EF database context instance to be disposed.</param>
        private void KillBroker(PushSharpDatabaseContext dbContext)
        {
            _broker.StopAllServices();

            // unsubscribe from the API events
            _broker.OnNotificationSent          -= broker_OnNotificationSent;
            _broker.OnNotificationFailed        -= broker_OnNotificationFailed;
            _broker.OnServiceException          -= broker_OnServiceException;
            _broker.OnNotificationRequeue       -= broker_OnNotificationRequeue;
            _broker.OnDeviceSubscriptionExpired -= broker_OnDeviceSubscriptionExpired;
            _broker.OnDeviceSubscriptionChanged -= broker_OnDeviceSubscriptionChanged;
            _broker.OnChannelCreated            -= broker_OnChannelCreated;
            _broker.OnChannelDestroyed          -= broker_OnChannelDestroyed;
            _broker.OnChannelException          -= broker_OnChannelException;

            DisposeContext(dbContext, true);

            On(DisplayMessage, "Push Broker successfully stopped.");
        }
        /// <summary>
        /// Enqueues a single notification on the database.
        /// </summary>
        /// <param name="databaseContext">The database context used for saving.</param>
        /// <param name="pushNotification">A push notification to be saved for later processing.</param>
        /// <param name="saveAndDisposeContext"></param>
        /// <returns>True if all OK, false if not.</returns>
        public bool EnqueueNotificationOnDatabase(PushSharpDatabaseContext databaseContext, PushNotification pushNotification, bool saveAndDisposeContext = true)
        {
            try
            {
                databaseContext.PushNotification.Add(pushNotification);

                if (saveAndDisposeContext)
                {
                    databaseContext.SaveChanges();
                    databaseContext.Dispose();
                }

                return(true);
            }
            catch (Exception ex)
            {
                On(DisplayErrorMessage, "EX. ERROR: Enqueuing notification, DB save failed: " + ex.Message);
                SimpleErrorLogger.LogError(ex);
                return(false);
            }
        }
        /// <summary>
        /// Enqueues a list of push notifications on the database to be pushed when the processor runs.
        /// </summary>
        /// <param name="databaseContext">The database context used for saving.</param>
        /// <param name="pushNotifications">The list of push notifications on the database to be pushed when the processor runs</param>
        /// <returns>True if all OK, false if not.</returns>
        public bool EnqueueNotificationsOnDatabase(PushSharpDatabaseContext databaseContext, List <PushNotification> pushNotifications)
        {
            try
            {
                foreach (var pushNotification in pushNotifications)
                {
                    if (!EnqueueNotificationOnDatabase(databaseContext, pushNotification, false))
                    {
                        throw new Exception("INTERNAL EX. ERROR: Error on adding a single notification in EnqueueNotificationsOnDatabase method!");
                    }
                }

                databaseContext.SaveChanges();
                databaseContext.Dispose();

                return(true);
            }
            catch (Exception ex)
            {
                On(DisplayErrorMessage, "EX. ERROR: Enqueuing notification, DB save failed: " + ex.Message);
                SimpleErrorLogger.LogError(ex);
                return(false);
            }
        }
        /// <summary>
        /// The main processor method used to process a single push notification, checks if the processing will be an immediate single push or regular thread looping model.
        /// Looks up for a single (or more if you wish) entity in the databae which has not been processed.
        /// Puts the fetched unprocessed push notification entity to processing over the Push Sharp API.
        /// Finally saves the state of processing.
        /// </summary>
        /// <param name="databaseContext">The current database context to be used for processing to the database.</param>
        /// <param name="pushNotification">A single push notification entity to be processed and saved.</param>
        /// <param name="isDirectSinglePush">Decides wethere the processing will take place immediately for the sent notification or will the method lookup from the database for a first unprocessed push notification.</param>
        /// <returns>True if all OK, false if not.</returns>
        public bool ProcessNotification(PushSharpDatabaseContext dbContext, PushNotification pushNotification = null, bool isDirectSinglePush = false)
        {
            _databaseContext    = dbContext;
            _isDirectSinglePush = isDirectSinglePush;

            if (_isDirectSinglePush)
            {
                InitBroker();
            }

            On(DisplayMessage, "Checking for unprocessed notifications...");
            PushNotification notificationEntity = pushNotification;

            try
            {
                if (notificationEntity != null)
                {
                    // save a new immediate unprocessed push notification
                    _databaseContext.PushNotification.Add(pushNotification);
                    _databaseContext.SaveChanges();

                    // reload the entity
                    notificationEntity = _databaseContext.PushNotification
                                         .Where(x => x.ID == pushNotification.ID)
                                         .Include(x => x.MobileDevice)
                                         .Include(x => x.MobileDevice.Client)
                                         .FirstOrDefault();
                }
                else // take one latest unprocessed notification, this can be changed to take any set size instead of one
                {
                    notificationEntity = _databaseContext.PushNotification.FirstOrDefault(s =>
                                                                                          s.Status == (int)PushNotificationStatus.Unprocessed &&
                                                                                          s.CreatedAt <= DateTime.Now);
                }
            }
            catch (Exception ex)
            {
                On(DisplayErrorMessage, "EX. ERROR: Check for unprocessed notifications: " + ex.Message);
                SimpleErrorLogger.LogError(ex);
            }

            // Process i.e. push the push notification via PushSharp...
            if (notificationEntity != null)
            {
                bool messagePushed = true;

                On(DisplayStatusMessage, "Processing notification...");
                On(DisplayMessage, "ID " + notificationEntity.ID + " for " + notificationEntity.MobileDevice.Client.Username + " -> " + notificationEntity.Message);

                //---------------------------
                // ANDROID GCM NOTIFICATIONS
                //---------------------------
                if (notificationEntity.MobileDevice.SmartphonePlatform == "android")
                {
                    var gcmNotif = new GcmNotification()
                    {
                        Tag = notificationEntity.ID
                    };
                    string msg = JsonConvert.SerializeObject(new { message = notificationEntity.Message });

                    gcmNotif.ForDeviceRegistrationId(notificationEntity.MobileDevice.PushNotificationsRegistrationID)
                    .WithJson(msg);

                    _broker.QueueNotification(gcmNotif);
                    UpdateNotificationQueued(notificationEntity);
                }
                ////-------------------------
                //// APPLE iOS NOTIFICATIONS
                ////-------------------------
                else if (notificationEntity.MobileDevice.SmartphonePlatform == "ios")
                {
                    var appleNotif = new AppleNotification()
                    {
                        Tag = notificationEntity.ID
                    };
                    var msg = new AppleNotificationPayload(notificationEntity.Message);

                    appleNotif.ForDeviceToken(notificationEntity.MobileDevice.PushNotificationsRegistrationID)
                    .WithPayload(msg)
                    .WithSound("default");

                    _broker.QueueNotification(appleNotif);
                    UpdateNotificationQueued(notificationEntity);
                }
                //----------------------
                // WINDOWS NOTIFICATIONS
                //----------------------
                else if (notificationEntity.MobileDevice.SmartphonePlatform.Equals("wp") || notificationEntity.MobileDevice.SmartphonePlatform.Equals("wsa"))
                {
                    var wNotif = new WindowsToastNotification()
                    {
                        Tag = notificationEntity.ID
                    };

                    wNotif.ForChannelUri(notificationEntity.MobileDevice.PushNotificationsRegistrationID)
                    .AsToastText02("PushSharp Notification", notificationEntity.Message);

                    _broker.QueueNotification(wNotif);
                    UpdateNotificationQueued(notificationEntity);
                }
                else
                {
                    On(DisplayErrorMessage, "ERROR: Unsupported device OS: " + notificationEntity.MobileDevice.SmartphonePlatform);

                    notificationEntity.Status      = (int)PushNotificationStatus.Error;
                    notificationEntity.ModifiedAt  = DateTime.Now;
                    notificationEntity.Description = "(Processor) Unsupported device OS: " + notificationEntity.MobileDevice.SmartphonePlatform;
                    SimpleErrorLogger.LogError(new Exception("EX. ERROR: " + notificationEntity.Description));
                    messagePushed = false;
                }

                try
                {
                    // Save changes to DB to keep the correct state of messages
                    _databaseContext.SaveChanges();

                    // bubble out the single push error, else return true to continue iteration
                    if (_isDirectSinglePush)
                    {
                        return(messagePushed);
                    }

                    return(true);
                }
                catch (Exception ex)
                {
                    On(DisplayErrorMessage, "EX. ERROR: Updating notification, DB save failed: " + ex.Message);
                    SimpleErrorLogger.LogError(ex);

                    // bubble out the single push error, else return true to continue iteration
                    if (_isDirectSinglePush)
                    {
                        return(false);
                    }

                    return(true);
                }
                finally
                {
                    if (_isDirectSinglePush)
                    {
                        KillBroker(_databaseContext);
                    }
                }
            }
            else
            {
                if (_isDirectSinglePush)
                {
                    KillBroker(_databaseContext);
                }

                // no messages were queued, take a nap...
                return(false);
            }
        }
 public BaseApiController()
 {
     this.Processor       = new PushNotificationProcessor();
     this.DatabaseContext = new PushSharpDatabaseContext();
 }