/// <summary>
        /// Aktualisiert den Nutzernamen des lokalen Nutzers der Anwendung, falls eine Änderung
        /// gegenüber dem aktuellen Nutzernamen vorliegt. Die Aktualisierung erfolgt sowohl lokal, 
        /// als auch auf dem REST Server.
        /// </summary>
        /// <param name="username">Der neue Nutzername des lokalen Nutzers.</param>
        /// <exception cref="ClientException">Wirft ClientException, wenn Aktualisierung nicht durchgeführt werden konnte.</exception>
        public async Task<bool> UpdateLocalUsernameAsync(string username)
        {
            User currentLocalUser = base.getLocalUser();

            // Prüfe, ob der Name aktualisiert werden muss.
            if(String.Compare(currentLocalUser.Name, username) != 0)
            {
                // Setze neuen Namen in ein Nutzer Objekt und führe Eingabevalidierung durch.
                User tmpLocalUser = new User();
                tmpLocalUser.Name = username;

                tmpLocalUser.ValidateNameProperty();
                if(tmpLocalUser.HasValidationError("Name"))
                {
                    // Melde Validationsfehler und breche ab.
                    base.reportValidationErrors(tmpLocalUser.GetValidationErrors());
                    return false;
                }
                else
                {
                    tmpLocalUser.ClearValidationErrors();
                    base.clearValidationErrorForProperty("Name");
                }

                // Verwende Funktionalität im LocalUserController, um die Aktualisierung des Namens durchzuführen.
                await localUserController.UpdateLocalUserAsync(username, null);
            }
            return true;
        }
 /// <summary>
 /// Erzeugt ein JSON-Dokument aus dem übergebenen User-Objekt.
 /// </summary>
 /// <param name="user">Das zu serialisierende User Objekt.</param>
 /// <returns>Ein generiertes JSON-Dokument mit den Nutzerdaten, oder null falls Serialisierung fehlschlägt.</returns>
 public string ParseUserToJsonString(User user)
 {
     string jsonContent = null;
     try
     {
         jsonContent = JsonConvert.SerializeObject(user);
     }
     catch (JsonException ex)
     {
         Debug.WriteLine("JsonParsingManager: Error during serialization of user object. " +
             "Exception is: " + ex.Message);
     }
     return jsonContent;
 }
 /// <summary>
 /// Speichert einen Datensatz einer Nutzer-Ressource lokal ab.
 /// </summary>
 /// <param name="user">Der zu speichernde Datensatz in Form eines Nutzer Objekts.</param>
 /// <exception cref="ClientException">Wirft ClientException, wenn Speicherung fehlschlägt.</exception>
 public void StoreUserLocally(User user)
 {
     try
     {
         userDBManager.StoreUser(user);
     }
     catch (DatabaseException ex)
     {
         Debug.WriteLine("StoreUserLocally: Failed to store the user in local DB. Msg is {0}.", ex.Message);
         throw new ClientException(ErrorCodes.LocalDatabaseException, ex.Message);
     }
 }
        /// <summary>
        /// Erstelle einen lokalen Nutzeraccount.
        /// </summary>
        /// <param name="name">Der Name für den Nutzer.</param>
        /// <returns>Liefert true zurück, wenn der Account erfolgreich angelegt wurde. False, wenn die Validierung fehlgeschlagen hat.</returns>
        /// <exception cref="ClientException">Wirft eine ClientException, wenn die Erstellung des Nutzeraccounts wegen eines aufgetretenen Fehlers fehlschlägt.</exception>
        public async Task<bool> CreateLocalUserAsync(string name)
        {
            Debug.WriteLine("Starting createLocalUser().");

            // TODO: Platziere diesen Code woanders und gebe ihn über einen Parameter an diese Methode.
            // Frage eine Kanal-URI vom WNS ab, die dann als PushAccessToken für diesen Nutzer dient.
            PushNotificationChannel pushChannel = null;
            try {
                pushChannel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
                Debug.WriteLine("Received a channel URI: " + pushChannel.Uri);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception occurred in CreateLocalUserAsync during WNS initialization. The message is: {0}.", ex.Message);
                // Abbilden auf ClientException.
                throw new ClientException(ErrorCodes.WnsChannelInitializationFailed, "Initialization of channel to WNS has failed.");
            }

            User localUser = new User();
            localUser.Name = name;
            localUser.PushAccessToken = pushChannel.Uri;
            localUser.Platform = DataHandlingLayer.DataModel.Enums.Platform.WINDOWS;

            // Führe Datenvalidierung auf Property Name aus.
            localUser.ClearValidationErrors();  
            clearValidationErrorForProperty("Name");

            localUser.ValidateNameProperty();
            if(localUser.HasValidationError("Name"))
            {
                reportValidationErrors(localUser.GetValidationErrors());
                return false;
            }

            // Generiere Json String aus dem Objekt.
            string jsonContent = jsonParser.ParseUserToJsonString(localUser);
            Debug.WriteLine("The json String is: " + jsonContent);
            if (jsonContent == null)
            {
                Debug.WriteLine("Error during serialization to json. Cannot continue.");
                throw new ClientException(ErrorCodes.JsonParserError, "Creation of user account has failed.");
            }

            // Sende einen Request zum Erstellen eines Nutzeraccounts.
            string responseString;
            try
            {
                responseString = await userAPI.SendCreateUserRequestAsync(jsonContent);
            }
            catch (APIException e)
            {
                Debug.WriteLine("Error occured. The creation of the user account has failed.");
                Debug.WriteLine("The error code is: " + e.ErrorCode + " and the status code of the response is: " + e.ResponseStatusCode);
                // Abbilden des aufgetretenen Fehlers auf eine ClientException.
                throw new ClientException(e.ErrorCode, "Creation of user account has failed.");
            }

            // Deserialisiere den Antwort String des Servers.
            localUser = jsonParser.ParseUserFromJson(responseString);

            // Speichere den erstellten Nutzeraccount in der Datenbank ab.
            if (localUser != null)
            {
                try
                {
                    localUserDB.StoreLocalUser(localUser);
                }
                catch (DatabaseException ex)
                {
                    Debug.WriteLine("A exception occurred in the local database. Exception message is: " + ex.Message);
                    // Abbilden des aufgetretenen Fehlers auf eine ClientException.
                    throw new ClientException(ErrorCodes.LocalDatabaseException, "Creation of user account has failed.");
                }
            }
            else
            {
                // Abbilden des aufgetretenen Fehlers auf eine ClientException.
                throw new ClientException(ErrorCodes.JsonParserError, "Creation of user account has failed.");
            }

            Debug.WriteLine("Finished createLocalUser().");
            return true;
        }
        /// <summary>
        /// Fügt den übergebenen Nutzer als aktiven Nutzer der Gruppe mit der angegebenen Id hinzu.
        /// </summary>
        /// <param name="groupId">Die Id der Gruppe.</param>
        /// <param name="user">Der hinzuzufügende Nutzer.</param>
        /// <exception cref="ClientException">Wirft ClientException, wenn Aktion fehlschlägt.</exception>
        public void AddParticipantToGroup(int groupId, User user)
        {
            if (!groupDBManager.IsGroupStored(groupId))
            {
                Debug.WriteLine("AddParticipantToGroup: There is no group with id {0} in the local datasets.",
                    groupId);

                throw new ClientException(ErrorCodes.GroupNotFound, "Cannot continue without stored group.");
            }

            // Prüfe, ob der Nutzer schon in den lokalen Datensätzen gespeichert ist.
            bool stored = userController.IsUserLocallyStored(user.Id);
            if (!stored)
            {
                userController.StoreUserLocally(user);
            }

            // Füge Nutzer als aktiver Teilnehmer der Gruppe hinzu.
            try
            {
                bool? activeStatus = groupDBManager.RetrieveActiveStatusOfParticipant(groupId, user.Id);
                if (!activeStatus.HasValue)
                {
                    // Teilnehmer noch nicht in Gruppe.
                    groupDBManager.AddParticipantToGroup(groupId, user.Id, true);
                }
                else if (activeStatus.Value == false)
                {
                    // Setze Teilnehmer wieder in den aktiven Zustand.
                    groupDBManager.ChangeActiveStatusOfParticipant(groupId, user.Id, true);
                }
            }
            catch (DatabaseException ex)
            {
                Debug.WriteLine("AddParticipantToGroup: Failed to add participant to group. Msg is {0}.", ex.Message);
                throw new ClientException(ErrorCodes.LocalDatabaseException, ex.Message);
            }
        }
        /// <summary>
        /// Erzeugt eine Instanz der Klasse GroupDetailsViewModel.
        /// </summary>
        /// <param name="navService">Eine Referenz auf den Navigationsdienst der Anwendung.</param>
        /// <param name="errorMapper">Eine Referenz auf den Fehlerdienst der Anwendung.</param>
        public GroupDetailsViewModel(INavigationService navService, IErrorMapper errorMapper)
            : base(navService, errorMapper)
        {
            // Erzeuge Controller-Instanz.
            groupController = new GroupController(this);

            IsGroupParticipant = false;
            HasLeaveOption = false;

            localUser = groupController.GetLocalUser();

            if (BallotCollection == null)
                BallotCollection = new ObservableCollection<Ballot>();

            if (ConversationCollection == null)
                ConversationCollection = new ObservableCollection<Conversation>();

            // Erzeuge Befehle.
            JoinGroupCommand = new AsyncRelayCommand(
                param => executeJoinGroupCommandAsync(),
                param => canJoinGroup());
            LeaveGroupCommand = new AsyncRelayCommand(
                param => executeLeaveGroupCommandAsync(),
                param => canLeaveGroup());
            EditGroupCommand = new RelayCommand(
                param => executeEditGroupCommand(),
                param => canEditGroup());
            ConversationSelectedCommand = new RelayCommand(
                param => executeConversationSelectedCommand(param));
            SynchronizeDataCommand = new AsyncRelayCommand(
                param => executeSynchronizeDataCommandAsync(),
                param => canSynchronizeData());
            DeleteGroupCommand = new AsyncRelayCommand(
                param => executeDeleteGroupAsync(),
                param => canDeleteGroup());
            DeleteGroupLocallyCommand = new RelayCommand(
                param => executeDeleteGroupLocallyCommand(),
                param => canDeleteGroupLocally());
            ChangeToGroupSettingsCommand = new RelayCommand(
                param => executeChangeToGroupSettingsCommand(),
                param => canChangeToGroupSettings());
            ChangeToAddConversationDialog = new RelayCommand(
                param => executeChangeToAddConversationDialog(),
                param => canChangeToAddConversationDialog());
            BallotSelectedCommand = new RelayCommand(
                param => executeBallotSectedCommand(param));
            SwitchToCreateBallotDialogCommand = new RelayCommand(
                param => executeSwitchToCreateBallotDialogCommand(),
                param => canSwitchToCreateBallotDialog());
            SwichToGroupParticipantsViewCommand = new RelayCommand(
                param => executeSwitchToGroupParticipantsView(),
                param => canSwitchToGroupParticipantsView());
        }
        /// <summary>
        /// Lädt die Abstimmungsergebnisse der gewählten Abstimmung und bereitet deren Anzeige vor. 
        /// </summary>
        public async Task LoadBallotOptionResultsAsync()
        {
            if (SelectedBallot == null || AffectedGroup == null)
                return;

            List<VoteResult> voteResults = new List<VoteResult>();
            try
            {
                List<Option> options = await Task.Run(() => groupController.GetOptions(SelectedBallot.Id, true));
                Dictionary<int, User> groupParticipants = await Task.Run(() => groupController.GetParticipantsLookupDirectory(AffectedGroup.Id));

                int totalAmountOfVotes = 0;
                foreach (Option option in options)
                {
                    VoteResult result = new VoteResult()
                    {
                        OptionId = option.Id,
                        OptionText = option.Text,
                        IsLastVoteResultInList = false
                    };

                    if (SelectedBallot.HasPublicVotes.HasValue)
                    {
                        result.IsPublic = SelectedBallot.HasPublicVotes.Value;
                    }

                    if (option.VoterIds != null)
                    {
                        // Setze Anzahl Stimmen.
                        result.VoteCount = option.VoterIds.Count;

                        // Addiere Anzahl Stimmen auf Gesamtzahl auf.
                        totalAmountOfVotes += option.VoterIds.Count;

                        if (result.IsPublic)
                        {
                            List<User> voters = new List<User>();

                            foreach (var voter in option.VoterIds)
                            {
                                if (groupParticipants.ContainsKey(voter))
                                {
                                    voters.Add(groupParticipants[voter]);
                                }
                                else
                                {
                                    User dummy = new User()
                                    {
                                        Name = "Unknown user"
                                    };
                                    voters.Add(dummy);
                                }
                            }

                            // Generiere String mit Nutzern, die abgestimmt haben.
                            result.GenerateVoterNamesString(voters);
                        }
                    }

                    voteResults.Add(result);
                }

                // Berechne Abstimmungsergebnis.
                foreach (VoteResult result in voteResults)
                {
                    result.CalculateVoteResultInPercentage(totalAmountOfVotes);
                }

                // Lade Collection.
                VoteResultsCollection = new ObservableCollection<VoteResult>(voteResults);

                if (VoteResultsCollection.Count > 0)
                    VoteResultsCollection.Last<VoteResult>().IsLastVoteResultInList = true;
            }
            catch (ClientException ex)
            {
                Debug.WriteLine("LoadBallotOptionResultsAsync: Loading failed. Message is {0}.", ex.Message);
                displayError(ex.ErrorCode);
            }
        }
        /// <summary>
        /// Erzeugt eine Instanz der Klasse BallotDetailsViewModel.
        /// </summary>
        /// <param name="navService">Eine Referenz auf den Navigationsdienst der Anwendung.</param>
        /// <param name="errorMapper">Eine Referenz auf den Fehlerdienst der Anwendung.</param>
        public BallotDetailsViewModel(INavigationService navService, IErrorMapper errorMapper)
            : base (navService, errorMapper)
        {
            groupController = new GroupController(this);
            localUser = groupController.GetLocalUser();

            if (BallotOptionCollection == null)
                BallotOptionCollection = new ObservableCollection<Option>();

            if (VoteResultsCollection == null)
                VoteResultsCollection = new ObservableCollection<VoteResult>();

            PlaceVotesCommand = new AsyncRelayCommand(
                param => executePlaceVotesCommand(),
                param => canPlaceVotes());
            SynchronizeBallotCommand = new AsyncRelayCommand(
                param => executeSynchronizeBallotCommand(),
                param => canSynchronizeBallot());
            SwitchToEditDialogCommand = new RelayCommand(
                param => executeSwitchToEditDialogCommand(),
                param => canSwitchToEditDialog());
            DeleteBallotCommand = new AsyncRelayCommand(
                param => executeDeleteBallotAsync(),
                param => canDeleteBallot());
        }
        /// <summary>
        /// Ruft das Nutzerobjekt ab, das über die angegebene Id identifiziert wird.
        /// Im Objekt sind jedoch nur die Eigenschaften Id und Name gesetzt.
        /// </summary>
        /// <param name="userId">Die Id des Nutzers.</param>
        /// <returns>Ein Objekt vom Typ User.</returns>
        /// <exception cref="DatabaseException">Wirft DatabaseException, falls Abruf fehlschlägt.</exception>
        public User GetUser(int userId)
        {
            User user = 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 query = @"SELECT * 
                            FROM User 
                            WHERE Id=?;";

                        using (var stmt = conn.Prepare(query))
                        {
                            stmt.Bind(1, userId);

                            if (stmt.Step() == SQLiteResult.ROW)
                            {
                                user = new User()
                                {
                                    Id = userId,
                                    Name = (string)stmt["Name"]
                                };
                            }
                        }
                    }
                    catch (SQLiteException sqlEx)
                    {
                        Debug.WriteLine("GetUser: SQLiteException occurred. Msg is {0}.", sqlEx.Message);
                        throw new DatabaseException(sqlEx.Message);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine("GetUser: Exception occurred. Msg is {0}.", ex.Message);
                        throw new DatabaseException(ex.Message);
                    }
                    finally
                    {
                        mutex.ReleaseMutex();
                    }
                }
            }
            else
            {
                Debug.WriteLine("GetUser: Mutex timeout.");
                throw new DatabaseException("GetUser: Timeout: Failed to get access to DB.");
            }

            return user;
        }
        /// <summary>
        /// Speichert einen Nutzerdatensatz in der Datenbank ab.
        /// </summary>
        /// <param name="user">Der zu speichernde Datensatz als Objekt der Klasse User.</param>
        /// <exception cref="DatabaseException">Wirft DatabaseException, wenn Speichern fehlschlägt.</exception>
        public void StoreUser(User user)
        {
            // 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 query = @"INSERT INTO User (Id, Name) 
                            VALUES (?, ?);";

                        using (var stmt = conn.Prepare(query))
                        {
                            stmt.Bind(1, user.Id);
                            stmt.Bind(2, user.Name);

                            if (stmt.Step() != SQLiteResult.DONE)
                                Debug.WriteLine("Failed to store user with id {0} to database.", user.Id);
                            else
                                Debug.WriteLine("Successfully stored user with id {0} to database.", user.Id);
                        }

                    }
                    catch (SQLiteException sqlEx)
                    {
                        Debug.WriteLine("StoreUser: SQLiteException occurred. Message is {0}.", sqlEx.Message);
                        throw new DatabaseException(sqlEx.Message);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine("StoreUser: Exception occurred. Message is {0}.", ex.Message);
                        throw new DatabaseException(ex.Message);
                    }
                    finally
                    {
                        mutex.ReleaseMutex();
                    }
                }
            }
        }
 /// <summary>
 /// Speichert die Referenz auf das lokale Nutzerobjekt im Speicherbereich der Singleton-Klasse LocalUser,
 /// so dass es zur Laufzeit der Anwendung aus diesem Speicher abgefragt werden kann.
 /// </summary>
 /// <param name="localUser">Das Objekt der Klasse User, welches gespeichert werden soll.</param>
 public void CacheLocalUserObject(User localUser)
 {
     this.localUser = localUser;
 }