List<Models.Assessment.Assessment> MapAssessmentList(List<QuestionAnswer> query)
        {
            var list = new List<Models.Assessment.Assessment>();

            Models.Assessment.Assessment model = null;
            Models.Assessment.Question q = null;
            Models.Assessment.Answer a = null;
            int totalPages = 0;

            long responseId = -1;
            int qNo = -1;
            int aNo = -1;

            bool next_r = false;
            bool next_q = false;
            bool next_a = false;

            foreach (var item in query.OrderBy(x => x.ResponseId).ThenBy(x => x.QuestionNo).ThenBy(x => x.AnswerNo))
            {
                next_r = item.ResponseId != responseId;
                next_q = item.QuestionNo != qNo || next_r;
                next_a = item.AnswerNo != aNo || next_q;

                responseId = item.ResponseId;
                qNo = item.QuestionNo;
                aNo = item.AnswerNo;

                if (next_r)
                {
                    model = new Models.Assessment.Assessment();
                    list.Add(model);

                    model.ResponseId = item.ResponseId;
                    model.DateCreated = item.DateCreated;
                    model.Score = item.ScoreOverall;

                    model.CampaignId = item.CampaignId;
                    model.CampaignGuid = item.CampaignGuid;
                    model.CampaignName = item.CampaignName;
                    model.CampaignDescription = item.CampaignDescription;

                    totalPages = 0;
                }

                if (next_q)
                {
                    q = new Models.Assessment.Question();
                    model.Questions.Add(q);

                    q.OrderNo = item.QuestionNo;
                    q.AssessmentQuestionId = item.AssessmentQuestionId;
                    q.Type = (Models.Assessment.AnswerType)item.AnswerType;
                    q.Section = item.Section;
                    q.PageNo = item.PageNo;
                    q.Text = item.QuestionText;
                    q.AltText = item.AltText;
                    q.ValidationText = item.ValidationText;
                    q.Optional = item.Optional;
                    q.QuestionGroup = item.QuestionGroup;
                    q.QuestionGroupId = item.QuestionGroupId;

                    q.Name = "Q" + q.OrderNo;
                }

                if (next_a)
                {
                    a = new Models.Assessment.Answer();
                    q.Answers.Add(a);
                    if (item.AlternativeAnswer) q.AltAnswer = a;

                    a.OrderNo = item.AnswerNo;
                    a.QuestionItemId = item.QuestionItemId;
                    a.AnswerChoiceId = item.AnswerChoiceId;
                    a.Type = (Models.Assessment.AnswerType)item.ChoiceType;
                    a.Text = item.AnswerText;
                    a.Value = item.Encrypted ? _aes.Decrypt(item.Value) : item.Value;
                    a.DefaultValue = item.Encrypted ? _aes.Decrypt(item.DefaultValue) : item.DefaultValue;
                    a.Encrypted = item.Encrypted;
                    a.AlternativeAnswer = item.AlternativeAnswer;
                    a.AltQuestionItemId = item.AltQuestionItemId;
                    a.Score = item.Score;

                    // to be used as HTML input element name
                    a.Name = string.Format("Q{0}-{1}", q.OrderNo, a.OrderNo);
                }

                if (item.PageNo.HasValue && item.PageNo > totalPages) totalPages = (int)item.PageNo;
                model.TotalPages = totalPages;
            }

            return list;
        }
        // 1. read from the UI by answer Name or question Name
        // 2. match question definitiions stored in cashe by question No and answer No
        // 3. save in the db by question Id, question item Id and response Id
        private Assessment ProcessFormData(FormCollection form)
        {
            var model = new Assessment();

            // page number
            string name = "CurrentPage";
            string value = form[name];
            int pageNo = Helper.IntValue(value);
            model.CurrentPageNo = pageNo;

            // questions
            var questions = QuestionCache.GetQuestions(pageNo);

            // answers
            foreach(var question in questions)
            {
                var aq = new Models.Assessment.Question()
                {
                    Name = question.Name,
                    OrderNo = question.OrderNo,
                    AssessmentQuestionId = question.AssessmentQuestionId,
                    Type = question.Type,
                    PageNo = question.PageNo,
                };

                model.Questions.Add(aq);
                bool selected = false;

                foreach(var item in question.Answers)
                {
                    switch (item.Type)
                    {
                        case AnswerType.Integer:
                        case AnswerType.Text:
                            name = item.Name;       // item.Name
                            value = form[name];
                            selected = !string.IsNullOrEmpty(value);
                            break;
                        case AnswerType.DropDown:
                        case AnswerType.Radio:
                            name = question.Name;   // question.Name
                            value = form[name];
                            long choiceId = 0;
                            if (long.TryParse(value, out choiceId))
                            {
                                selected = choiceId == item.AnswerChoiceId;
                                value = null;
                            }
                            break;
                        case AnswerType.Checkbox:
                            name = item.Name;       // item.Name
                            value = form[name];

                            // false,false or true,false
                            var val = value.Split(',');
                            bool val0 = false;
                            bool val1 = false;

                            if (val.Length > 0)
                            {
                                bool.TryParse(val[0], out val0);
                                if (val.Length > 1) bool.TryParse(val[1], out val1);
                            }

                            selected = val0 || val1;
                            value = selected.ToString();
                            break;
                    }

                    // single choice questions: consider selected item
                    // multiple choice questions: consider all items
                    if (selected || item.Type == AnswerType.Checkbox)
                    {
                        var aac = new Models.Assessment.Answer()
                        {
                            Value = value,
                            Type = item.Type,
                            QuestionItemId = item.QuestionItemId,
                            AnswerChoiceId = item.AnswerChoiceId,
                            Name = item.Name,
                            Score = item.Score,
                            Selected = selected
                        };

                        aq.Answers.Add(aac);
                    }
                }
            }

            return model;
        }
        Models.Assessment.Assessment MapAssessment(List<QuestionAnswer> query)
        {
            var model = new Models.Assessment.Assessment();
            Models.Assessment.Question q = null;
            Models.Assessment.Answer a = null;
            int totalPages = 0;

            int qNo = -1;
            int aNo = -1;

            bool next_q = false;
            bool next_a = false;

            foreach (var item in query.OrderBy(x => x.QuestionNo).ThenBy(x => x.AnswerNo))
            {
                next_q = item.QuestionNo != qNo;
                next_a = item.AnswerNo != aNo || next_q;

                qNo = item.QuestionNo;
                aNo = item.AnswerNo;

                if (next_q)
                {
                    q = new Models.Assessment.Question();
                    model.Questions.Add(q);

                    q.OrderNo = item.QuestionNo;
                    q.AssessmentQuestionId = item.AssessmentQuestionId;
                    q.Type = (Models.Assessment.AnswerType)item.AnswerType;
                    q.Section = item.Section;
                    q.PageNo = item.PageNo;
                    q.Text = item.QuestionText;
                    q.AltText = item.AltText;
                    q.ValidationText = item.ValidationText;
                    q.Optional = item.Optional;
                    q.QuestionGroup = item.QuestionGroup;
                    q.QuestionGroupId = item.QuestionGroupId;

                    q.Name = "Q" + q.OrderNo;
                }

                if (next_a)
                {
                    a = new Models.Assessment.Answer();
                    q.Answers.Add(a);
                    if (item.AlternativeAnswer) q.AltAnswer = a;

                    a.OrderNo = item.AnswerNo;
                    a.QuestionItemId = item.QuestionItemId;
                    a.AnswerChoiceId = item.AnswerChoiceId;
                    a.Type = (Models.Assessment.AnswerType)item.ChoiceType;
                    a.Text = item.AnswerText;
                    a.Value = item.Encrypted ? _aes.Decrypt(item.Value) : item.Value;
                    a.DefaultValue = item.Encrypted ? _aes.Decrypt(item.DefaultValue) : item.DefaultValue;
                    a.Encrypted = item.Encrypted;
                    a.AlternativeAnswer = item.AlternativeAnswer;
                    a.AltQuestionItemId = item.AltQuestionItemId;
                    a.Score = item.Score;

                    if (a.Type == Models.Assessment.AnswerType.Checkbox)
                    {
                        bool selected = false;
                        bool.TryParse(a.Value, out selected);
                        a.Selected = selected;
                    }
                    else
                    {
                        a.Selected = true;
                    }

                    // to be used as HTML input element name
                    a.Name = string.Format("Q{0}-{1}", q.OrderNo, a.OrderNo);
                }

                if (item.PageNo.HasValue && item.PageNo > totalPages) totalPages = (int)item.PageNo;
            }

            model.TotalPages = totalPages;

            return model;
        }