public ActionResult Create(int id, int? categoryId, Question question, ResponsesParameter[] response)
        {
            var isNewVersion = false;
            var survey = Repository.OfType<Survey>().GetNullableById(id);
            if (survey == null)
            {
                Message = "Survey Not Found";
                return this.RedirectToAction<ErrorController>(a => a.Index());
            }
            var viewModel = QuestionViewModel.Create(Repository, survey);
            if (categoryId != null) //This category Id is just used for defaults and navigation
            {
                var category = Repository.OfType<Category>().GetNullableById(categoryId.Value);
                viewModel.Category = category;
            }
            viewModel.Question = question;

            if (question.Category != null && Repository.OfType<Answer>().Queryable.Where(a => a.Category.Id == question.Category.Id).Any())
            {
                //The category picked already has answers, so if it is valid and we create a new question, we want to create a new version of the category first.
                isNewVersion = true;
            }

            // Remove responses that do not have a Choice or that have the remove checked. This is the create, so they will never be added
            var cleanedResponse = new List<ResponsesParameter>();
            foreach (var responsesParameter in response.OrderBy(a => a.Order))
            {
                if (!string.IsNullOrWhiteSpace(responsesParameter.Value) && !responsesParameter.Remove)
                {
                    cleanedResponse.Add(responsesParameter);
                }
            }
            viewModel.Responses = cleanedResponse;

            var questionToCreate = new Question(survey);
            Mapper.Map(question, questionToCreate);

            foreach (var responsesParameter in viewModel.Responses)
            {
                var responseToAdd = new Response
                {
                    Order = responsesParameter.Order,
                    IsActive = true,
                    Score = responsesParameter.Score.GetValueOrDefault(0),
                    Value = responsesParameter.Value
                };

                questionToCreate.AddResponse(responseToAdd);
            }

            ModelState.Clear();
            questionToCreate.TransferValidationMessagesTo(ModelState);

            foreach (var responsesParameter in cleanedResponse)
            {
                if (!responsesParameter.Score.HasValue)
                {
                    ModelState.AddModelError("Question", "All responses need a score");
                }
                else
                {
                    if(questionToCreate.IsOpenEnded)
                    {
                        switch ((QuestionType)questionToCreate.OpenEndedQuestionType)
                        {
                            case QuestionType.WholeNumber:
                                int number;
                                if (!int.TryParse(responsesParameter.Value, out number))
                                {
                                    ModelState.AddModelError("Question", "Choices must be whole numbers");
                                }
                                break;
                            case QuestionType.Decimal:
                                float floatNumber;
                                if (!float.TryParse(responsesParameter.Value, out floatNumber))
                                {
                                    ModelState.AddModelError("Question", "Choices must be numbers (decimal ok)");
                                }
                                break;
                            case QuestionType.Time:
                                float floatTime;
                                if (!responsesParameter.Value.TimeTryParse(out floatTime))
                                {
                                    ModelState.AddModelError("Question", "Choices must be Time (hh:mm)");
                                }
                                break;
                            case QuestionType.TimeAmPm:
                                float floatTimeAmPm;
                                if (!responsesParameter.Value.TimeTryParseAmPm(out floatTimeAmPm))
                                {
                                    ModelState.AddModelError("Question", "Choices must be Time (hh:mm AM/PM)");
                                }
                                break;
                            case QuestionType.TimeRange:
                                float timeRangeNumber;
                                if (!float.TryParse(responsesParameter.Value, out timeRangeNumber))
                                {
                                    ModelState.AddModelError("Question", "Choices must be numbers (decimal ok)");
                                }
                                break;

                            default:
                                ModelState.AddModelError("Question", "time and time range not supported yet");
                                break;
                        }
                    }
                }
            }

            if (questionToCreate.Responses.Where(a => a.IsActive).Count() == 0)
            {
                ModelState.AddModelError("Question", "Responses are required.");
            }
            if (questionToCreate.Category != null && !questionToCreate.Category.IsCurrentVersion)
            {
                ModelState.AddModelError("Question.Category", "Selected Category is not current.");
            }

            if (ModelState.IsValid)
            {
                var extraMessage = string.Empty;
                if (isNewVersion && questionToCreate.IsActive)
                {
                    questionToCreate.Category = _archiveService.ArchiveCategory(Repository, questionToCreate.Category.Id, questionToCreate.Category);
                    viewModel.Category = questionToCreate.Category;
                    extraMessage = ", related Category versioned";
                }

                _questionRepository.EnsurePersistent(questionToCreate);

                Message = string.Format("Question Created Successfully{0}", extraMessage);

                if (viewModel.Category != null)
                {
                    return this.RedirectToAction<CategoryController>(a => a.Edit(viewModel.Category.Id));
                }
                return this.RedirectToAction<SurveyController>(a => a.Edit(survey.Id));
            }
            return View(viewModel);
        }
        public ActionResult Edit(int id, int surveyId, int? categoryId, Question question, ResponsesParameter[] response)
        {
            //To check if there are related answers, we need to check two things:
            //  1) Does this question have related answers
            //  2) Does the related Category have related answers (cauz we might be moving the question to a different category)
            //If there are related answers we may have to version one or both categories
            //And we need to check if we need to version
            //  1) Moving question to a different category
            //  2) Active changed
            //  3) Open Ended Changed
            //  4) Response added
            //  5) Response Hidden/Unhidden (Response.IsActive)
            //  6) quesion (name) is changed

            var originalCategoryId = 0;
            var newCategoryId = 0;
            var originalCategoryHasAnswers = false;
            var newCategoryHasAnswers = false;
            var originalHasChanges = false;
            var newHasChanges = false;

            var survey = Repository.OfType<Survey>().GetNullableById(surveyId);
            if (survey == null)
            {
                Message = "Survey Not Found";
                return this.RedirectToAction<ErrorController>(a => a.Index());
            }

            var questionToEdit = _questionRepository.GetNullableById(id);
            if (questionToEdit == null)
            {
                Message = "Question Not Found.";
                return this.RedirectToAction<SurveyController>(a => a.Edit(survey.Id));
            }

            //Save the Id of the original Category in case we need to version it.
            originalCategoryId = questionToEdit.Category.Id;
            originalCategoryHasAnswers = Repository.OfType<Answer>().Queryable.Where(a => a.Category.Id == originalCategoryId).Any();
            if (question.Category != null && question.Category.Id != originalCategoryId)
            {
                newCategoryId = question.Category.Id;
                newCategoryHasAnswers = Repository.OfType<Answer>().Queryable.Where(a => a.Category.Id == newCategoryId).Any();
            }

            var viewModel = QuestionViewModel.Create(Repository, survey);
            if (categoryId != null)
            {
                var category = Repository.OfType<Category>().GetNullableById(categoryId.Value);
                viewModel.Category = category;
            }
            viewModel.Question = question;

            // never removed saved responses, only make them inactive.
            var cleanedResponse = new List<ResponsesParameter>();
            foreach (var responsesParameter in response.OrderBy(a => a.Order))
            {
                if (responsesParameter.ResponseId != 0)
                {
                    cleanedResponse.Add(responsesParameter);
                }
                else if (!string.IsNullOrWhiteSpace(responsesParameter.Value) && !responsesParameter.Remove)
                {
                    cleanedResponse.Add(responsesParameter);
                }
            }
            viewModel.Responses = cleanedResponse;

            //Version Checks Part1
            if (originalCategoryHasAnswers) //original category and has answers
            {
                if (newCategoryId != 0) //Changed to a different Category
                {
                    //if we are changing the category, but the question was not active then there would not be any changes to the original category
                    if (questionToEdit.IsActive)
                    {
                        originalHasChanges = true;
                    }
                } else if (questionToEdit.IsActive != question.IsActive) //Active state changed
                {
                    originalHasChanges = true;
                } else if (questionToEdit.IsOpenEnded != question.IsOpenEnded) //OpenEnded Question Changed
                {
                    originalHasChanges = true;
                } else if (questionToEdit.OpenEndedQuestionType != question.OpenEndedQuestionType)  //type of open ended question changed
                {
                    originalHasChanges = true;
                } else if (questionToEdit.Name.ToLower() != question.Name.ToLower()) //Question (name) has changed
                {
                    originalHasChanges = true;
                } else if (viewModel.Responses.Count != questionToEdit.Responses.Count) //Number of possible responses has changed
                {
                    //Added
                    originalHasChanges = true;
                }
                else
                {
                    foreach (var responsesParameter in viewModel.Responses)
                    {
                        var foundResp = questionToEdit.Responses.Where(a => a.Id == responsesParameter.ResponseId).Single();
                        if (foundResp.Value.ToLower() != responsesParameter.Value.ToLower()) //Response Value (choice) has changed
                        {
                            originalHasChanges = true;
                            break;
                        } else if (foundResp.Score != responsesParameter.Score.GetValueOrDefault(0)) //Score has Changed
                        {
                            originalHasChanges = true;
                            break;
                        } else if (foundResp.IsActive == responsesParameter.Remove) //Hide response has changed
                        {
                            originalHasChanges = true;
                            break;
                        }
                    }
                }
            }
            if (newCategoryId != 0 && newCategoryHasAnswers)
            {
                var newCategory = Repository.OfType<Category>().GetNullableById(newCategoryId);
                if (newCategory != null)
                {
                    if (newCategory.IsActive && question.IsActive) //If the new Category isn't active it shouldn't have answers
                    {
                        newHasChanges = true;
                    }
                }
            }

            //Mapper.Map(question, questionToEdit);
            question.Responses.Clear();

            foreach (var responsesParameter in viewModel.Responses)
            {
                if (responsesParameter.ResponseId != 0)
                {
                    var foundResp = questionToEdit.Responses.Where(a => a.Id == responsesParameter.ResponseId).Single();
                    foundResp.Value = responsesParameter.Value;
                    foundResp.Score = responsesParameter.Score.GetValueOrDefault(0);
                    foundResp.IsActive = !responsesParameter.Remove;
                    foundResp.Order = responsesParameter.Order;
                    question.AddResponse(foundResp);
                }
                else
                {
                    var responseToAdd = new Response
                    {
                        Order = responsesParameter.Order,
                        IsActive = true,
                        Score = responsesParameter.Score.GetValueOrDefault(0),
                        Value = responsesParameter.Value
                    };

                    question.AddResponse(responseToAdd);
                }
            }
            question.Survey = questionToEdit.Survey;

            ModelState.Clear();
            question.TransferValidationMessagesTo(ModelState);

            foreach (var responsesParameter in cleanedResponse)
            {
                if (!responsesParameter.Score.HasValue)
                {
                    ModelState.AddModelError("Question", "All responses need a score");
                }
                if (question.IsOpenEnded && !responsesParameter.Remove)
                {
                    switch ((QuestionType)question.OpenEndedQuestionType)
                    {
                        case QuestionType.WholeNumber:
                            int number;
                            if (!int.TryParse(responsesParameter.Value, out number))
                            {
                                ModelState.AddModelError("Question", "Choices must be whole numbers");
                            }
                            break;
                        case QuestionType.Decimal:
                            float floatNumber;
                            if (!float.TryParse(responsesParameter.Value, out floatNumber))
                            {
                                ModelState.AddModelError("Question", "Choices must be numbers (decimal ok)");
                            }
                            break;
                        case QuestionType.Time:
                            float floatTime;
                            if (!responsesParameter.Value.TimeTryParse(out floatTime))
                            {
                                ModelState.AddModelError("Question", "Choices must be Time (hh:mm)");
                            }
                            break;
                        case QuestionType.TimeAmPm:
                            float floatTimeAmPm;
                            if (!responsesParameter.Value.TimeTryParseAmPm(out floatTimeAmPm))
                            {
                                ModelState.AddModelError("Question", "Choices must be Time (hh:mm AM/PM)");
                            }
                            break;
                        case QuestionType.TimeRange:
                            float timeRangeNumber;
                            if (!float.TryParse(responsesParameter.Value, out timeRangeNumber))
                            {
                                ModelState.AddModelError("Question", "Choices must be numbers (decimal ok)");
                            }
                            break;
                        default:
                            ModelState.AddModelError("Question", "time and time range not supported yet");
                            break;
                    }
                }
            }

            foreach (var responseCheck in question.Responses)
            {
                if (string.IsNullOrWhiteSpace(responseCheck.Value))
                {
                    ModelState.AddModelError("Question", string.Format("Response {0} must have a choice.", responseCheck.Order + 1));
                }
            }
            if (question.Responses.Where(a => a.IsActive).Count() == 0)
            {
                ModelState.AddModelError("Question", "Active Responses are required.");
            }

            if (question.Category != null && !question.Category.IsCurrentVersion)
            {
                ModelState.AddModelError("Question.Category", "Selected Category is not current.");
            }

            if (ModelState.IsValid)
            {
                string extraMessage1;
                string extraMessage2;

                #region Original Has Changes and needs to be versioned
                if (originalHasChanges)
                {
                    var newOriginalCategory = _archiveService.ArchiveCategory(
                        Repository,
                        originalCategoryId, questionToEdit);
                    if (newCategoryId == 0)
                    {
                        var newQuestion = new Question(question.Survey);
                        newQuestion.Category = newOriginalCategory;
                        newQuestion.IsActive = question.IsActive;
                        newQuestion.IsOpenEnded = question.IsOpenEnded;
                        newQuestion.OpenEndedQuestionType = question.OpenEndedQuestionType;
                        newQuestion.Name = question.Name;
                        newQuestion.PrimaryPhoto = question.PrimaryPhoto;
                        newQuestion.Order = questionToEdit.Order;
                        foreach (var responsesParameter in viewModel.Responses)
                        {
                            var responseToAdd = new Response
                            {
                                Order = responsesParameter.Order,
                                IsActive = !responsesParameter.Remove,
                                Score = responsesParameter.Score.GetValueOrDefault(0),
                                Value = responsesParameter.Value
                            };

                            newQuestion.AddResponse(responseToAdd);
                        }
                        foreach (var photo in questionToEdit.Photos) //This should work, but it needs to be tested.
                        {
                            var newPhoto = Repository.OfType<Photo>().Queryable.Single(a => a.Id == photo.Id);
                            newQuestion.Photos.Add(newPhoto);
                        }

                        question = newQuestion;
                        extraMessage1 = "Related Category Versioned";
                        extraMessage2 = string.Empty;

                        _questionRepository.EnsurePersistent(question);

                        Message = string.Format("Question Edited Successfully {0} {1}", extraMessage1, extraMessage2);

                        if (viewModel.Category != null)
                        {
                            return this.RedirectToAction<CategoryController>(a => a.Edit(newOriginalCategory.Id));
                        }
                        return this.RedirectToAction<SurveyController>(a => a.Edit(survey.Id));
                    }
                    else
                    {
                        if (newHasChanges)
                        {
                            var newNewCategory = _archiveService.ArchiveCategory(Repository, newCategoryId, questionToEdit);

                            var newQuestion = new Question(question.Survey);
                            newQuestion.Category = newNewCategory;
                            newQuestion.IsActive = question.IsActive;
                            newQuestion.IsOpenEnded = question.IsOpenEnded;
                            newQuestion.OpenEndedQuestionType = question.OpenEndedQuestionType;
                            newQuestion.Name = question.Name;
                            newQuestion.PrimaryPhoto = question.PrimaryPhoto;
                            newQuestion.Order = questionToEdit.Order;
                            foreach (var responsesParameter in viewModel.Responses)
                            {
                                var responseToAdd = new Response
                                {
                                    Order = responsesParameter.Order,
                                    IsActive = !responsesParameter.Remove,
                                    Score = responsesParameter.Score.GetValueOrDefault(0),
                                    Value = responsesParameter.Value
                                };

                                newQuestion.AddResponse(responseToAdd);
                            }
                            foreach (var photo in questionToEdit.Photos) //This should work, but it needs to be tested.
                            {
                                var newPhoto = Repository.OfType<Photo>().Queryable.Single(a => a.Id == photo.Id);
                                newQuestion.Photos.Add(newPhoto);
                            }

                            question = newQuestion;
                            extraMessage1 = "Previously Related Category Versioned";
                            extraMessage2 = "Newly Related Category Versioned";

                            _questionRepository.EnsurePersistent(question);

                            Message = string.Format("Question Edited Successfully {0} {1}", extraMessage1, extraMessage2);

                            if (viewModel.Category != null)
                            {
                                return this.RedirectToAction<CategoryController>(a => a.Edit(newOriginalCategory.Id));
                            }
                            return this.RedirectToAction<SurveyController>(a => a.Edit(survey.Id));
                        }
                        else
                        {
                            var newQuestion = new Question(question.Survey);
                            newQuestion.Category = question.Category;
                            newQuestion.IsActive = question.IsActive;
                            newQuestion.IsOpenEnded = question.IsOpenEnded;
                            newQuestion.OpenEndedQuestionType = question.OpenEndedQuestionType;
                            newQuestion.Name = question.Name;
                            newQuestion.PrimaryPhoto = question.PrimaryPhoto;
                            newQuestion.Order = questionToEdit.Order;
                            foreach (var responsesParameter in viewModel.Responses)
                            {
                                var responseToAdd = new Response
                                {
                                    Order = responsesParameter.Order,
                                    IsActive = !responsesParameter.Remove,
                                    Score = responsesParameter.Score.GetValueOrDefault(0),
                                    Value = responsesParameter.Value
                                };

                                newQuestion.AddResponse(responseToAdd);
                            }
                            foreach (var photo in questionToEdit.Photos) //This should work, but it needs to be tested.
                            {
                                var newPhoto = Repository.OfType<Photo>().Queryable.Single(a => a.Id == photo.Id);
                                newQuestion.Photos.Add(newPhoto);
                            }

                            question = newQuestion;
                            extraMessage1 = "Previously Related Category Versioned";
                            extraMessage2 = "Newly Related Category Not Versioned";

                            _questionRepository.EnsurePersistent(question);

                            Message = string.Format("Question Edited Successfully {0} {1}", extraMessage1, extraMessage2);

                            if (viewModel.Category != null)
                            {
                                return this.RedirectToAction<CategoryController>(a => a.Edit(newOriginalCategory.Id));
                            }
                            return this.RedirectToAction<SurveyController>(a => a.Edit(survey.Id));
                        }

                    }

                }
                #endregion Original Has Changes and needs to be versioned

                #region Original Is not Versioned, but new Category Is

                if (newHasChanges)
                {
                    var newNewCategory = _archiveService.ArchiveCategory(Repository, newCategoryId, questionToEdit);

                    var newQuestion = new Question(question.Survey);
                    newQuestion.Category = newNewCategory;
                    newQuestion.IsActive = question.IsActive;
                    newQuestion.IsOpenEnded = question.IsOpenEnded;
                    newQuestion.OpenEndedQuestionType = question.OpenEndedQuestionType;
                    newQuestion.Name = question.Name;
                    newQuestion.PrimaryPhoto = question.PrimaryPhoto;
                    newQuestion.Order = questionToEdit.Order;
                    foreach (var responsesParameter in viewModel.Responses)
                    {
                        var responseToAdd = new Response
                        {
                            Order = responsesParameter.Order,
                            IsActive = !responsesParameter.Remove,
                            Score = responsesParameter.Score.GetValueOrDefault(0),
                            Value = responsesParameter.Value
                        };

                        newQuestion.AddResponse(responseToAdd);
                    }
                    foreach (var photo in questionToEdit.Photos) //This should work, but it needs to be tested.
                    {
                        var newPhoto = Repository.OfType<Photo>().Queryable.Single(a => a.Id == photo.Id);
                        newQuestion.Photos.Add(newPhoto);
                    }

                    question = newQuestion;

                    extraMessage1 = "Previously Related Category Not Versioned";
                    extraMessage2 = "Newly Related category Versioned";

                    _questionRepository.EnsurePersistent(question);

                    Message = string.Format("Question Edited Successfully {0} {1}", extraMessage1, extraMessage2);

                    if (viewModel.Category != null)
                    {
                        return this.RedirectToAction<CategoryController>(a => a.Edit(viewModel.Category.Id));
                    }
                    return this.RedirectToAction<SurveyController>(a => a.Edit(survey.Id));

                }
                #endregion Original Is not Versioned, but new Category Is

                #region No Versioning, editing as normal

                Mapper.Map(question, questionToEdit);

                questionToEdit.Responses.Clear();

                foreach (var responsesParameter in viewModel.Responses)
                {
                    if (responsesParameter.ResponseId != 0)
                    {
                        var foundResp = question.Responses.Where(a => a.Id == responsesParameter.ResponseId).Single();
                        foundResp.Value = responsesParameter.Value;
                        foundResp.Score = responsesParameter.Score.GetValueOrDefault(0);
                        foundResp.IsActive = !responsesParameter.Remove;
                        foundResp.Order = responsesParameter.Order;
                        questionToEdit.AddResponse(foundResp);
                    }
                    else
                    {
                        var responseToAdd = new Response
                        {
                            Order = responsesParameter.Order,
                            IsActive = true,
                            Score = responsesParameter.Score.GetValueOrDefault(0),
                            Value = responsesParameter.Value
                        };

                        questionToEdit.AddResponse(responseToAdd);
                    }
                }

                _questionRepository.EnsurePersistent(questionToEdit);

                Message = "Question Edited Successfully";

                if (viewModel.Category != null)
                {
                    return this.RedirectToAction<CategoryController>(a => a.Edit(questionToEdit.Category.Id));
                }
                return this.RedirectToAction<SurveyController>(a => a.Edit(survey.Id));

                #endregion No Versioning, editing as normal

            }
            else
            {
                viewModel.UniqueTags = Repository.OfType<PhotoTag>().Queryable.OrderBy(b => b.Name).Select(a => a.Name).Distinct().ToList();
                return View(viewModel);
            }
        }