/// <summary>
        /// Initialize test
        /// </summary>
        /// <param name="subjectIds">Subject ids in which questions taking</param>
        /// <param name="testType">Test type</param>
        /// <param name="sourceType">See TestSourceTypes class</param>
        /// <param name="source">Nullable id of source</param>
        /// <returns></returns>
        private ActionResult StartTest(IEnumerable <int> subjectIds, TestType testType, int sourceType, int?source)
        {
            if (subjectIds == null || !subjectIds.Any())
            {
                return(RedirectToAction("Index", "Home"));
            }

            var questionBank = new QuestionBank();
            var questions    =
                _db.Questions.Where(
                    x => subjectIds.Contains(x.SubjectID) && x.IsPublished && x.Answers.Any());

            if (!questions.Any())
            {
                return(RedirectToAction("Error", new { message = "Для теста не найдено ни одного вопроса. Обратитесь к администратору." }));
            }

            for (int i = 1; i <= 10; i++)
            {
                questionBank.Questions.Add(new List <int>(questions.Where(x => x.Difficulty == i).Select(x => x.ID)));
            }

            var testData = new TestData
            {
                TestCompleted        = false,
                TrueDifficultyLevel  = 5,
                SubjectsIds          = subjectIds.ToList(),
                QuestionBank         = questionBank,
                Started              = TimeManager.GetCurrentTime(),
                TestType             = testType,
                MaxAmountOfQuestions = _db.Questions.Count(x => subjectIds.Contains(x.SubjectID) && x.IsPublished),
                SourceType           = sourceType,
                Source = source,
            };

            Question selectedQuestion = GetQuestion(testData);

            testData.TestSeed = TemplateManager.GetRandomSeed();
            testData.CurrentQuestionDifficulty = selectedQuestion.Difficulty;
            testData.CurrentQuestionId         = selectedQuestion.ID;

            SetTestData(testData);

            return(RedirectToAction("Index"));
        }
 /// <summary>
 /// Calculate best difficulty level based on pass/fail attempts
 /// </summary>
 /// <param name="question">Question</param>
 public static int GetQuestionBestDifficultyLevel(Question question)
 {
     var result = (question.TotalAttempts == 0) ? 5 : 10 - (int)(Math.Round((float)question.RightAttempts * 10 / question.TotalAttempts));
     return (result == 0) ? 1 : result;
 }
 public ActionResult CreateAndContinue(Question question)
 {
     return Create(question, "Question");
 }
 public ActionResult CreateAndBack(Question question)
 {
     return Create(question, "Subject");
 }
        /// <summary>
        /// Creates question
        /// </summary>
        /// <param name="question"></param>
        /// <param name="controller">Controller name for redirection</param>
        /// <returns></returns>
        private ActionResult Create(Question question, string controller)
        {
            if (ModelState.IsValid)
            {
                _db.Questions.AddObject(question);
                _db.SaveChanges();
                return RedirectToAction("Edit", controller,
                                        new { id = question.ID });
            }

            ViewBag.Types = GetQuestionTypes();
            return View("Create");
        }
 public ActionResult Edit(Question question)
 {
     if (ModelState.IsValid)
     {
         _db.Questions.Attach(question);
         _db.ObjectStateManager.ChangeObjectState(question,EntityState.Modified);
         _db.SaveChanges();
     }
     ViewBag.Types = GetQuestionTypes();
     return View(question);
 }
 /// <summary>
 /// Deprecated Method for adding a new object to the Questions EntitySet. Consider using the .Add method of the associated ObjectSet&lt;T&gt; property instead.
 /// </summary>
 public void AddToQuestions(Question question)
 {
     base.AddObject("Questions", question);
 }
 /// <summary>
 /// Create a new Question object.
 /// </summary>
 /// <param name="id">Initial value of the ID property.</param>
 /// <param name="body">Initial value of the Body property.</param>
 /// <param name="difficulty">Initial value of the Difficulty property.</param>
 /// <param name="subjectID">Initial value of the SubjectID property.</param>
 /// <param name="questionTypeID">Initial value of the QuestionTypeID property.</param>
 /// <param name="isPublished">Initial value of the IsPublished property.</param>
 /// <param name="totalAttempts">Initial value of the TotalAttempts property.</param>
 /// <param name="rightAttempts">Initial value of the RightAttempts property.</param>
 public static Question CreateQuestion(global::System.Int32 id, global::System.String body, global::System.Int32 difficulty, global::System.Int32 subjectID, global::System.Int32 questionTypeID, global::System.Boolean isPublished, global::System.Int32 totalAttempts, global::System.Int32 rightAttempts)
 {
     Question question = new Question();
     question.ID = id;
     question.Body = body;
     question.Difficulty = difficulty;
     question.SubjectID = subjectID;
     question.QuestionTypeID = questionTypeID;
     question.IsPublished = isPublished;
     question.TotalAttempts = totalAttempts;
     question.RightAttempts = rightAttempts;
     return question;
 }
        public ActionResult Process(FormCollection collection)
        {
            // Geting session information
            int      sessionId = 0;
            TestData testData  = GetTestData(out sessionId);


            // If test data is bad ending survey
            if (testData == null)
            {
                return(RedirectToAction("End"));
            }

            // If bad question token (for example student are trying to answer question previously cached in browser) redirecting to Index (will show last generated question)
            if (collection["QuestionToken"] != testData.GetQuestionHash())
            {
                return(RedirectToAction("Index"));
            }

            // Get previous question to check asnwer is correct
            GeneratedQuestion question =
                TemplateManager.Generate(testData.CurrentQuestionId,
                                         testData.TestSeed);

            // Remembering some nessasary data
            testData.ItemsTaken++;
            testData.TotalDifficultiesUsed += testData.CurrentQuestionDifficulty;



            // Calculating the amount that will change the difficulty
            double difficultyShift = 0.2 + (float)2 / testData.ItemsTaken;

            // Checking answer is correct
            bool answerIsCorrect = CheckAnswerIsCorrect(question, collection["Answers"]);

            // Saving to question information about its own statistic
            QuestionController.AddAttempt(testData.CurrentQuestionId, answerIsCorrect);

            // Adding data to 'ResultGraph'
            testData.AddPointToResultGraph(answerIsCorrect);
            // TODO: Temperory method for statistics. (Re)move
            testData.AddPointToRDF();

            // Correcting difficulty
            if (answerIsCorrect)
            {
                testData.TrueDifficultyLevel += difficultyShift;
                if (testData.TrueDifficultyLevel > 10)
                {
                    testData.TrueDifficultyLevel = 10;
                }

                testData.RightAnswersCount++;
            }
            else
            {
                testData.TrueDifficultyLevel -= difficultyShift;
                if (testData.TrueDifficultyLevel < 1)
                {
                    testData.TrueDifficultyLevel = 1;
                }
            }



            // TODO: Make CONST optional. For the next programmers' generation
            // Checking if measurement error lower than CONST
            var error   = testData.CalculateError();
            var measure = testData.CalculateMeasure();

            if (error <= 0.5)
            {
                testData.TestCompleted = true;
            }
            if (measure + error <= 1 || measure - error >= 10)
            {
                testData.TestCompleted = true;
            }

            //Check for test min length
            // TODO: Add some behaviors. For the next programmers' generation. For example different options for different test types.
            // If amount of taken question equals amount of total questions in test, mark test as completed.
            if (testData.ItemsTaken >= testData.MaxAmountOfQuestions)
            {
                testData.TestCompleted = true;
            }
            // TODO: Add min length to test data
            else if (testData.ItemsTaken < 10)
            {
                testData.TestCompleted = false;
            }

            // Selecting next question
            Question selectedQuestion = GetQuestion(testData);

            // Generates random seed, which helps to generate the same question from tamplate, if needed
            testData.TestSeed = TemplateManager.GetRandomSeed();

            // Remembering next question parameters
            testData.CurrentQuestionDifficulty = selectedQuestion.Difficulty;
            testData.CurrentQuestionId         = selectedQuestion.ID;

            // Saving test session
            SetTestData(testData, sessionId);

            // Continue test or end it depending on TestCompleted flag
            return((testData.TestCompleted) ? RedirectToAction("End") : RedirectToAction("Index"));
        }
        /// <summary>
        /// Returns GeneratedQuestion
        /// </summary>
        /// <param name = "templateId">Template id</param>
        /// <param name = "seed">Random seed</param>
        /// <returns></returns>
        public static GeneratedQuestion Generate(int templateId, int seed)
        {
            var result = new GeneratedQuestion();
            var rnd    = new Random(seed);

            // Get template from _db
            Question question =
                Db.Questions.FirstOrDefault(q => q.ID == templateId);

            if (question == null)
            {
                throw new Exception("Template not found");
            }

            result.Body         = question.Body;
            result.QuestionType = 1;
            result.Answers      = new List <GeneratedAnswer>();

            // Insert definitions to Body
            int tagsLength = TagStartInsert.Length + TagEndInsert.Length;

            for (int i = 0; i < result.Body.Length - tagsLength; i++)
            {
                if (result.Body.Substring(i, TagStartInsert.Length) !=
                    TagStartInsert)
                {
                    continue;
                }

                // We found start insert tag
                int tagStartInsertPosition = i;
                int definitionNamePosition = i + TagStartInsert.Length;
                for (i = definitionNamePosition;
                     i < result.Body.Length - TagEndInsert.Length;
                     i++)
                {
                    if (result.Body.Substring(i, TagEndInsert.Length) !=
                        TagEndInsert)
                    {
                        continue;
                    }

                    // We found end insert tag
                    string definitionName =
                        result.Body.Substring(definitionNamePosition,
                                              i - definitionNamePosition);
                    if (!string.IsNullOrEmpty(definitionName))
                    {
                        // Get definition from _db
                        Definition definition =
                            Db.Definitions.FirstOrDefault(
                                d => d.Name == definitionName);
                        if (definition != null)
                        {
                            // Get examples to definition from _db
                            List <Example> examples =
                                definition.Examples.Where(e => !e.IsAntiExample)
                                .ToList();
                            if (examples.Count == 0)
                            {
                                throw new Exception("Definition has no examples");
                            }

                            Example example =
                                examples[rnd.Next(0, examples.Count)];

                            // Replacing
                            string oldSubstr = TagStartInsert + definitionName +
                                               TagEndInsert;
                            result.Body = result.Body.Replace(oldSubstr,
                                                              example.Value.Trim
                                                                  ());
                            i = tagStartInsertPosition + example.Value.Length -
                                1;
                        }
                    }

                    break;
                }
            }

            // Get answers from _db
            List <Answer> answers = question.Answers.ToList();

            if (answers.Count == 0)
            {
                throw new Exception("Question has no answers");
            }
            foreach (Answer answer in answers)
            {
                var newAnswer = new GeneratedAnswer
                {
                    Body      = answer.Body,
                    IsCorrect = answer.IsCorrect
                };

                result.Answers.Add(newAnswer);
            }

            result.QuestionType = question.QuestionTypeID;
            return(result);
        }