/// <summary>
        /// Erzeugt eine Instanz der Reminder Klasse, welche mit den Daten gefüllt
        /// wird, die der Nutzer eingegeben hat.
        /// </summary>
        /// <returns>Eine Instanz von Reminder, oder null, falls Erzeugung fehlschlägt.</returns>
        private Reminder createReminderFromEnteredData()
        {
            Moderator activeModerator = channelController.GetLocalModerator();
            if (activeModerator == null)
            {
                Debug.WriteLine("No active moderator. Cannot continue.");
                return null;
            }

            DateTime selectedStartDateTmp = new DateTime(SelectedStartDate.Year, SelectedStartDate.Month, SelectedStartDate.Day,
                SelectedTime.Hours, SelectedTime.Minutes, SelectedTime.Seconds);
            DateTime selectedEndDateTmp = new DateTime(SelectedEndDate.Year, SelectedEndDate.Month, SelectedEndDate.Day,
                SelectedTime.Hours, SelectedTime.Minutes, SelectedTime.Seconds);

            selectedStartDateTmp = DateTime.SpecifyKind(selectedStartDateTmp, DateTimeKind.Local);
            selectedEndDateTmp = DateTime.SpecifyKind(selectedEndDateTmp, DateTimeKind.Local);

            DateTimeOffset reminderStartDate = new DateTimeOffset(selectedStartDateTmp);
            DateTimeOffset reminderEndDate = new DateTimeOffset(selectedEndDateTmp);
            
            //// Start und Ende-Datum
            //DateTimeOffset reminderStartDate = new DateTimeOffset(SelectedStartDate.Year, SelectedStartDate.Month, SelectedStartDate.Day,
            //    SelectedTime.Hours, SelectedTime.Minutes, SelectedTime.Seconds, TimeZoneInfo.Local.BaseUtcOffset);
            //DateTimeOffset reminderEndDate = new DateTimeOffset(SelectedEndDate.Year, SelectedEndDate.Month, SelectedEndDate.Day,
            //    SelectedTime.Hours, SelectedTime.Minutes, SelectedTime.Seconds, TimeZoneInfo.Local.BaseUtcOffset);

            int chosenInterval = IntervalValue;
            int channelId = SelectedChannel.Id;
            int authorId = activeModerator.Id;
            string enteredTitle = Title;
            string enteredContent = Text;
            Priority priority = Priority.NORMAL;
            if (IsPriorityHighSelected)
            {
                priority = Priority.HIGH;
            }
            bool ignoreFlag = SkipNextReminderDate;

            Reminder newReminder = new Reminder()
            {
                StartDate = reminderStartDate,
                EndDate = reminderEndDate,
                Interval = chosenInterval,
                ChannelId = channelId,
                AuthorId = authorId,
                Title = enteredTitle,
                Text = enteredContent,
                MessagePriority = priority,
                Ignore = ignoreFlag
            };

            return newReminder;
        }
        /// <summary>
        /// Holt den Reminder mit der angegebenen Id aus der lokalen Datenbank, sofern
        /// der Datensatz vorhanden ist.
        /// </summary>
        /// <param name="reminderId">Die Id des Reminders, der aus der DB geholt werden soll.</param>
        /// <returns>Ein Objekt vom Typ Reminder, oder null, falls kein Datensatz existiert hat.</returns>
        /// <exception cref="DatabaseException">Wirft DatabaseException, wenn Abruf der Daten fehlschlägt.</exception>
        public Reminder GetReminder(int reminderId)
        {
            Reminder reminder = null;

             // Frage das Mutex Objekt ab.
            Mutex mutex = DatabaseManager.GetDatabaseAccessMutexObject();

            // Fordere Zugriff auf die Datenbank an.
            if (mutex.WaitOne(DatabaseManager.MutexTimeoutValue))
            {
                using (SQLiteConnection conn = DatabaseManager.GetConnection())
                {
                    try
                    {
                        string sql = @"SELECT * 
                            FROM Reminder 
                            WHERE Id=?;";

                        int channelId, interval, authorId;
                        string title, text;
                        bool ignore;
                        bool? isActive = null;
                        Priority priority;
                        DateTimeOffset startDate, endDate, creationDate, modificationDate;

                        using (var stmt = conn.Prepare(sql))
                        {
                            stmt.Bind(1, reminderId);

                            if (stmt.Step() == SQLiteResult.ROW)
                            {
                                channelId = Convert.ToInt32(stmt["Channel_Id"]);
                                startDate = DatabaseManager.DateTimeFromSQLite(stmt["StartDate"].ToString());
                                endDate = DatabaseManager.DateTimeFromSQLite(stmt["EndDate"].ToString());
                                creationDate = DatabaseManager.DateTimeFromSQLite(stmt["CreationDate"].ToString());
                                modificationDate = DatabaseManager.DateTimeFromSQLite(stmt["ModificationDate"].ToString());
                                interval = Convert.ToInt32(stmt["Interval"]);
                                ignore = ((long)stmt["Ignore"] == 1) ? true : false;
                                title = (string)stmt["Title"];
                                text = (string)stmt["Text"];
                                authorId = Convert.ToInt32(stmt["Author_Moderator_Id"]);
                                priority = (Priority)Enum.ToObject(typeof(Priority), stmt["Priority"]);

                                if (stmt["Active"] != null)
                                {
                                    isActive = ((long)stmt["Active"] == 1) ? true : false;
                                }

                                reminder = new Reminder(reminderId, creationDate, modificationDate, startDate, endDate, interval,
                                    ignore, channelId, authorId, title, text, priority);
                                reminder.IsActive = isActive;       // Setze IsActive Property.
                            }
                        }
                    }
                    catch (SQLiteException sqlEx)
                    {
                        Debug.WriteLine("Extraction of reminder with id {0} has failed. Msg is: {1}.",
                            reminderId,
                            sqlEx.Message);
                        throw new DatabaseException(sqlEx.Message);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine("GetReminder has failed. The message is: {0} and stack trace is {1}.",
                            ex.Message, ex.StackTrace);
                        throw new DatabaseException(ex.Message);
                    }
                    finally
                    {
                        mutex.ReleaseMutex();
                    }
                }
            }
            else
            {
                Debug.WriteLine("Couldn't get access to database. Time out.");
                throw new DatabaseException("Could not get access to the database.");
            }

            return reminder;
        }
        /// <summary>
        /// Aktualisiert das Datum des nächsten Termins, an dem der Reminder feuert.
        /// </summary>
        private void updateNextReminderDate()
        {
            Debug.WriteLine("In updateNextReminderDate.");

            if (SelectedStartDate == DateTimeOffset.MinValue || SelectedEndDate == DateTimeOffset.MinValue)
                return;

            DateTime selectedStartDateTmp = new DateTime(SelectedStartDate.Year, SelectedStartDate.Month, SelectedStartDate.Day,
                SelectedTime.Hours, SelectedTime.Minutes, SelectedTime.Seconds);
            DateTime selectedEndDateTmp = new DateTime(SelectedEndDate.Year, SelectedEndDate.Month, SelectedEndDate.Day,
                SelectedTime.Hours, SelectedTime.Minutes, SelectedTime.Seconds);

            selectedStartDateTmp = DateTime.SpecifyKind(selectedStartDateTmp, DateTimeKind.Local);
            selectedEndDateTmp = DateTime.SpecifyKind(selectedEndDateTmp, DateTimeKind.Local);

            DateTimeOffset reminderStartDate = new DateTimeOffset(selectedStartDateTmp);
            DateTimeOffset reminderEndDate = new DateTimeOffset(selectedEndDateTmp);

            //DateTimeOffset reminderStartDate = new DateTimeOffset(SelectedStartDate.Year, SelectedStartDate.Month, SelectedStartDate.Day,
            //    SelectedTime.Hours, SelectedTime.Minutes, SelectedTime.Seconds, TimeZoneInfo.Local.BaseUtcOffset);
            //DateTimeOffset reminderEndDate = new DateTimeOffset(SelectedEndDate.Year, SelectedEndDate.Month, SelectedEndDate.Day,
            //    SelectedTime.Hours, SelectedTime.Minutes, SelectedTime.Seconds, TimeZoneInfo.Local.BaseUtcOffset);

            // Erzeuge Reminder Objekt mit aktuellen Daten und lasse den nächsten
            // Reminder Zeitpunkt bestimmen.
            Reminder reminderTmp = new Reminder()
            {
                StartDate = reminderStartDate,
                EndDate = reminderEndDate,
                Ignore = SkipNextReminderDate,
                Interval = IntervalValue
            };

            reminderTmp.ComputeFirstNextDate();
            reminderTmp.EvaluateIsExpired();

            if (reminderTmp.IsExpired)
            {
                Debug.WriteLine("Reminder is expired.");
                IsReminderExpired = true;
            }
            else
            {
                IsReminderExpired = false;
            }
            
            NextReminderDate = reminderTmp.NextDate;
        }
        /// <summary>
        /// Speichert den übergebenen Reminder in der lokalen Datenbank ab.
        /// </summary>
        /// <param name="reminder">Das Reminder Objekt mit den Daten des Reminder.</param>
        /// <exception cref="DatabaseException">Wirft eine DatabaseException, wenn das Abspeichern fehlschlägt.</exception>
        public void StoreReminder(Reminder reminder)
        {
            if (reminder == null)
                return;

            // Frage das Mutex Objekt ab.
            Mutex mutex = DatabaseManager.GetDatabaseAccessMutexObject();

            // Fordere Zugriff auf die Datenbank an.
            if (mutex.WaitOne(DatabaseManager.MutexTimeoutValue))
            {
                using (SQLiteConnection conn = DatabaseManager.GetConnection())
                {
                    try
                    {
                        string sql = @"INSERT INTO Reminder (Id, Channel_Id, StartDate, EndDate, CreationDate, 
                            ModificationDate, ""Interval"", ""Ignore"", Title, Text, Priority, Author_Moderator_Id, Active) 
                            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";

                        using (var insertStmt = conn.Prepare(sql))
                        {
                            insertStmt.Bind(1, reminder.Id);
                            insertStmt.Bind(2, reminder.ChannelId);
                            insertStmt.Bind(3, DatabaseManager.DateTimeToSQLite(reminder.StartDate));
                            insertStmt.Bind(4, DatabaseManager.DateTimeToSQLite(reminder.EndDate));
                            insertStmt.Bind(5, DatabaseManager.DateTimeToSQLite(reminder.CreationDate));
                            insertStmt.Bind(6, DatabaseManager.DateTimeToSQLite(reminder.ModificationDate));
                            insertStmt.Bind(7, reminder.Interval);
                            insertStmt.Bind(8, (reminder.Ignore) ? 1 : 0);
                            insertStmt.Bind(9, reminder.Title);
                            insertStmt.Bind(10, reminder.Text);
                            insertStmt.Bind(11, (int)reminder.MessagePriority);
                            insertStmt.Bind(12, reminder.AuthorId);

                            if (reminder.IsActive == null)
                            {
                                insertStmt.Bind(13, reminder.IsActive);
                            }
                            else
                            {
                                insertStmt.Bind(13, (reminder.IsActive == true) ? 1 : 0);
                            }

                            insertStmt.Step();

                            Debug.WriteLine("Stored reminder with id {0}.", reminder.Id);
                        }
                    }
                    catch (SQLiteException sqlEx)
                    {
                        Debug.WriteLine("Couldn't store reminder with id {0}.", reminder.Id);
                        throw new DatabaseException(sqlEx.Message);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine("StoreReminder has failed. The message is: {0} and stack trace is {1}.",
                            ex.Message, ex.StackTrace);
                        throw new DatabaseException(ex.Message);
                    }
                    finally
                    {
                        mutex.ReleaseMutex();
                    }
                }
            }
            else
            {
                Debug.WriteLine("Couldn't get access to database. Time out.");
                throw new DatabaseException("Could not get access to the database.");
            }
        }
        /// <summary>
        /// Aktualisiert den lokalen Datensatz für den übergebenen Reminder.
        /// Schreibt die Werte des übergebenen Objekts als neuen Datensatz anstelle des alten
        /// Datensatzes in die Datenbank.
        /// </summary>
        /// <param name="updatedReminder">Das Reminder Objekt mit den aktualisierten Reminder-Daten.</param>
        /// <exception cref="DatabaseException">Wirft DatabaseException, wenn Update fehlschlägt.</exception>
        public void UpdateReminder(Reminder updatedReminder)
        {
            if (updatedReminder == null)
                return;

            // Frage das Mutex Objekt ab.
            Mutex mutex = DatabaseManager.GetDatabaseAccessMutexObject();

            // Fordere Zugriff auf die Datenbank an.
            if (mutex.WaitOne(DatabaseManager.MutexTimeoutValue))
            {
                using (SQLiteConnection conn = DatabaseManager.GetConnection())
                {
                    try
                    {
                        string sql = @"UPDATE Reminder 
                            SET Channel_Id=?, StartDate=?, EndDate=?, CreationDate=?, ModificationDate=?, 
                            ""Interval""=?, ""Ignore""=?, Title=?, Text=?, Priority=?, Author_Moderator_Id=?, Active=?  
                            WHERE Id=?;";

                        using (var updateStmt = conn.Prepare(sql))
                        {
                            updateStmt.Bind(1, updatedReminder.ChannelId);
                            updateStmt.Bind(2, DatabaseManager.DateTimeToSQLite(updatedReminder.StartDate));
                            updateStmt.Bind(3, DatabaseManager.DateTimeToSQLite(updatedReminder.EndDate));
                            updateStmt.Bind(4, DatabaseManager.DateTimeToSQLite(updatedReminder.CreationDate));
                            updateStmt.Bind(5, DatabaseManager.DateTimeToSQLite(updatedReminder.ModificationDate));
                            updateStmt.Bind(6, updatedReminder.Interval);
                            updateStmt.Bind(7, (updatedReminder.Ignore) ? 1 : 0);
                            updateStmt.Bind(8, updatedReminder.Title);
                            updateStmt.Bind(9, updatedReminder.Text);
                            updateStmt.Bind(10, (int)updatedReminder.MessagePriority);
                            updateStmt.Bind(11, updatedReminder.AuthorId);
                            updateStmt.Bind(12, (updatedReminder.IsActive == true) ? 1 : 0);

                            updateStmt.Bind(13, updatedReminder.Id);

                            if (updateStmt.Step() != SQLiteResult.DONE)
                                Debug.WriteLine("Update for reminder with id {0} has failed.", updatedReminder.Id);
                            else
                                Debug.WriteLine("Successfully updated reminder with id {0}.", updatedReminder.Id);
                        }
                    }
                    catch (SQLiteException sqlEx)
                    {
                        Debug.WriteLine("Update of reminder with id {0} has failed. Msg is: {1}.",
                            updatedReminder.Id,
                            sqlEx.Message);
                        throw new DatabaseException(sqlEx.Message);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine("Update of reminder has failed. The message is: {0} and stack trace is {1}.",
                            ex.Message, ex.StackTrace);
                        throw new DatabaseException(ex.Message);
                    }
                    finally
                    {
                        mutex.ReleaseMutex();
                    }
                }
            }
            else
            {
                Debug.WriteLine("Couldn't get access to database. Time out.");
                throw new DatabaseException("Could not get access to the database.");
            }
        }
        /// <summary>
        /// Hilfsmethode, die eine Speicherung eines Reminders realisiert, bei der 
        /// fehlende Informationen zunächst vom Server abgefragt werden. 
        /// Beachte: Mögliche Fehler werden von dieser Methode nicht zurückgeliefert.
        /// </summary>
        /// <param name="reminder">Der zu speichernde Reminder.</param>
        private async Task storeReminderIncludingRelevantInformationAsync(Reminder reminder)
        {
            Debug.WriteLine("Starting storeReminderIncludingRelevantInformationAsync.");
            try
            {
                List<Moderator> moderators = await GetResponsibleModeratorsAsync(reminder.ChannelId);
                if (moderators == null)
                    return;

                foreach (Moderator moderator in moderators)
                {
                    if (!moderatorDatabaseManager.IsModeratorStored(moderator.Id))
                    {
                        Debug.WriteLine("Need to store moderator with id {0} in local DB.", moderator.Id);
                        moderatorDatabaseManager.StoreModerator(moderator);
                    }

                    if (moderator.IsActive)
                    {
                        if (!channelDatabaseManager.IsResponsibleForChannel(reminder.ChannelId, moderator.Id))
                        {
                            Debug.WriteLine("Need to add moderator with id {0} as responsible moderator for channel with id {1}.",
                                moderator.Id, reminder.ChannelId);
                            channelDatabaseManager.AddModeratorToChannel(reminder.ChannelId, moderator.Id, true);
                        }
                    }
                }

                if (!moderatorDatabaseManager.IsModeratorStored(reminder.AuthorId))
                {
                    // Wenn noch immer der Moderator fehlt, dann bilde ab auf Dummy Moderator.
                    Debug.WriteLine("Need to map author to dummy moderator.");
                    reminder.AuthorId = 0;
                }

                // Speichere reminder.
                channelDatabaseManager.StoreReminder(reminder);
                Debug.WriteLine("Finished storeReminderIncludingRelevantInformationAsync.");
            }
            catch (DatabaseException ex)
            {
                Debug.WriteLine("Fallback method storeReminderIncludingRelevantInformationAsync failed due to database exception." + 
                    "Reminder with id {0} couldn't be stored. Msg is: {1}", reminder.Id, ex.Message);
            }
            catch (ClientException clientEx)
            {
                Debug.WriteLine("Fallback method storeReminderIncludingRelevantInformationAsync failed due to client exception." +
                    "Reminder with id {0} couldn't be stored. ErrorCode is: {1}", reminder.Id, clientEx.ErrorCode);
            }
        }
        /// <summary>
        /// Aktualisiert die für die View relevanten Parameter eines Reminder Objekts, welches aktuell
        /// vom ViewModel gehalten wird.
        /// </summary>
        /// <param name="currentReminder">Die aktuell gehaltene Reminder-Instanz.</param>
        /// <param name="newReminder">Die Reminder-Instanz mit den neuen Daten.</param>
        private void updateViewRelatedPropertiesOfReminder(Reminder currentReminder, Reminder newReminder)
        {
            currentReminder.StartDate = newReminder.StartDate;
            currentReminder.EndDate = newReminder.EndDate;
            currentReminder.Interval = newReminder.Interval;
            currentReminder.Ignore = newReminder.Ignore;
            currentReminder.IsActive = newReminder.IsActive;
            currentReminder.Text = newReminder.Text;
            currentReminder.Title = newReminder.Title;
            currentReminder.MessagePriority = newReminder.MessagePriority;
            currentReminder.ModificationDate = newReminder.ModificationDate;
            currentReminder.AuthorId = newReminder.AuthorId;

            currentReminder.ComputeFirstNextDate();
            currentReminder.EvaluateIsExpired();
        }
        /// <summary>
        /// Erstellt ein Objekt vom Typ Reminder, bei welchem genau die Felder gesetzt sind, die sich 
        /// bei den übergebenen Instanzen geändert haben. Das zurückgelieferte Objekt enthält dabei die aktualisierten
        /// Werte in den geänderten Feldern. Das zurückgegebene Objekt kann direkt für einen Aktualisierungsrequest an den 
        /// Server genutzt werden. Gab es überhaupt keine Änderung so liefert die Methode null zurück.
        /// </summary>
        /// <param name="oldReminder">Das Objekt mit den Daten vor der Aktualisierung.</param>
        /// <param name="newReminder">Das Objekt mit den aktualisierten Werten.</param>
        /// <returns>Ein Objekt vom Typ Reminder, in welchem genau die Felder gesetzt sind, die 
        ///     sich geändert haben. Liefert null, wenn es gar keine Änderung gab.</returns>
        private Reminder createUpdatableReminderInstance(Reminder oldReminder, Reminder newReminder)
        {
            bool hasChanged = false;
            Reminder updatableReminder = new Reminder();

            if (DateTimeOffset.Compare(oldReminder.StartDate, newReminder.StartDate) != 0)
            {
                hasChanged = true;
                updatableReminder.StartDate = newReminder.StartDate;
            }

            if (DateTimeOffset.Compare(oldReminder.EndDate, newReminder.EndDate) != 0)
            {
                hasChanged = true;
                updatableReminder.EndDate = newReminder.EndDate;
            }

            if (oldReminder.Interval != newReminder.Interval)
            {
                hasChanged = true;
                updatableReminder.Interval = newReminder.Interval;
            }

            if (oldReminder.Ignore != newReminder.Ignore)
            {
                hasChanged = true;
                updatableReminder.Ignore = newReminder.Ignore;
            }

            if (oldReminder.Text != newReminder.Text)
            {
                hasChanged = true;
                updatableReminder.Text = newReminder.Text;
            }

            if (oldReminder.Title != newReminder.Title)
            {
                hasChanged = true;
                updatableReminder.Title = newReminder.Title;
            }

            // Beachte: Message Priority muss gesetzt werden, da sonst der Default-Wert beim JSON Parsing
            // in das JSON Dokument geschrieben wird und dadurch ungewollt die Einstellung des Reminder ändern könnte.
            if (oldReminder.MessagePriority != newReminder.MessagePriority)
            {
                hasChanged = true;
                updatableReminder.MessagePriority = newReminder.MessagePriority;
            }
            else
            {
                updatableReminder.MessagePriority = oldReminder.MessagePriority;
            }

            // Prüfe, ob sich überhaupt eine Property geändert hat.
            if (!hasChanged)
            {
                Debug.WriteLine("No Property of reminder has been updated. Method will return null.");
                updatableReminder = null;
            }

            return updatableReminder;
        }
        /// <summary>
        /// Sende Request zum Ändern des Aktivitätszustandes des Reminders mit der angegebenen Id
        /// zum Server. Die Aktualisierung wird auf dem Server vorgenommen.
        /// </summary>
        /// <param name="channelId">Die Id des Kanals zu dem der Reminder gehört.</param>
        /// <param name="reminderId">Die Id des Reminder, dessen Aktivitätszustand geändert werden soll.</param>
        /// <param name="isActive">Der neue Zustand.</param>
        /// <returns>Liefert true, wenn Aktualisierung erfolgreich, ansonsten false.</returns>
        /// <exception cref="ClientException">Wirft ClientException, wenn Aktualisierungsrequest nicht erfolgreich,
        ///     oder ein anderes Problem aufgetreten ist.</exception>
        public async Task<bool> ChangeReminderActiveStatusAsync(int channelId, int reminderId, bool? isActive)
        {
            Moderator activeModerator = GetLocalModerator();
            if (activeModerator == null)
                return false;

            // Erstelle Reminder-Objekt für Aktualisierungsrequest.
            Reminder updatableReminder = new Reminder()
            {
                Id = reminderId,
                ChannelId = channelId,
                IsActive = isActive
            };

            // Generiere Json-Dokument.
            string jsonContent = jsonParser.ParseReminderToJson(updatableReminder);
            if (jsonContent == null)
                return false;

            string serverResponse = null;
            try
            {
                // Sende Request an den Server.
                serverResponse = await channelApi.SendUpdateReminderRequestAsync(
                    activeModerator.ServerAccessToken,
                    channelId,
                    reminderId,
                    jsonContent);
            }
            catch (APIException ex)
            {
                if (ex.ErrorCode == ErrorCodes.ChannelNotFound)
                {
                    Debug.WriteLine("Channel not found on server. Channel probably deleted.");
                    // Behandlung Not Found. Kanal wahrscheinlich gelöscht.
                    MarkChannelAsDeleted(channelId);
                }

                if (ex.ErrorCode == ErrorCodes.ReminderNotFound)
                {
                    Debug.WriteLine("Reminder not found on server. Reminder probably deleted.");
                    // Behandlung von Not Found. Reminder wahrscheinlich gelöscht.
                    DeleteLocalReminder(reminderId);
                }

                Debug.WriteLine("Update request for reminder with id {0} has failed.", reminderId);
                throw new ClientException(ex.ErrorCode, ex.Message);
            }

            // Parse Server Antwort.
            if (serverResponse != null)
            {
                Reminder updatedReminder = jsonParser.ParseReminderFromJson(serverResponse);
                if (updatableReminder != null)
                {
                    // Aktualisiere lokalen Datensatz.
                    ReplaceLocalReminder(updatedReminder);
                }
            }

            return true;
        }
        /// <summary>
        /// Aktualisiert einen Reminder. Ermittelt die zu aktualisierenden Properties und führt einen
        /// Aktualisierungsrequest an den Server aus, um die Ressource zu aktualisieren. Bei einer erfolgreichen
        /// Aktualisierung wird auch der lokal gehaltene Datensatz aktualisiert.
        /// </summary>
        /// <param name="oldReminder">Das Reminder Objekt mit den Daten vor der Aktualisierung.</param>
        /// <param name="newReminder">Das Reminder Objekt mit den aktualisiertern Daten.</param>
        /// <returns>Liefert true, wenn die Aktualisierung erfolgreich durchgeführt werden konnte.
        ///     Liefert false, wenn Aktualisierung fehlgeschlagen ist, z.B. aufgrund eines Validierungsfehlers.</returns>
        /// <exception cref="ClientException">Wirft eine ClientException, wenn ein Fehler während der Aktualisierung auftritt, der
        ///     dem Nutzer gemeldet werden muss, z.B. wenn der Server den Request abgelehnt hat.</exception>
        public async Task<bool> UpdateReminderAsync(Reminder oldReminder, Reminder newReminder)
        {
            if (oldReminder == null || newReminder == null)
                return false;

            Moderator activeModerator = GetLocalModerator();
            if (activeModerator == null)
                return false;

            // Validiere zunächst die neu eingegebenen Daten, bei Validierungsfehlern kann hier gleich abgebrochen werden.
            clearValidationErrors();
            newReminder.ClearValidationErrors();
            newReminder.ValidateAll();
            if (newReminder.HasValidationErrors())
            {
                // Melde Validierungsfehler und breche ab.
                reportValidationErrors(newReminder.GetValidationErrors());
                return false;
            }

            // Erstelle Objekt für Aktualisierungsrequest an den Server.
            Reminder updatableReminder = createUpdatableReminderInstance(oldReminder, newReminder);
            if (updatableReminder == null)
            {
                Debug.WriteLine("No changes in reminder object detected. No update request required.");
                return true;
            }

            // Generiere Json-Dokument.
            string jsonContent = jsonParser.ParseReminderToJson(updatableReminder);
            if (jsonContent == null)
                return false;

            string serverResponse = null;
            try
            {
                // Sende Request an den Server.
                serverResponse = await channelApi.SendUpdateReminderRequestAsync(
                    activeModerator.ServerAccessToken,
                    oldReminder.ChannelId,
                    oldReminder.Id,
                    jsonContent);
            }
            catch (APIException ex)
            {
                if (ex.ErrorCode == ErrorCodes.ChannelNotFound)
                {
                    Debug.WriteLine("Channel not found on server. Channel probably deleted.");
                    // Behandlung Not Found. Kanal wahrscheinlich gelöscht.
                    MarkChannelAsDeleted(oldReminder.ChannelId);
                }

                if (ex.ErrorCode == ErrorCodes.ReminderNotFound)
                {
                    Debug.WriteLine("Reminder not found on server. Reminder probably deleted.");
                    // Behandlung von Not Found. Reminder wahrscheinlich gelöscht.
                    DeleteLocalReminder(oldReminder.Id);
                }

                Debug.WriteLine("Update request for reminder with id {0} has failed.", oldReminder.Id);
                throw new ClientException(ex.ErrorCode, ex.Message);
            }

            // Parse Server Antwort.
            if (serverResponse != null)
            {
                Reminder updatedReminder = jsonParser.ParseReminderFromJson(serverResponse);
                if (updatableReminder != null)
                {
                    ReplaceLocalReminder(updatedReminder);
                }
            }

            return true;
        }
        /// <summary>
        /// Erzeugt einen neuen Reminder. Führt die
        /// Validierung der Daten durch. Überträgt die Reminder-Daten an den Server und
        /// speichert die Daten lokal ab, wenn die Bestätigung vom Server kommt.
        /// </summary>
        /// <param name="newReminder">Das Objekt, welches die Daten des neu anzulegenden
        ///     Reminders beinhaltet.</param>
        /// <returns>Liefert true, wenn Reminder erfolgreich angelegt werden konnte, sonst false.</returns>
        /// <exception cref="ClientException">Wirft ClientException, wenn ein Fehler während des Erstellungsvorgangs auftritt.
        ///     Beispielsweise dann, wenn der Server den Request ablehnt.</exception>
        public async Task<bool> CreateReminderAsync(Reminder newReminder)
        {
            if (newReminder == null)
                return false;

            Moderator activeModerator = GetLocalModerator();
            if (activeModerator == null)
            {
                Debug.WriteLine("No active moderator. Need to abort CreateReminderAsync.");
                return false;
            }

            // Führe Validierung durch.
            clearValidationErrors();
            newReminder.ClearValidationErrors();
            newReminder.ValidateAll();
            if (newReminder.HasValidationErrors())
            {
                // Melde Validierungsfehler und breche ab.
                reportValidationErrors(newReminder.GetValidationErrors());
                return false;
            }

            // Erstelle JSON-Dokument.
            string jsonContent = jsonParser.ParseReminderToJson(newReminder);
            if (jsonContent == null)
            {
                Debug.WriteLine("Couldn't parse reminder to json. Need to abort execution.");
                return false;
            }

            string serverResponse = null;
            try
            {
                // Setzte Request an Server ab.
                serverResponse = await channelApi.SendCreateReminderRequestAsync(
                    activeModerator.ServerAccessToken,
                    newReminder.ChannelId,
                    jsonContent);
            }
            catch (APIException ex)
            {
                if (ex.ErrorCode == ErrorCodes.ChannelNotFound)
                {
                    Debug.WriteLine("Channel not found on server. Channel probably deleted.");
                    // Behandlung Not Found. Kanal wahrscheinlich gelöscht.
                    MarkChannelAsDeleted(newReminder.ChannelId);
                }

                Debug.WriteLine("Request to create reminder has failed.");
                throw new ClientException(ex.ErrorCode, ex.Message);
            }

            // Parse Reminder aus Server-Antwort.
            Reminder createdReminder = jsonParser.ParseReminderFromJson(serverResponse);
            if (createdReminder != null)
            {
                createdReminder.IsActive = true;    // Ist aktiv, wenn er gerade erstellt wurde.
                // Speichere Reminder lokal ab.
                StoreReminder(createdReminder);
            }

            return true;
        }
 /// <summary>
 /// Ersetze die lokal verwaltete Reminderressource durch eine neuere Version
 /// derselben Ressource.
 /// </summary>
 /// <param name="newReminder">Die neuere Version der Reminderressource.</param>
 /// <exception cref="ClientException">Wirft eine ClientException, wenn ein Fehler
 ///     während des Vorgangs auftritt.</exception>
 public void ReplaceLocalReminder(Reminder newReminder)
 {
     try
     {
         channelDatabaseManager.UpdateReminder(newReminder);
     }
     catch (DatabaseException ex)
     {
         Debug.WriteLine("Failed to replace local reminder.");
         throw new ClientException(ErrorCodes.LocalDatabaseException, ex.Message);
     }
 }
 /// <summary>
 /// Speichere den Reminder lokal im Speicher ab.
 /// </summary>
 /// <param name="reminder">Das Reminder Objekt mit den Reminder Daten.</param>
 /// <exception cref="ClientException">Wirft Exception, wenn Speichern fehlschlägt.</exception>
 public void StoreReminder(Reminder reminder)
 {
     try
     {
         if (!moderatorDatabaseManager.IsModeratorStored(reminder.AuthorId))
         {
             Debug.WriteLine("Missing author. Can't store reminder directly. Start fallback method");
             Task.Run(() => storeReminderIncludingRelevantInformationAsync(reminder));
         }
         else
         {
             channelDatabaseManager.StoreReminder(reminder);
         }
     }
     catch (DatabaseException ex)
     {
         Debug.WriteLine("Failed to store reminder.");
         throw new ClientException(ErrorCodes.LocalDatabaseException, ex.Message);
     }
 }
        /// <summary>
        /// Serialisiert ein Objekt vom Typ Reminder in ein JSON-Dokument.
        /// </summary>
        /// <param name="reminder">Das zu serialisierende Objekt.</param>
        /// <returns>Das Objekt in Form eines JSON-Dokument, oder null, wenn die Umwandlung fehlgeschlagen ist.</returns>
        public string ParseReminderToJson(Reminder reminder)
        {
            if (reminder == null)
                return null;

            string jsonContent = null;
            try
            {
                //// Spezielle Serialisierungssettings für Datum.
                //JsonSerializerSettings utcDateSettings = new JsonSerializerSettings();
                //utcDateSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;

                //Newtonsoft.Json.Converters.IsoDateTimeConverter dateConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter
                //{
                //    DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffzz"
                //};
                //utcDateSettings.Converters.Add(dateConverter);

                jsonContent = JsonConvert.SerializeObject(reminder);

                // Anpassung Json Content zwecks Datumsformat.
                string finalJson = string.Empty;
                string[] parts = jsonContent.Split(new string[] { "," }, StringSplitOptions.None);
                foreach (string part in parts)
                {
                    if (part.Contains("startDate") || part.Contains("endDate"))
                    {
                        string[] splittedDate = part.Split(new string[] { ":" }, StringSplitOptions.None);

                        // Füge Teil 1 wieder an, ebenso wie den Doppelpunkt.
                        finalJson += splittedDate[0] + ":";

                        string date = string.Empty;
                        if (splittedDate[0].Contains("\"startDate\""))
                        {
                            // Parse Datum mit eigener Parse Methode.
                            date = "\"" + parseDateTimeToISO8601Format(reminder.StartDate) + "\"";
                        }
                        else if (splittedDate[0].Contains("\"endDate\""))
                        {
                            // Parse Datum mit eigener Parse Methode.
                            date = "\"" + parseDateTimeToISO8601Format(reminder.EndDate) + "\"";
                        }

                        // Füge Datum an.
                        finalJson += date;

                        //finalJson += part.Substring(0, finalJson.Length - 1) +  ".000Z" + part.Substring(finalJson.Length - 1, 1);        // Füge Millisekunden Bereich an.
                    }
                    else
                    {
                        finalJson += part;
                    }
                    finalJson += ",";
                }
                finalJson = finalJson.Substring(0, finalJson.Length - 1);

                Debug.WriteLine("JsonParsingManager: Final json is: {0}", finalJson);

                jsonContent = finalJson;
            }
            catch (JsonException jsonEx)
            {
                Debug.WriteLine("JsonParsingManager: Could not serialize reminder to json.");
                Debug.WriteLine("JsonParsingManager: Message is: {0}.", jsonEx.Message);
            }

            return jsonContent;
        }