public HttpResponseMessage RegisterUser([FromBody]InputUserDto value)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    if (value == null)
                    {
                        throw new ArgumentException("Cannot register an empty user.");
                    }

                    this.ValidateUsername(value.Username);
                    this.ValidatePassword(value.Password);
                    this.ValidateFirstOrLastName(value.FirstName);
                    this.ValidateFirstOrLastName(value.LastName);

                    var db = new BankContext();

                    var user = db.Users.FirstOrDefault(u => u.Username == value.Username);

                    if (user != null)
                    {
                        throw new InvalidOperationException("User already exists.");
                    }

                    var role = db.Roles.FirstOrDefault(r => r.Name == "Private");

                    if (role == null)
                    {
                        throw new InvalidOperationException("No such role.");
                    }

                    user = new User()
                    {
                        Username = value.Username,
                        Password = value.Password,
                        FirstName = value.FirstName,
                        LastName = value.LastName,
                        Role = role
                    };

                    db.Users.Add(user);
                    db.SaveChanges();

                    string sessionKey = this.GenerateSessionKey(user.Id);
                    user.SessionKey = sessionKey;
                    db.SaveChanges();

                    var loggedUser = new LoggedUserDto()
                    {
                        FirstName = user.FirstName,
                        LastName = user.LastName,
                        SessionKey = sessionKey
                    };

                    var response = this.Request.CreateResponse(HttpStatusCode.Created, loggedUser);

                    return response;
                });

            return responseMsg;
        }
        public HttpResponseMessage LoginUser([FromBody]InputUserDto value)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    if (value == null)
                    {
                        throw new ArgumentException("Cannot login an empty user.");
                    }

                    this.ValidateUsername(value.Username);
                    this.ValidatePassword(value.Password);

                    var db = new BankContext();

                    var user = db.Users.FirstOrDefault(
                    u => u.Username == value.Username &&
                        u.Password == value.Password);

                    if (user == null)
                    {
                        throw new InvalidOperationException("Invalid username or password.");
                    }

                    if (user.SessionKey == null || user.SessionKey.Length != SessionKeyLength)
                    {
                        user.SessionKey = this.GenerateSessionKey(user.Id);
                        db.SaveChanges();
                    }

                    var loggedUser = new LoggedUserDto()
                    {
                        FirstName = user.FirstName,
                        LastName = user.LastName,
                        Role = user.Role,
                        SessionKey = user.SessionKey
                    };

                    var response = this.Request.CreateResponse(HttpStatusCode.Accepted, loggedUser);

                    return response;
                });

            return responseMsg;
        }
        public HttpResponseMessage UpdateUser(InputUserDto value)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
            () =>
            {
                var db = new BankContext();
                var user = this.ValidateAndGetLoggedUser(db);

                if (!ModelState.IsValid)
                {
                    throw new InvalidOperationException("Invalid model state.");
                }

                Role role = null;
                if (value.RoleId.HasValue)
                {
                    role = db.Roles.FirstOrDefault(r => r.Id == value.RoleId);
                    if (role == null)
                    {
                        throw new ArgumentException("No such role.");
                    }
                }

                user.UpdateWith(new User
                {
                    FirstName = value.FirstName,
                    LastName = value.LastName,
                    Role = role
                });

                db.Entry(user).State = EntityState.Modified;
                db.SaveChanges();

                var response = new HttpResponseMessage(HttpStatusCode.NoContent);
                return response;
            });

            return responseMsg;
        }
        public HttpResponseMessage LogoutUser()
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
            () =>
            {
                var db = new BankContext();
                var user = this.ValidateAndGetLoggedUser(db);

                user.SessionKey = null;
                db.SaveChanges();

                var response = new HttpResponseMessage(HttpStatusCode.NoContent);
                return response;
            });

            return responseMsg;
        }
        public HttpResponseMessage MakeTransfer(InputTransactionLogDto transaction)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
            () =>
            {
                var db = new BankContext();
                var user = this.ValidateAndGetLoggedUser(db);

                var fromAccount = db.Accounts.FirstOrDefault(a => a.Iban == transaction.FromAccountIban);
                if (fromAccount == null)
                {
                    throw new ArgumentException(
                        string.Format("Account with id = {0} doesn't exist.", transaction.FromAccountIban));
                }

                if (fromAccount.User.Id != user.Id)
                {
                    throw new InvalidOperationException(
                        string.Format(
                        "Current user has id = {0} but the account belongs to user with id = {1}.",
                        user.Id,
                        fromAccount.User.Id));
                }

                Currency currency = null;
                if (transaction.CurrencyId.HasValue)
                {
                    currency = db.Currencies.FirstOrDefault(c => c.Id == transaction.CurrencyId.Value);
                    if (currency == null)
                    {
                        throw new ArgumentException("No such currency.");
                    }
                }
                else
                {
                    currency = fromAccount.Currency;
                }

                Account toAccount = null;
                string toIban = null;
                string description = null;
                if (transaction.ToAccountIban != "")
                {
                    toAccount = db.Accounts.FirstOrDefault(a => a.Iban == transaction.ToAccountIban);
                    if (toAccount == null)
                    {
                        throw new ArgumentException("No such destination account.");
                    }

                    if (toAccount.User.Id != user.Id)
                    {
                        throw new InvalidOperationException(
                            string.Format(
                            "Current user has id = {0} but the destination account belongs to user with id = {1}.",
                            user.Id,
                            toAccount.User.Id));
                    }
                    description = "Transfer between user's accounts.";
                    toIban = toAccount.Iban;

                    toAccount.Balance += transaction.Amount;
                    db.Entry(toAccount).State = EntityState.Modified;
                }

                fromAccount.Balance -= transaction.Amount;
                db.Entry(fromAccount).State = EntityState.Modified;

                db.SaveChanges();

                if (toAccount == null)
                {
                    description = "Transfer to an external account.";
                    toIban = transaction.toIban;
                }

                db.TransactionLogs.Add(new TransactionLog
                {
                    Amount = transaction.Amount,
                    Currency = currency,
                    Timestamp = DateTime.Now,
                    FromAccount = fromAccount,
                    ToIban = toIban,
                    Description = description
                });

                db.SaveChanges();

                var response = new HttpResponseMessage(HttpStatusCode.NoContent);
                return response;
            });

            return responseMsg;
        }
        public HttpResponseMessage CreateAccount([FromBody]InputAccountDto value)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    var db = new BankContext();
                    var user = this.ValidateAndGetLoggedUser(db);

                    var currency = db.Currencies.FirstOrDefault(c => c.Id == value.CurrencyId);
                    if (currency == null)
                    {
                        throw new ArgumentException("No such currency.");
                    }

                    var accountType = db.AccountTypes.FirstOrDefault(at => at.Id == value.TypeId);
                    if (accountType == null)
                    {
                        throw new ArgumentException("No such account type.");
                    }

                    if (ModelState.IsValid)
                    {
                        string iban = this.GenerateIban();
                        decimal interestRate = value.InterestRate ?? 7.8M;

                        var account = new Account
                        {
                            Iban = iban,
                            InterestRate = interestRate,
                            Balance = value.Balance.Value,
                            Description = value.Description,
                            Currency = currency,
                            Type = accountType,
                            User = user
                        };

                        db.Accounts.Add(account);
                        user.Accounts.Add(account);
                        db.SaveChanges();

                        var createdAccountDto = new OutputAccountDto()
                        {
                            Id = account.Id,
                            Iban = account.Iban,
                            InterestRate = account.InterestRate,
                            Balance = account.Balance,
                            Description = account.Description,
                            Currency = account.Currency,
                            Type = account.Type
                        };

                        var response = Request.CreateResponse(HttpStatusCode.Created, createdAccountDto);
                        return response;
                    }
                    else
                    {
                        throw new ApplicationException("Invalid model state.");
                    }
                });

            return responseMsg;
        }
        public HttpResponseMessage UpdateAccount(int id, InputAccountDto value)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
            () =>
            {
                var db = new BankContext();
                var user = this.ValidateAndGetLoggedUser(db);

                if (!ModelState.IsValid)
                {
                    throw new InvalidOperationException("Invalid model state.");
                }

                var accountToUpdate = db.Accounts.FirstOrDefault(a => a.Id == id);
                if (accountToUpdate == null)
                {
                    throw new ArgumentException(
                        string.Format("Account with id = {0} doesn't exist.", id));
                }

                //if (accountToUpdate.User.Id != user.Id)
                //{
                //    throw new InvalidOperationException(
                //        string.Format(
                //        "Current user has id = {0} but the account belongs to user with id = {1}.",
                //        user.Id,
                //        accountToUpdate.User.Id));
                //}

                decimal interestRate = value.InterestRate ?? 0.0M;

                Currency currency = null;
                if (value.CurrencyId.HasValue)
                {
                    currency = db.Currencies.FirstOrDefault(c => c.Id == value.CurrencyId);
                    if (currency == null)
                    {
                        throw new ArgumentException("No such currency.");
                    }
                }

                AccountType type = null;
                if (value.TypeId.HasValue)
                {
                    type = db.AccountTypes.FirstOrDefault(at => at.Id == value.TypeId);
                    if (type == null)
                    {
                        throw new ArgumentException("No such account type.");
                    }
                }

                accountToUpdate.UpdateWith(new Account
                {
                    InterestRate = interestRate,
                    Description = value.Description,
                    Currency = currency,
                    Type = type
                });

                db.Entry(accountToUpdate).State = EntityState.Modified;
                db.SaveChanges();

                var response = new HttpResponseMessage(HttpStatusCode.NoContent);
                return response;
            });

            return responseMsg;
        }