public HttpResponseMessage AddImage(
            int placeId,
            ImageModel imageModel,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    using (context)
                    {
                        var user = UsersController.GetUserBySessionKey(context, sessionKey);
                        var place = GetAllPlaces(context).FirstOrDefault(p => p.Id == placeId);
                        place.Images.Add(new Image()
                        {
                            Url = imageModel.ImageUrl,
                            Place = place,
                            User = user
                        });
                        context.SaveChanges();

                        return this.Request.CreateResponse(HttpStatusCode.NoContent);
                    }
                });

            return responseMsg;
        }
        public HttpResponseMessage AddComment(
            int placeId,
            CommentModel commentModel,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    using (context)
                    {
                        var user = UsersController.GetUserBySessionKey(context, sessionKey);
                        var place = context.Places.FirstOrDefault(p => p.Id == placeId);
                        if (place == null)
                        {
                            throw new ArgumentNullException("place", "A place with the specified ID does not exist.");
                        }

                        place.Comments.Add(new Comment()
                        {
                            Content = commentModel.Content,
                            Date = DateTime.Now,
                            Place = place,
                            User = user,
                        });
                        context.SaveChanges();

                        return this.Request.CreateResponse(HttpStatusCode.OK, commentModel);
                    }
                });

            return responseMsg;
        }
        public HttpResponseMessage CreateComment(CommentModel commentModel, int id,
           [ValueProvider(typeof(HeaderValueProviderFactory<string>))] string sessionKey)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    using (context)
                    {
                        var user = UsersController.GetUserBySessionKey(context, sessionKey);
                        var place = context.Places.FirstOrDefault(p => p.Id == id);

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

                        var comment = new Comment()
                        {
                            Content = commentModel.Content,
                            Date = DateTime.Now,
                            User = user
                        };

                        place.Comments.Add(comment);
                        context.SaveChanges();

                        var createdComment = new CommentModel()
                        {
                            Date = comment.Date,
                            Content = comment.Content,
                            PostedBy = comment.User.Nickname
                        };

                        var response = this.Request.CreateResponse(HttpStatusCode.Created, createdComment);
                        return response;
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage PostTown(TownModel model, [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
                                               string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    var context = new PlacesContext();

                    using (context)
                    {
                        Town townEntity = new Town();
                        CountrySmallModel countryModel = new CountrySmallModel();
                        var countryEntity = context.Countries.Where(c => c.Id == model.CountryId).FirstOrDefault();

                        if (countryEntity != null)
                        {
                            countryModel.Id = countryEntity.Id;
                            countryModel.Name = countryEntity.Name;
                            townEntity.Country = countryEntity;
                        }
                        else
                        {
                            throw new ArgumentException("No town with this id was found");
                        }

                        townEntity.Name = model.Name;
                        context.Towns.Add(townEntity);
                        context.SaveChanges();

                        // get the id from the entity added in the db
                        model.Id = townEntity.Id;

                        return this.Request.CreateResponse(HttpStatusCode.Created, model);
                    }
                }
            );

            return responseMsg;
        }
        public HttpResponseMessage LoginUser(UserRegisteredModel userModel)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    using (context)
                    {
                        this.ValidateUsername(userModel.Username);
                        this.ValidateAuthCode(userModel.AuthCode);

                        string usernameToLower = userModel.Username.ToLower();

                        User existingUser = context.Users
                                                   .FirstOrDefault(u => u.Username.ToLower() == usernameToLower);
                        if (existingUser == null)
                        {
                            throw new ArgumentNullException("The user does not exist.");
                        }

                        if (existingUser.SessionKey == null)
                        {
                            existingUser.SessionKey = this.GenerateSessionKey(existingUser.Id);
                            context.SaveChanges();
                        }

                        UserLoggedInModel loggedUser = new UserLoggedInModel()
                        {
                            Nickname = existingUser.Nickname,
                            SessionKey = existingUser.SessionKey
                        };

                        return this.Request.CreateResponse(HttpStatusCode.Created, loggedUser);
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage RegisterUser(UserRegisteredModel userModel)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    using (context)
                    {
                        this.ValidateUsername(userModel.Username);
                        this.ValidateNickname(userModel.Nickname);
                        this.ValidateAuthCode(userModel.AuthCode);

                        string usernameToLower = userModel.Username.ToLower();
                        string nicknameToLower = userModel.Nickname.ToLower();

                        User user = context.Users
                                           .FirstOrDefault(u => u.Username.ToLower() == usernameToLower ||
                                                                u.Nickname == nicknameToLower);
                        if (user != null)
                        {
                            throw new InvalidOperationException("The user already exists.");
                        }

                        user = new User()
                        {
                            Username = usernameToLower,
                            Nickname = userModel.Nickname,
                            AuthCode = userModel.AuthCode,
                            Role = Role.User
                        };
                        context.Users.Add(user);
                        context.SaveChanges();

                        user.SessionKey = this.GenerateSessionKey(user.Id);
                        context.SaveChanges();

                        UserLoggedInModel loggedInUser = new UserLoggedInModel()
                        {
                            Nickname = user.Nickname,
                            SessionKey = user.SessionKey
                        };

                        return this.Request.CreateResponse(HttpStatusCode.Created, loggedInUser);
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage PutUser([FromBody] UserEditModel userEditModel, [FromUri]int id, [ValueProvider(typeof(HeaderValueProviderFactory<string>))] string sessionKey)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    using (context)
                    {
                        User existingUser = GetUserBySessionKey(context, sessionKey);

                        if (existingUser == null)
                        {
                            throw new ArgumentNullException("The user does not exist or is already logged out.");
                        }

                        // check if user is admin
                        if (existingUser.Role != Role.Admin)
                        {
                            throw new InvalidOperationException("User is not admin and cannot see admin information.");
                        }

                        User editedUser = context.Users.Find(userEditModel.Id);

                        if (editedUser == null)
                        {
                            throw new ArgumentNullException(String.Format("Invalid user id: {0}. User not found.", userEditModel.Id));
                        }

                        if (ModelState.IsValid && id == userEditModel.Id)
                        {
                            editedUser.Nickname = userEditModel.Nickname;
                            editedUser.Role = (Role)userEditModel.Role;

                            context.Entry(editedUser).State = EntityState.Modified;

                            try
                            {
                                context.SaveChanges();
                            }
                            catch (DbUpdateConcurrencyException)
                            {
                                return Request.CreateResponse(HttpStatusCode.NotFound);
                            }

                            return Request.CreateResponse(HttpStatusCode.NoContent);
                        }
                        else
                        {
                            return Request.CreateResponse(HttpStatusCode.BadRequest);
                        }
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage LogoutUser(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    using (context)
                    {
                        User existingUser = context.Users
                                                   .FirstOrDefault(u => u.SessionKey == sessionKey);
                        if (existingUser == null)
                        {
                            throw new ArgumentNullException("The user does not exist or is already logged out.");
                        }

                        existingUser.SessionKey = null;
                        context.SaveChanges();

                        return this.Request.CreateResponse(HttpStatusCode.NoContent);
                    }
                });

            return responseMessage;
        }
        // POST api/Country
        public HttpResponseMessage PostCountry(
            CountrySmallModel countryModel,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMessage = PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    var country = new Country()
                    {
                        Name = countryModel.Name,
                        Id = countryModel.Id
                    };

                    if (!context.Countries.Any(c => c.Name.ToLower() == countryModel.Name.ToLower()))
                    {
                        context.Countries.Add(country);
                        context.SaveChanges();
                    }

                    countryModel.Id = country.Id;
                    return this.Request.CreateResponse(HttpStatusCode.Created, countryModel);
                });

            return responseMessage;
        }
        public HttpResponseMessage PostPlace(
            PlaceModel placeModel,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    using (context)
                    {
                        var user = UsersController.GetUserBySessionKey(context, sessionKey);
                        if (user.Role != Role.Admin)
                        {
                            throw new InvalidOperationException("User is not admin and cannot see admin information.");
                        }

                        var place = new Place();
                        place.Name = placeModel.Name;
                        place.User = user;
                        if (placeModel.TownId != 0)
                        {
                            var contextTown = context.Towns.Find(placeModel.TownId);
                            if (contextTown != null)
                            {
                                place.Town = contextTown;
                            }
                            else
                            {
                                throw new ArgumentNullException("town", "The town does not exist.");
                            }
                        }

                        place.Content = placeModel.Content;
                        if (placeModel.ImageUrls != null)
                        {
                            foreach (var imageUrl in placeModel.ImageUrls)
                            {
                                place.Images.Add(new Image()
                                {
                                    Place = place,
                                    Url = imageUrl,
                                    User = user
                                });
                            }
                        }

                        context.Places.Add(place);
                        context.SaveChanges();
                        placeModel.Id = place.Id;
                    }
                    return this.Request.CreateResponse(HttpStatusCode.Created, placeModel);
                });

            return responseMsg;
        }