using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

namespace TELTest {
    public class QuizContainer : IEquatable<QuizContainer> {
        public QuizContainer() {
            Created = DateTime.MinValue;
        }
        public string Title;
        public string Author;
        public string Password;
        public DateTime Created;
        public Guid Guid;
        public QuizQuestion[] Questions;
        public Visibility Visibility;
        public string SerializeXML() {
            XmlDocument xd = new XmlDocument();
            var quiz = xd.CreateNode(XmlNodeType.Element, "Quiz", null);
            var title = xd.CreateNode(XmlNodeType.Element, "Name", null);
            title.InnerText = Title;
            quiz.AppendChild(title);

            var author = xd.CreateNode(XmlNodeType.Element, "Author", null);
            author.InnerText = Author;
            quiz.AppendChild(author);

            var guid = xd.CreateNode(XmlNodeType.Element, "Guid", null);
            guid.InnerText = Guid + "";
            quiz.AppendChild(guid);

            var created = xd.CreateNode(XmlNodeType.Element, "Created", null);
            created.InnerText = Created.ToString("O");
            quiz.AppendChild(created);

            var pwd = xd.CreateNode(XmlNodeType.Element, "Password", null);
            pwd.InnerText = Password;
            quiz.AppendChild(pwd);

            var vis = xd.CreateNode(XmlNodeType.Element, "Visibility", null);
            vis.InnerText = ((int)Visibility) + "";
            quiz.AppendChild(vis);

            var questions = xd.CreateNode(XmlNodeType.Element, "Questions", null);
            foreach (var item in Questions) {
                var q = xd.CreateNode(XmlNodeType.Element, "Question", null);

                var cap = xd.CreateNode(XmlNodeType.Element, "Caption", null);
                cap.InnerText = item.Content;
                q.AppendChild(cap);

                foreach (var it2 in item.Answers) {
                    var ans = xd.CreateNode(XmlNodeType.Element, "Answer", null);
                    ans.InnerText = it2.Content;
                    if (it2.Correct) {
                        var attr = xd.CreateAttribute("Correct");
                        attr.InnerText = "True";
                        ans.Attributes.Append(attr);
                    }
                    q.AppendChild(ans);
                }
                questions.AppendChild(q);
            }
            quiz.AppendChild(questions);
            return quiz.OuterXml;
        }
        public static QuizContainer FromXml(string content) {
            XmlDocument xd = new XmlDocument();
            xd.LoadXml(content);

            QuizContainer qc = new QuizContainer();
            qc.Title = xd.GetElementsByTagName("Name")[0].InnerText;
            qc.Author = xd.GetElementsByTagName("Author")[0].InnerText;
            var pw = xd.GetElementsByTagName("Password");
            if (pw.Count != 0) {
                qc.Password = pw[0].InnerText;
            }

            var vs = xd.GetElementsByTagName("Visibility");
            if (vs.Count != 0) {
                qc.Visibility = (Visibility)int.Parse(vs[0].InnerText);
            }
            qc.Guid = Guid.Parse(xd.GetElementsByTagName("Guid")[0].InnerText.Trim());
            List<QuizQuestion> qst = new List<QuizQuestion>();
            var q = xd.GetElementsByTagName("Questions")[0];
            foreach (XmlNode item in q.ChildNodes) {
                QuizQuestion qq = new QuizQuestion();
                qq.Content = item["Caption"].InnerText;
                List<QuizQuestionAnswer> ass = new List<QuizQuestionAnswer>();
                var an = item.ChildNodes;
                foreach (XmlNode aw in an) {

                    if (aw.Name.ToUpper() != "ANSWER") continue;
                    ass.Add(new QuizQuestionAnswer() {
                        Content = aw.InnerText,
                        Correct = aw.Attributes["Correct"] != null && aw.Attributes["Correct"].InnerText.ToUpper() != "FALSE"
                    });
                }
                qq.Answers = ass.ToArray();
                qst.Add(qq);
            }
            qc.Questions = qst.ToArray();
            return qc;
        }
        public static QuizContainer FromQuizhouse_poor(string content) {
            TextReader tr = new StringReader(content);
            QuizContainer qc = new QuizContainer();
            qc.Title = tr.ReadLine();
            qc.Author = tr.ReadLine();
            qc.Questions = new QuizQuestion[5];
            for (int i = 0; i < 5; i++) {
                qc.Questions[i] = new QuizQuestion() {
                    Content = tr.ReadLine(),
                    Answers = new[] {
                        new QuizQuestionAnswer(){ Content = tr.ReadLine() },
                        new QuizQuestionAnswer(){ Content = tr.ReadLine() },
                        new QuizQuestionAnswer(){ Content = tr.ReadLine() },
                        new QuizQuestionAnswer(){ Content = tr.ReadLine() },
                    }
                };
                string corr = tr.ReadLine();
                switch (corr.ToUpper()[0]) {
                case 'A':
                    qc.Questions[i].Answers[0].Correct = true;
                    break;
                case 'B':
                    qc.Questions[i].Answers[1].Correct = true;
                    break;
                case 'C':
                    qc.Questions[i].Answers[2].Correct = true;
                    break;
                case 'D':
                    qc.Questions[i].Answers[3].Correct = true;
                    break;
                }
            }
            return qc;
        }

