public ActionResult Index(string sort, string gender, int page = 1, int qcat = -1, bool onlyUnanswered = false)
        {
            List<Question> results;

            //default the sort to latest
            Constants.QuestionSort currentSort = Constants.QuestionSort.Latest;
            string pageTitle = "";

            if (!string.IsNullOrEmpty(sort))
            {
                if (sort.ToLower() == Constants.QuestionSort.Latest.ToString().ToLower())
                    currentSort = Constants.QuestionSort.Latest;
                else if (sort.ToLower() == Constants.QuestionSort.Top_Rated.ToString().ToLower())
                    currentSort = Constants.QuestionSort.Top_Rated;
            }

            IQueryable<Question> query = _questionRepo.Questions;

            //if there is no gender filter, then we can execute query directly without extra filtering
            if (!string.IsNullOrEmpty(gender))
            {
                gender = gender.ToLower(); //lower case it first to make it easier to compare
                var femaleGender = Constants.Gender.F.ToString().ToLower();
                var maleGender = Constants.Gender.M.ToString().ToLower();
                if (gender == femaleGender)
                {
                    query = query.Where(q => q.Gender.Equals(femaleGender, StringComparison.CurrentCultureIgnoreCase));
                }
                else if (gender == maleGender)
                {
                    query = query.Where(q => q.Gender.Equals(maleGender, StringComparison.CurrentCultureIgnoreCase));
                }
            }

            //check if there is a category
            if (qcat >= 0)
            {
                //if category is the default 'unknown' category, then also check for questions that has 'null' as the category
                if (qcat == 0)
                    query = query.Where(q => q.Category == qcat || q.Category == null);
                else
                    query = query.Where(q => q.Category == qcat);
            }

            Guid currentUserId = Guid.Empty;
            User currentUser = null;
            List<int> answeredQuestionIds = new List<int>();
            bool isLoggedIn = _membershipService.IsAuthenticated();
            if (isLoggedIn)
            {
                currentUserId = _membershipService.GetCurrentUserId();
                currentUser = _userRepo.Users.Where(u => u.UserID == currentUserId).First();
                answeredQuestionIds = currentUser.Answers.Select(ans => ans.QuestionID).ToList();

                //check to see if we dont want to include answered questions, which means we should exclude questions
                if (onlyUnanswered)
                {
                    query = query.Where(q => !answeredQuestionIds.Contains(q.QuestionID)).Where(q => string.IsNullOrEmpty(q.Gender) || q.Gender == currentUser.Gender);
                }
            }

            int numResults = 0;
            if (currentSort == Constants.QuestionSort.Latest)
            {
                numResults = query.Count();
                results = query.OrderByDescending(q => q.DateCreated).Skip((page - 1) * _pageSize).Take(_pageSize).ToList();
            }
            else
            {
                numResults = query.Count();
                results = query.OrderByDescending(q => (q.BumpUpValue - q.BumpDownValue)).ThenByDescending(q => q.DateCreated).Skip((page - 1) * _pageSize).Take(_pageSize).ToList();
            }

            //set pagetitle based on the question category
            //if qcat is -1, then it means we're on the view all page
            if (qcat == -1)
            {
                pageTitle = "'Would You Rather' Questions For Everyone - RatherThis.com";
            }
            else
            {
                CategoryItem currentCat = Constants.QuestionCategories.Where(c => c.CategoryID == qcat).First();
                pageTitle = "Fun And Interesting Questions About " + currentCat.Name + " - RatherThis.com";
            }

            //set meta info
            ViewBag.Title = pageTitle;
            ViewBag.Description = Utility.GetMetaDescription(qcat);
            ViewBag.Keywords = Utility.GetMetaKeywords(qcat);

            Dictionary<object, string> resultModel = new Dictionary<object, string>();
            foreach (var q in results)
            {
                //get the question options
                QuestionOption option1 = q.QuestionOptions.ElementAt(0);
                QuestionOption option2 = q.QuestionOptions.ElementAt(1);

                DateTime date = q.DateCreated;
                String questionGender = q.Gender;
                String name = q.User.Username;
                String optionText1 = option1.OptionText;
                String optionText2 = option2.OptionText;

                //if category is null, then default to the 'unknown' category
                CategoryItem questionCat = q.Category ==  null ? Constants.QuestionCategories.Where(cat => cat.CategoryID == 0).First() : Constants.QuestionCategories.Where(cat => cat.CategoryID == q.Category).First();  //default to 'unknown'

                //if user is not logged in, then display the question view since we don't know whether user has answered or not
                if (!isLoggedIn)
                {
                    QuestionDisplayViewModel model = new QuestionDisplayViewModel();
                    model.IsLoggedIn = false;
                    model.Date = date;
                    model.Gender = questionGender;
                    model.Name = name;
                    model.UserId = Guid.Empty;

                    model.OptionText1 = optionText1;
                    model.OptionText2 = optionText2;

                    model.OptionId1 = option1.QuestionOptionID;
                    model.OptionId2 = option2.QuestionOptionID;

                    model.QuestionId = q.QuestionID;
                    model.QuestionUserGender = q.User.Gender;
                    model.QuestionUsername = q.User.Username;
                    model.QuestionCategory = questionCat.Name;
                    model.QuestionCategoryId = questionCat.CategoryID;

                    resultModel.Add(model, "question");
                }
                else
                {
                    //if user is logged in, then check whether user has already answered the question. if so then render answer view, otherwise render the question view
                    //or if the user doesn't match the gender restriction, then just display the answer format
                    //(e.g. if current user is male, and this is a 'for ladies' question, since user can't answer it anyways, then just display the answer view

                    //check whether user has already answered this question
                    Answer userAnswer = q.Answers.Where(a => a.UserID == currentUserId).FirstOrDefault();
                    Guid questionUserId = q.UserID;

                    bool isAnswered = (userAnswer == null) ? false : true;
                    bool isGenderMismatch = (!string.IsNullOrEmpty(q.Gender) && q.Gender.ToLower() != currentUser.Gender.ToLower()) ? true : false;
                    if (isAnswered || (!isAnswered && isGenderMismatch))
                    {
                        AnswerDisplayViewModel model = new AnswerDisplayViewModel();
                        model.QuestionId = q.QuestionID;
                        model.Date = date;
                        model.Gender = questionGender;
                        model.Name = name;
                        model.UserId = questionUserId;
                        if (isAnswered)
                            model.AnsweredOptionId = userAnswer.QuestionOptionID;

                        model.OptionText1 = optionText1;
                        model.OptionText2 = optionText2;

                        model.OptionVotes1 = q.Answers.Where(a => a.QuestionOptionID == option1.QuestionOptionID).Count();
                        model.OptionVotes2 = q.Answers.Where(a => a.QuestionOptionID == option2.QuestionOptionID).Count();
                        model.TotalVotes = (model.OptionVotes1 + model.OptionVotes2);

                        model.OptionId1 = option1.QuestionOptionID;
                        model.OptionId2 = option2.QuestionOptionID;
                        model.QuestionUserGender = q.User.Gender;
                        model.QuestionUsername = q.User.Username;

                        model.QuestionCategory = questionCat.Name;
                        model.QuestionCategoryId = questionCat.CategoryID;
                        /*
                        CommentListViewModel commentModel = new CommentListViewModel();
                        commentModel.OptionId1 = option1.QuestionOptionID;
                        commentModel.OptionId2 = option2.QuestionOptionID;
                        commentModel.Comments = q.Comments.ToList();
                        model.CommentModel = commentModel;
                         * */

                        model.NumComments = q.Comments.Count();
                        resultModel.Add(model, "answer");
                    }
                    else
                    {
                        QuestionDisplayViewModel model = new QuestionDisplayViewModel();
                        model.IsLoggedIn = true;
                        model.Date = date;
                        model.Gender = questionGender;
                        model.Name = name;
                        model.UserId = questionUserId;

                        model.OptionText1 = optionText1;
                        model.OptionText2 = optionText2;

                        model.OptionId1 = option1.QuestionOptionID;
                        model.OptionId2 = option2.QuestionOptionID;

                        model.QuestionId = q.QuestionID;
                        model.QuestionUserGender = q.User.Gender;
                        model.QuestionUsername = q.User.Username;
                        model.QuestionCategory = questionCat.Name;
                        model.QuestionCategoryId = questionCat.CategoryID;

                        resultModel.Add(model, "question");
                    }
                }
            }

            QuestionIndexViewModel viewModel = new QuestionIndexViewModel();
            viewModel.ResultViewModels = resultModel;
            viewModel.CurrentPage = page;
            viewModel.Gender = gender;
            viewModel.Sort = currentSort.ToString();
            viewModel.TotalPages = (int)Math.Ceiling((double)numResults / _pageSize);
            viewModel.CurrentCategoryId = qcat;
            viewModel.IsOnlyUnanswered = onlyUnanswered;

            return View(viewModel);
        }
        public PartialViewResult RenderQuestion(int qid, int commentListSize = 9, bool showAllComments = false)
        {
            Question q;

            //need to re-retrieve the question from db in order to get eager loading for its relationships, otherwise the question passed in to our action only  has the question's base properties
            q = _questionRepo.Questions.Where(qe => qe.QuestionID == qid).FirstOrDefault();
            //TODO: what happens if this is null (e.g. bad data)

            //get the question options
            QuestionOption option1 = q.QuestionOptions.ElementAt(0);
            QuestionOption option2 = q.QuestionOptions.ElementAt(1);

            DateTime date = q.DateCreated;
            String gender = q.Gender;
            String name = q.User.Username;
            String optionText1 = option1.OptionText;
            String optionText2 = option2.OptionText;

            bool isLoggedIn = _membershipService.IsAuthenticated();

            //if user is not logged in, then display the question view since we don't know whether user has answered or not
            if (!isLoggedIn)
            {
                QuestionDisplayViewModel model = new QuestionDisplayViewModel();
                model.IsLoggedIn = false;
                model.Date = date;
                model.Gender = gender;
                model.Name = name;
                model.UserId = Guid.Empty;

                model.OptionText1 = optionText1;
                model.OptionText2 = optionText2;

                model.OptionId1 = option1.QuestionOptionID;
                model.OptionId2 = option2.QuestionOptionID;

                model.QuestionId = q.QuestionID;
                model.QuestionUserGender = q.User.Gender;
                model.QuestionUsername = q.User.Username;

                return PartialView("_QuestionDisplay", model);
            }
            else
            {
                //if user is logged in, then check whether user has already answered the question. if so then render answer view, otherwise render the question view
                //or if the user doesn't match the gender restriction, then just display the answer format
                //(e.g. if current user is male, and this is a 'for ladies' question, since user can't answer it anyways, then just display the answer view

                //check whether user has already answered this question
                Guid currentUserId = _membershipService.GetCurrentUserId();
                User currentUser = _userRepo.Users.Where(u => u.UserID == currentUserId).First();

                Answer userAnswer = _answerRepo.Answers.Where(a => a.UserID == currentUserId && a.QuestionID == q.QuestionID).FirstOrDefault();
                Guid questionUserId = q.UserID;

                bool isAnswered = (userAnswer == null) ? false : true;
                bool isGenderMismatch = (!string.IsNullOrEmpty(q.Gender) && q.Gender.ToLower() != currentUser.Gender.ToLower()) ? true : false;
                if (isAnswered || isGenderMismatch)
                {
                    AnswerDisplayViewModel model = new AnswerDisplayViewModel();
                    model.QuestionId = q.QuestionID;
                    model.Date = date;
                    model.Gender = gender;
                    model.Name = name;
                    model.UserId = questionUserId;
                    if(isAnswered)
                        model.AnsweredOptionId = userAnswer.QuestionOptionID;

                    model.OptionText1 = optionText1;
                    model.OptionText2 = optionText2;

                    model.OptionVotes1 = q.Answers.Where(a => a.QuestionOptionID == option1.QuestionOptionID).Count();
                    model.OptionVotes2 = q.Answers.Where(a => a.QuestionOptionID == option2.QuestionOptionID).Count();
                    model.TotalVotes = (model.OptionVotes1 + model.OptionVotes2);

                    model.OptionId1 = option1.QuestionOptionID;
                    model.OptionId2 = option2.QuestionOptionID;

                    model.QuestionUserGender = q.User.Gender;
                    model.QuestionUsername = q.User.Username;
                    /*
                    CommentListViewModel commentModel = new CommentListViewModel();
                    commentModel.OptionId1 = option1.QuestionOptionID;
                    commentModel.OptionId2 = option2.QuestionOptionID;
                    commentModel.Comments = q.Comments.ToList();
                    model.CommentModel = commentModel;
                    */
                    model.NumComments = q.Comments.Count();
                    model.CommentListSize = commentListSize;
                    model.IsShowAllComment = showAllComments;

                    return PartialView("_AnswerDisplay", model);
                }
                else
                {
                    QuestionDisplayViewModel model = new QuestionDisplayViewModel();
                    model.IsLoggedIn = true;
                    model.Date = date;
                    model.Gender = gender;
                    model.Name = name;
                    model.UserId = questionUserId;

                    model.OptionText1 = optionText1;
                    model.OptionText2 = optionText2;

                    model.OptionId1 = option1.QuestionOptionID;
                    model.OptionId2 = option2.QuestionOptionID;

                    model.QuestionId = q.QuestionID;
                    model.QuestionUserGender = q.User.Gender;
                    model.QuestionUsername = q.User.Username;

                    return PartialView("_QuestionDisplay", model);
                }
            }
        }
        public ActionResult UserDetail(string username, string filter = "", int page = 1)
        {
            UserDetailViewModel userDetailViewModel = new UserDetailViewModel();

            User user = _userRepo.GetUserWithQuestionsAnswersByUsername(username);
            if (user != null)
            {
                int numResults;
                IEnumerable<Question> questionResults;
                List<Question> results;

                Constants.Filter currentFilter = Constants.Filter.QUESTION;
                if (filter.ToLower() == Constants.Filter.ANSWER.ToString().ToLower())
                {
                    currentFilter = Constants.Filter.ANSWER;
                }

                if (currentFilter == Constants.Filter.ANSWER)
                {
                    questionResults = user.Answers.Select(a => a.Question);
                }
                else
                {
                    questionResults = user.Questions;
                }
                //count total number of results
                numResults = questionResults.Count();
                //get the actual list of results, accounting for page number and page size
                results = questionResults.OrderByDescending(q => q.DateCreated).Skip((page - 1) * _pageSize).Take(_pageSize).ToList();

                Dictionary<object, string> resultModel = new Dictionary<object, string>();
                //by 'CURRENT USER', i mean the user that is viewing this page (which could be different from the 'user' whose page is being displayed. e.g. im viewing a friend's user detail page)
                bool isLoggedIn = _membershipService.IsAuthenticated(); //check to see whether the current user viewing this page is authenticated
                Guid currentUserId = _membershipService.GetCurrentUserId(); //get current user's user id
                User currentUser = _userRepo.Users.Where(u => u.UserID == currentUserId).FirstOrDefault();
                foreach (var q in results)
                {
                    //get the question options
                    QuestionOption option1 = q.QuestionOptions.ElementAt(0);
                    QuestionOption option2 = q.QuestionOptions.ElementAt(1);

                    DateTime date = q.DateCreated;
                    String questionGender = q.Gender;
                    String name = q.User.Username;
                    String optionText1 = option1.OptionText;
                    String optionText2 = option2.OptionText;

                    //if user is not logged in, then display the question view since we don't know whether user has answered or not
                    if (!isLoggedIn)
                    {
                        QuestionDisplayViewModel model = new QuestionDisplayViewModel();
                        model.IsLoggedIn = false;
                        model.Date = date;
                        model.Gender = questionGender;
                        model.Name = name;
                        model.UserId = Guid.Empty;

                        model.OptionText1 = optionText1;
                        model.OptionText2 = optionText2;

                        model.OptionId1 = option1.QuestionOptionID;
                        model.OptionId2 = option2.QuestionOptionID;

                        model.QuestionId = q.QuestionID;
                        model.QuestionUserGender = q.User.Gender;
                        model.QuestionUsername = q.User.Username;

                        resultModel.Add(model, "question");
                    }
                    else
                    {
                        //if user is logged in, then check whether user has already answered the question. if so then render answer view, otherwise render the question view
                        //or if the user doesn't match the gender restriction, then just display the answer format
                        //(e.g. if current user is male, and this is a 'for ladies' question, since user can't answer it anyways, then just display the answer view

                        //check whether user has already answered this question
                        Answer userAnswer = q.Answers.Where(a => a.UserID == currentUserId).FirstOrDefault();
                        Guid questionUserId = q.UserID;

                        bool isAnswered = (userAnswer == null) ? false : true;
                        bool isGenderMismatch = (!string.IsNullOrEmpty(q.Gender) && q.Gender.ToLower() != currentUser.Gender.ToLower()) ? true : false;
                        if (isAnswered || (!isAnswered && isGenderMismatch))
                        {
                            AnswerDisplayViewModel model = new AnswerDisplayViewModel();
                            model.QuestionId = q.QuestionID;
                            model.Date = date;
                            model.Gender = questionGender;
                            model.Name = name;
                            model.UserId = questionUserId;
                            if (isAnswered)
                                model.AnsweredOptionId = userAnswer.QuestionOptionID;

                            model.OptionText1 = optionText1;
                            model.OptionText2 = optionText2;

                            model.OptionVotes1 = q.Answers.Where(a => a.QuestionOptionID == option1.QuestionOptionID).Count();
                            model.OptionVotes2 = q.Answers.Where(a => a.QuestionOptionID == option2.QuestionOptionID).Count();
                            model.TotalVotes = (model.OptionVotes1 + model.OptionVotes2);

                            model.OptionId1 = option1.QuestionOptionID;
                            model.OptionId2 = option2.QuestionOptionID;
                            model.QuestionUserGender = q.User.Gender;
                            model.QuestionUsername = q.User.Username;
                            /*
                            CommentListViewModel commentModel = new CommentListViewModel();
                            commentModel.OptionId1 = option1.QuestionOptionID;
                            commentModel.OptionId2 = option2.QuestionOptionID;
                            commentModel.Comments = q.Comments.ToList();
                            model.CommentModel = commentModel;
                             * */

                            model.NumComments = q.Comments.Count();
                            resultModel.Add(model, "answer");
                        }
                        else
                        {
                            QuestionDisplayViewModel model = new QuestionDisplayViewModel();
                            model.IsLoggedIn = true;
                            model.Date = date;
                            model.Gender = questionGender;
                            model.Name = name;
                            model.UserId = questionUserId;

                            model.OptionText1 = optionText1;
                            model.OptionText2 = optionText2;

                            model.OptionId1 = option1.QuestionOptionID;
                            model.OptionId2 = option2.QuestionOptionID;

                            model.QuestionId = q.QuestionID;
                            model.QuestionUserGender = q.User.Gender;
                            model.QuestionUsername = q.User.Username;

                            resultModel.Add(model, "question");
                        }
                    }
                }

                userDetailViewModel.CurrentPage = page;
                userDetailViewModel.Filter = currentFilter.ToString();
                userDetailViewModel.TotalPages = (int)Math.Ceiling((double)numResults / _pageSize);
                userDetailViewModel.ResultViewModels = resultModel;
                userDetailViewModel.Username = user.Username;
                userDetailViewModel.NumAsked = user.Questions.Count();
                userDetailViewModel.NumAnswered = user.Answers.Count();
                userDetailViewModel.UserGender = user.Gender;
            }
            return View(userDetailViewModel);
        }