public HttpResponseMessage RegisterUser(UserRegisterModel model)
        {
            var responseMsg = this.ExceptionHandler(
                () =>
                {
                    var context = new ForumContext();

                    using (context)
                    {
                        UserDataPersister.ValidateUsername(model.Username);
                        UserDataPersister.ValidateNickname(model.Nickname);
                        UserDataPersister.ValidateAuthCode(model.AuthCode);

                        var usernameToLower = model.Username.ToLower();
                        var nicknameToLower = model.Nickname.ToLower();

                        var user = context.Users.FirstOrDefault(
                            usr => usr.Username == usernameToLower || usr.Nickname.ToLower() == nicknameToLower);

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

                        var newUser = new User
                        {
                            Username = usernameToLower,
                            Nickname = model.Nickname,
                            AuthCode = model.AuthCode
                        };

                        context.Users.Add(newUser);
                        context.SaveChanges();

                        newUser.SessionKey = UserDataPersister.GenerateSessionKey(newUser.Id);
                        context.SaveChanges();


                        var loggedModel = new LoggedUserModel
                        {
                            Nickname = newUser.Nickname,
                            SessionKey = newUser.SessionKey
                        };

                        var response = this.Request.CreateResponse(HttpStatusCode.Created, loggedModel);
                        response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = newUser.Id }));

                        return response;
                    }
                });

            return responseMsg;
        }
        public HttpResponseMessage PostRegisterUser(UserModel model)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
                {

                    var context = new ForumContext();

                    using (context)
                    {
                        this.ValidateUserName(model.UserName);
                        this.ValidateNickName(model.NickName);
                        this.ValidateAuthCode(model.AuthCode);

                        var userNameToLower = model.UserName.ToLower();
                        var nickNameToLower = model.NickName.ToLower();

                        var user = context.Users.FirstOrDefault(
                            usr => usr.UserName == userNameToLower &&
                                usr.NickName == usr.NickName);

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

                        user = new User()
                        {
                            UserName = userNameToLower,
                            NickName = model.NickName,
                            AuthCode = model.AuthCode
                        };

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

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

                        var loggedModel = new UserLoggedModel()
                        {
                            Nickname = user.NickName,
                            SessionKey = user.SessionKey
                        };

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

                        return response;
                    }
                });

            return responseMsg;
            }
        public HttpResponseMessage PostLoginUser(UserModel model)
        {
            return this.PerformOperationAndHandleExceptions(() =>
            {
                var context = new ForumContext();
                using (context)
                {
                    var usernameToLower = model.Username.ToLower();
                    var entity = context.Users.SingleOrDefault(u => u.Username == usernameToLower &&
                        u.AuthCode == model.AuthCode);
                    if (entity == null)
                    {
                        var errResponse = this.Request.CreateErrorResponse(HttpStatusCode.BadRequest,
                            "Invalid username or password");
                        throw new HttpResponseException(errResponse);
                    }

                    entity.SessionKey = this.GenerateSessionKey(entity.Id);

                    context.SaveChanges();
                    var responseModel = new UserLoggedModel()
                    {
                        Username = entity.Username,
                        SessionKey = entity.SessionKey
                    };

                    var response = this.Request.CreateResponse(HttpStatusCode.Accepted, responseModel);
                    return response;
                }
            });
        }
        public HttpResponseMessage DeletePostById(string sessionKey, int id)
        {
            HttpResponseMessage responseMessage = this.PerformOperationAndHandleExceptions(
               () =>
               {
               ForumContext context = new ForumContext();

               User adminUser = context.Users.FirstOrDefault(usr => usr.SessionKey == sessionKey);

               if (adminUser == null)
               {
                   throw new ArgumentNullException("If you want to edit users, you have to login or register first.");
               }

               if (adminUser.IsAdmin == false)
               {
                   throw new ArgumentException("You have to be admin, to edit users.");
               }

               Post currentPost = context.Posts.FirstOrDefault(pst => pst.Id == id);

               if (currentPost == null)
               {
                   throw new ArgumentNullException("Post you want to edit, doesn't exist.");
               }

               context.Posts.Remove(currentPost);

               context.SaveChanges();

               //UserModel result = UserModel.Parse(currentUser);

               var response = this.Request.CreateResponse(HttpStatusCode.NoContent);

               return response;

               });

            return responseMessage;
        }
        public HttpResponseMessage DeleteCategoryById(string sessionKey, int id)
        {
            HttpResponseMessage responseMessage = this.PerformOperationAndHandleExceptions(
               () =>
               {
               ForumContext context = new ForumContext();

               User adminUser = context.Users.FirstOrDefault(usr => usr.SessionKey == sessionKey);

               if (adminUser == null)
               {
                   throw new ArgumentNullException("If you want to edit users, you have to login or register first.");
               }

               if (adminUser.IsAdmin == false)
               {
                   throw new ArgumentException("You have to be admin, to edit users.");
               }

               Category currentCategory = context.Categories.FirstOrDefault(cat => cat.Id == id);

               if (currentCategory == null)
               {
                   throw new ArgumentNullException("Category you want to remove, doesn't exist.");
               }

               context.Categories.Remove(currentCategory);

               context.SaveChanges();

               var response = this.Request.CreateResponse(HttpStatusCode.OK);

               return response;

               });

            return responseMessage;
        }
        public HttpResponseMessage PostCreateThread(ThreadModel model,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))] string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
            {
                if (model == null)
                {
                    throw new InvalidOperationException("Thread cannot be null");
                }

                var context = new ForumContext();
                using (context)
                {
                    User user = context.Users.Where(usr => usr.SessionKey == sessionKey).FirstOrDefault();
                    if (user == null)
                    {
                        throw new InvalidOperationException("Invalid sessionkey");
                    }

                    var thread = new Thread()
                    {
                        Title = model.Title,
                        DateCreated = model.DateCreated,
                        Content = model.Content
                    };

                    user.Threads.Add(thread);
                    context.SaveChanges();

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

                    return response;
                }
            });

            return responseMsg;
        }
        public HttpResponseMessage PostCreate(PostRegisterModel inputPost, string sessionKey)
        {
            HttpResponseMessage responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    ForumContext context = new ForumContext();

                    using(context)
                    {
                        User currentUser = context.Users.FirstOrDefault(usr => usr.SessionKey == sessionKey);

                        int currentCategoryId = inputPost.CurrentCategoryId;

                        Category currentCategory = context.Categories.FirstOrDefault(cat => cat.Id == currentCategoryId);

                        if(currentUser == null)
                        {
                            throw new ArgumentNullException("You should be logged or registered to create new posts.");
                        }

                        if(currentCategory == null)
                        {
                            throw new ArgumentNullException("You try to create post in non-existing category.");
                        }

                        Post newPost = new Post()
                        {
                            Author = currentUser,
                            Category = currentCategory,
                            Content = inputPost.Content,
                            CreationDate = DateTime.Now,
                            Title = inputPost.Title
                        };

                        foreach(string tagName in inputPost.Tags)
                        {
                            Tag currentTag = context.Tags.FirstOrDefault(t => t.Name == tagName);

                            if(currentTag == null)
                            {
                                currentTag = new Tag()
                                {
                                    Name = tagName
                                };

                                context.Tags.Add(currentTag);
                                context.SaveChanges();

                                newPost.Tags.Add(currentTag);
                            }
                            else
                            {
                                newPost.Tags.Add(currentTag);
                            }
                        }

                        context.Posts.Add(newPost);
                        context.SaveChanges();

                        var resultPost = new PostModel
                        {
                            Id = newPost.Id,
                            Content = newPost.Content,
                            CategoryName = newPost.Category.Title,
                            CategoryId = newPost.Category.Id,
                            CreationDate = newPost.CreationDate,
                            Tags = (from t in newPost.Tags
                                   select t.Name),
                            Title = newPost.Title,
                            Author = newPost.Author.Username
                        };

                        HttpResponseMessage response = this.Request.CreateResponse(HttpStatusCode.Created, resultPost);

                        return response;
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage EditCategoryById(string sessionKey, CategoryEditModel newComment)
        {
            HttpResponseMessage responseMessage = this.PerformOperationAndHandleExceptions(
             () =>
             {
                 ForumContext context = new ForumContext();

                 User adminUser = context.Users.FirstOrDefault(usr => usr.SessionKey == sessionKey);

                 if (adminUser == null)
                 {
                     throw new ArgumentNullException("If you want to edit users, you have to login or register first.");
                 }

                 if (adminUser.IsAdmin == false)
                 {
                     throw new ArgumentException("You have to be admin, to edit users.");
                 }

                 Comment currentComment = context.Comments.FirstOrDefault(comment => comment.Id == newComment.Id);

                 if (currentComment == null)
                 {
                     throw new ArgumentNullException("Comment you want to edit, doesn't exist.");
                 }

                 currentComment.Content = newComment.Content;

                 context.SaveChanges();

                 //TODO yoan change model from commentCreateModel to commentCreatedModel
                 var response = this.Request.CreateResponse(HttpStatusCode.OK, newComment);

                 return response;

             });

            return responseMessage;
        }
        public HttpResponseMessage PostRegisterUser(UserModel model)
        {
            return this.PerformOperationAndHandleExceptions(() =>
            {
                var usernameToLower = model.Username.ToLower();
                var context = new ForumContext();
                using (context)
                {
                    var entity = context.Users.FirstOrDefault(u => u.Username == usernameToLower);
                    if (entity != null)
                    {
                        string responseMessage = "Username already taken";

                        HttpResponseMessage errResponse =
                            this.Request.CreateErrorResponse(HttpStatusCode.Conflict, responseMessage);
                        throw new HttpResponseException(errResponse);
                    }

                    var user = new User()
                    {
                        Username = model.Username.ToLower(),
                        AuthCode = model.AuthCode
                    };

                    context.Users.Add(user);
                    context.SaveChanges();
                    return this.PostLoginUser(model);
                }
            });
        }
        public HttpResponseMessage PutUserLogout(string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
                {
                    this.ValidateSessionKey(sessionKey);
                    var context = new ForumContext();
                    using (context)
                    {
                        var user = context.Users.FirstOrDefault(usr => usr.SessionKey == sessionKey);
                        if (user == null)
                        {
                            throw new InvalidOperationException("Invalid user authentication");
                        }
                        user.SessionKey = null;
                        context.SaveChanges();

                        var response = this.Request.CreateResponse(HttpStatusCode.OK);

                        return response;
                    }
                });

            return responseMsg;
        }
        public HttpResponseMessage EditUserById(string sessionKey, UserEditModel newUser)
        {
            HttpResponseMessage responseMessage = this.PerformOperationAndHandleExceptions(
             () =>
             {
                 ForumContext context =new ForumContext();

                 User adminUser = context.Users.FirstOrDefault(usr => usr.SessionKey == sessionKey);

                 if (adminUser == null)
                 {
                     throw new ArgumentNullException("If you want to edit users, you have to login or register first.");
                 }

                 if(adminUser.IsAdmin == false)
                 {
                     throw new ArgumentException("You have to be admin, to edit users.");
                 }

                 User currentUser = context.Users.FirstOrDefault(usr => usr.Id == newUser.Id);

                 if (currentUser == null)
                 {
                     throw new ArgumentNullException("User you want to edit, doesn't exist.");
                 }

                 //currentUser.Username = newUser.Username;
                 currentUser.IsBanned = newUser.IsBanned;

                 context.SaveChanges();

                 UserModel result = UserModel.Parse(currentUser);

                 var response = this.Request.CreateResponse(HttpStatusCode.OK, result);

                 return response;

             });

            return responseMessage;
        }
        public HttpResponseMessage PutLogoutUser(string sessionKey)
        {
            HttpResponseMessage responseMessage = this.PerformOperationAndHandleExceptions(
              () =>
              {
                  ForumContext context = new ForumContext();

                  using (context)
                  {
                      User currentUser = context.Users.FirstOrDefault(usr => usr.SessionKey == sessionKey);

                      if (currentUser == null)
                      {
                          throw new ArgumentException("User is not registered or not logged in.");
                      }

                      currentUser.SessionKey = null;

                      context.SaveChanges();

                      string logoutText = "You successfully have logged out.";

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

                      return response;
                  }
              });

            return responseMessage;
        }
        public HttpResponseMessage PostRegisterUser(UserFlatModel inputUser)
        {
            HttpResponseMessage responseMessage = this.PerformOperationAndHandleExceptions(
                 () =>
                 {
                     ForumContext context = new ForumContext();

                     using (context)
                     {
                         this.ValidateUsername(inputUser.Username);
                         this.ValidateAuthCode(inputUser.AuthCode);

                         var usernameToLower = inputUser.Username.ToLower();

                         User user = context.Users.FirstOrDefault(
                             usr => usr.Username == usernameToLower);
                         if (user != null)
                         {
                             throw new InvalidOperationException("User already exists");
                         }

                         user = new User()
                         {
                             Username = usernameToLower,
                             AuthCode = inputUser.AuthCode,
                             CreationDate = DateTime.Now
                         };

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

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

                         UserLoggedModel loggedModel = new UserLoggedModel()
                         {
                             Username = user.Username,
                             SessionKey = user.SessionKey
                         };

                         HttpResponseMessage response =
                             this.Request.CreateResponse(HttpStatusCode.Created,
                                             loggedModel);
                         return response;
                     }
                 });

            return responseMessage;
        }
        public HttpResponseMessage PostLoginUser(UserFlatModel inputUser)
        {
            HttpResponseMessage responseMessage = this.PerformOperationAndHandleExceptions(
              () =>
              {
                  ForumContext context = new ForumContext();

                  using (context)
                  {
                      this.ValidateUsername(inputUser.Username);
                      this.ValidateAuthCode(inputUser.AuthCode);

                      var usernameToLower = inputUser.Username.ToLower();

                      User user = context.Users.FirstOrDefault(
                          usr => usr.Username == usernameToLower
                          && usr.AuthCode == inputUser.AuthCode);

                      if (user == null)
                      {
                          throw new InvalidOperationException("Invalid username or password");
                      }
                      if (user.SessionKey == null)
                      {
                          user.SessionKey = this.GenerateSessionKey(user.Id);
                          context.SaveChanges();
                      }
                      if (user.IsBanned == true)
                      {
                          throw new ArgumentException("User is banned.");
                      }

                      UserLoggedModel loggedModel = new UserLoggedModel()
                      {
                          Username = user.Username,
                          SessionKey = user.SessionKey
                      };

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

            return responseMessage;
        }
        public HttpResponseMessage PostCreateComment(CommentCreateModel inputComment, string sessionKey)
        {
            HttpResponseMessage responseMessage = this.PerformOperationAndHandleExceptions(
              () =>
              {
                  ForumContext context = new ForumContext();

                  User currentUser = context.Users.FirstOrDefault(usr => usr.SessionKey == sessionKey);

                  Post currentPost = context.Posts.FirstOrDefault(pst => pst.Id == inputComment.PostId);

                  if (currentUser == null)
                  {
                      throw new ArgumentNullException("If you want to comment posts, you should be logged or registered.");
                  }

                  if (currentPost == null)
                  {
                      throw new ArgumentNullException("The post you are trying to comment, doesn't exist.");
                  }

                  Comment newComment = new Comment()
                  {
                      Author = currentUser,
                      Post = currentPost,
                      Content = inputComment.Content,
                      CreationDate = DateTime.Now
                  };

                  context.Comments.Add(newComment);
                  context.SaveChanges();

                  CommentModel createdComment = new CommentModel()
                  {
                      Author = newComment.Author.Username,
                      Content = newComment.Content,
                      CreationDate = newComment.CreationDate
                  };

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

            return responseMessage;
        }
        public HttpResponseMessage PostCreate(SendMessageModel messageModel, string sessionKey)
        {
            HttpResponseMessage responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    ForumContext context = new ForumContext();

                    using (context)
                    {
                        User currentUser = context.Users.FirstOrDefault(usr => usr.SessionKey == sessionKey);
                        if (currentUser == null)
                        {
                            throw new ArgumentException("Invalid user data!");
                        }

                        User reciever = context.Users.FirstOrDefault(usr => usr.Username == messageModel.ToUser);
                        if (reciever == null)
                        {
                            throw new ArgumentException("Cannot send message to not registred users!");
                        }

                        var message = new Message
                        {
                            Sender = currentUser,
                            Reciever = reciever,
                            Content = messageModel.Content,
                            CreationDate = DateTime.Now
                        };

                        context.Messages.Add(message);
                        context.SaveChanges();

                        HttpResponseMessage response = this.Request.CreateResponse(HttpStatusCode.Created, message);

                        return response;
                    }
                });

            return responseMessage;
        }
        public void LogoutUser(
             [ValueProvider(typeof(HeaderValueProviderFactory<string>))] string sessionKey)
        {
            this.ExceptionHandler(
            () =>
            {
                var context = new ForumContext();

                using (context)
                {
                    var user = context.Users.FirstOrDefault(
                        usr => usr.SessionKey == sessionKey);

                    if (user == null)
                    {
                        throw new InvalidOperationException("Invalid Username or Password");
                    }

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

                    var loggedModel = new LoggedUserModel
                    {
                        Nickname = user.Nickname,
                        SessionKey = user.SessionKey
                    };

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

                    return response;
                }
            });
        }
        public HttpResponseMessage PutLogoutUser(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))] string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
              () =>
              {
                  var context = new ForumContext();
                  using (context)
                  {
                      var user = context.Users.FirstOrDefault(
                          u => u.SessionKey == sessionKey);

                      if (user == null)
                      {
                          throw new InvalidOperationException("Invalid sessionKey");
                      }

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

                      var response =
                          this.Request.CreateResponse(HttpStatusCode.OK);
                      return response;
                  }
              });

            return responseMsg;
        }
        public HttpResponseMessage LoginUser(UserLoginModel model)
        {
            var responseMsg = this.ExceptionHandler(
                () =>
                {
                    var context = new ForumContext();

                    using (context)
                    {
                        UserDataPersister.ValidateUsername(model.Username);
                        UserDataPersister.ValidateAuthCode(model.AuthCode);

                        var usernameToLower = model.Username.ToLower();

                        var user = context.Users.FirstOrDefault(
                            usr => usr.Username == usernameToLower && usr.AuthCode == model.AuthCode);

                        if (user == null)
                        {
                            throw new InvalidOperationException("Invalid Username or Password");
                        }

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

                        var loggedModel = new LoggedUserModel
                        {
                            Nickname = user.Nickname,
                            SessionKey = user.SessionKey
                        };

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

                        return response;
                    }
                });

            return responseMsg;
        }
        //public HttpResponseMessage PostNewPost(PostNewModel model)
        //{
        //    var responseMsg = this.PerformOperationAndHandleExceptions(
        //      () =>
        //      {
        //          var context = new BlogSystemContext();
        //          using (context)
        //          {
        //              var user = context.Users.FirstOrDefault(
        //                  usr => usr.SessionKey == sessionKey);
        //              if (user == null)
        //              {
        //                  throw new InvalidOperationException("Invalid sessionKey");
        //              }
        //              if (model.Title == null || model.Text == null)
        //              {
        //                  throw new ArgumentNullException("Post title or post text cannot be null");
        //              }
        //              string[] titleWords = model.Title.Split(
        //                  new char[] { ' ', ',', '.', '!', '?', '\'', '(', ')' },
        //                  StringSplitOptions.RemoveEmptyEntries);
        //              IList<Tag> tags = new List<Tag>();
        //              if (model.Tags != null)
        //              {
        //                  foreach (var item in model.Tags)
        //                  {
        //                      var tag = context.Tags.FirstOrDefault(t => t.Name == item.ToLower());
        //                      if (tag == null)
        //                      {
        //                          tag = new Tag()
        //                          {
        //                              Name = item.ToLower()
        //                          };
        //                          context.Tags.Add(tag);
        //                          context.SaveChanges();
        //                      }
        //                      tags.Add(tag);
        //                  }
        //              }
        //              foreach (var item in titleWords)
        //              {
        //                  var tag = context.Tags.FirstOrDefault(t => t.Name == item.ToLower());
        //                  if (tag == null)
        //                  {
        //                      tag = new Tag()
        //                      {
        //                          Name = item.ToLower()
        //                      };
        //                      context.Tags.Add(tag);
        //                      context.SaveChanges();
        //                  }
        //                  tags.Add(tag);
        //              }
        //              var post = new Post()
        //              {
        //                  Title = model.Title,
        //                  Text = model.Text,
        //                  PostDate = DateTime.Now,
        //                  User = user,
        //                  Tags = tags
        //              };
        //              context.Posts.Add(post);
        //              context.SaveChanges();
        //              var createdModel = new PostCreatedModel()
        //              {
        //                  Id = post.Id,
        //                  Title = post.Title
        //              };
        //              var response =
        //                  this.Request.CreateResponse(HttpStatusCode.Created,
        //                                  createdModel);
        //              return response;
        //          }
        //      });
        //    return responseMsg;
        //}
        //[ActionName("comment")]
        public HttpResponseMessage PutComment(int id, CommentModel model,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))] string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
              () =>
              {
                  var context = new ForumContext();
                  using (context)
                  {
                      var post = context.Posts.FirstOrDefault(p => p.Id == id);

                      if (post == null)
                      {
                          throw new InvalidOperationException("Invalid id");
                      }

                      var user = context.Users.FirstOrDefault(u => u.SessionKey == sessionKey);
                      //var user = context.Users.FirstOrDefault(u => u.Id == 2);
                      if (user == null)
                      {
                          throw new InvalidOperationException("Invalid sessionKey");
                      }

                      if (model.Text == null)
                      {
                          throw new ArgumentNullException("Comment text cannot be null");
                      }

                      var comment = new Comment()
                      {
                          Text = model.Text,
                          Creator = user,
                          CreatedOn = DateTime.Now,
                          Post = post
                      };

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

                      var response =
                          this.Request.CreateResponse(HttpStatusCode.OK, "NULL");
                      return response;
                  }
              });

            return responseMsg;
        }