        public bool IsQuizhouse_poorCompliant() {
            if (string.IsNullOrWhiteSpace(Title)) return false;
            if (string.IsNullOrWhiteSpace(Author)) return false;
            if (Questions.Length != 5) return false;
            foreach (var item in Questions) {
                if (item.Answers.Length != 4) return false;
                int correctAnswers = 0;
                foreach (var answer in item.Answers) {
                    if (answer.Correct) correctAnswers++;
                }
                if (correctAnswers != 1) return false;
            }
            return true;
        }

        public string SerializeQuizhouse_poor() {
            if (!IsQuizhouse_poorCompliant()) return null;
            StringBuilder sb = new StringBuilder();
            sb.AppendLineRN(Title);
            sb.AppendLineRN(Author);
            for (int i = 0; i < 5; i++) {
                sb.AppendLineRN(Questions[i].Content);
                char correct = ' ';
                for (int j = 0; j < 4; j++) {
                    sb.AppendLineRN(Questions[i].Answers[j].Content);
                    if (Questions[i].Answers[j].Correct) correct = char.ToLower(Utilities.NumberToLetter(j)[0]);
                }
                sb.AppendLineRN(correct + "");
            }
            return sb.ToString();
        }

        public override Boolean Equals(Object obj) => this.Equals(obj as QuizContainer);
        public Boolean Equals(QuizContainer other) => !(other is null) && this.Title == other.Title && this.Author == other.Author && this.Password == other.Password && this.Created == other.Created && this.Guid.Equals(other.Guid) && Enumerable.SequenceEqual(this.Questions, other.Questions);
        //EqualityComparer<QuizQuestion[]>.Default.Equals(this.Questions, other.Questions);

        public override Int32 GetHashCode() {
            Int32 hashCode = -614606056;
            hashCode = hashCode * -1521134295 + EqualityComparer<String>.Default.GetHashCode(this.Title);
            hashCode = hashCode * -1521134295 + EqualityComparer<String>.Default.GetHashCode(this.Author);
            hashCode = hashCode * -1521134295 + EqualityComparer<String>.Default.GetHashCode(this.Password);
            hashCode = hashCode * -1521134295 + this.Created.GetHashCode();
            hashCode = hashCode * -1521134295 + this.Guid.GetHashCode();
            hashCode = hashCode * -1521134295 + EqualityComparer<QuizQuestion[]>.Default.GetHashCode(this.Questions);
            return hashCode;
        }

        public static Boolean operator ==(QuizContainer left, QuizContainer right) {
            return EqualityComparer<QuizContainer>.Default.Equals(left, right);
        }

        public static Boolean operator !=(QuizContainer left, QuizContainer right) {
            return !(left == right);
        }
    }
    public struct QuizQuestion : IEquatable<QuizQuestion> {
        public string Content;
        public QuizQuestionAnswer[] Answers;

        public override Boolean Equals(Object obj) => obj is QuizQuestion question && this.Equals(question);
        public Boolean Equals(QuizQuestion other) => this.Content == other.Content && Enumerable.SequenceEqual(this.Answers, other.Answers);

        public override Int32 GetHashCode() {
            Int32 hashCode = 2043989270;
            hashCode = hashCode * -1521134295 + EqualityComparer<String>.Default.GetHashCode(this.Content);
            hashCode = hashCode * -1521134295 + EqualityComparer<QuizQuestionAnswer[]>.Default.GetHashCode(this.Answers);
            return hashCode;
        }

        public static Boolean operator ==(QuizQuestion left, QuizQuestion right) {
            return left.Equals(right);
        }

        public static Boolean operator !=(QuizQuestion left, QuizQuestion right) {
            return !(left == right);
        }
    }
    public struct QuizQuestionAnswer : IEquatable<QuizQuestionAnswer> {
        public string Content;
        public bool Correct;

        public override Boolean Equals(Object obj) => obj is QuizQuestionAnswer answer && this.Equals(answer);
        public Boolean Equals(QuizQuestionAnswer other) => this.Content == other.Content && this.Correct == other.Correct;

        public override Int32 GetHashCode() {
            Int32 hashCode = -1538403773;
            hashCode = hashCode * -1521134295 + EqualityComparer<String>.Default.GetHashCode(this.Content);
            hashCode = hashCode * -1521134295 + this.Correct.GetHashCode();
            return hashCode;
        }

        public static Boolean operator ==(QuizQuestionAnswer left, QuizQuestionAnswer right) {
            return left.Equals(right);
        }

        public static Boolean operator !=(QuizQuestionAnswer left, QuizQuestionAnswer right) {
            return !(left == right);
        }
    }
}
