using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.IO;
using System.Windows.Forms;

namespace EduNetworkBuilder
{
    public class PersonClass
    {
        public string filepath=""; //the path of the file.  We use the username as the file-name.
        public string StudentFilePath = "";//If admin, this is used to store the path of the directory where student files are stored.

        string _UserName="";
        /// <summary>
        /// The username of the person.  Will be used as a filename.  Cannot be changed once it is set
        /// </summary>
        public string UserName { get { return _UserName; } }
        /// <summary>
        /// The filename, without the path, of the file.  UserName + ".enbu"
        /// </summary>
        public string FileName { get { return UserName + ".enbu"; } }

        /// <summary>
        /// The full name of the person. Can have spaces and punctuation.  Can change as one wants it changed.
        /// </summary>
        public string FullName = "";  

        List<string> Passwords = new List<string>();

        string PasswordHint = "";
        /// <summary>
        /// The AltPassword is mainly used to hold the admin decrypting password.  The student account will
        /// use this to encrypt the student password, so the admin can open their file.
        /// </summary>
        string AltPassword = "";
        /// <summary>
        /// Used to determine if the user we are working with is the admin account.
        /// </summary>
        public bool isAdmin { get; protected set; }
        /// <summary>
        /// EverCompletedPuzzles is a list of puzzles that they have completed once.
        /// </summary>

        public List<SchoolworkClass> Projects = new List<SchoolworkClass>();

        public List<PersonClass> Students = new List<PersonClass>(); //only teachers (admins) will have students.

        public NBSettings UserSettings = new NBSettings();

        public bool ChangePassAtFirstLogin = true;

        private PersonClass()
        { }

        public PersonClass(String User, bool MakeAdmin)
        {
            _UserName = User;
            isAdmin = MakeAdmin;
        }

        public PersonClass(string Filename)
        {
            Load(Filename);
        }
        public PersonClass(XmlNode reader)
        {
            Load(reader);
        }


        public string Password(int index = 0)
        {
            if (Passwords.Count == 0) return "";
            if (index < 0) return "";
            if (index >= Passwords.Count) return "";
            return Passwords[index];
        }

        public void ChangePassword(string NewPassword)
        {
            Passwords.Insert(0, NewPassword);
            int maxPWs = 1;
            if (isAdmin)
                maxPWs = 10; //Admins store the last 10 passwords. If the admin changed his PW, we still need to decrypt the student's files
            for (int a = Passwords.Count - 1; a >= maxPWs; a--)
                Passwords.RemoveAt(a); //Remove all but the one password
        }

        #region Load and Save 
        //Load and save functions
        public void Load(string filename)
        {
            XmlDocument xmlDoc = new XmlDocument();
            if (File.Exists(filename))
            {
                xmlDoc.Load(filename);
                Load(xmlDoc);
            }
        }

        public void Load(XmlNode TheNode)
        {
            foreach (XmlNode Individual in TheNode.ChildNodes)
            {
                XmlNodeType myNodetype = Individual.NodeType;
                if (myNodetype == XmlNodeType.Element)
                {
                    switch (Individual.Name.ToLower())
                    {
                        case "edunetworkbuilderuser":
                        case "edunetworkbuilder":
                        case "user":
                            Load(Individual);
                            break;
                        case "username":
                            _UserName = Individual.InnerText;
                            break;
                        case "fullname":
                            FullName = Individual.InnerText;
                            break;
                        case "passwordhint":
                            PasswordHint = Individual.InnerText;
                            break;
                        case "altpassword":
                            AltPassword = Individual.InnerText;
                            break;
                        case "studentfilepath":
                            StudentFilePath = Individual.InnerText;
                            break;
                        case "isadmin":
                            bool isadmin = false;
                            bool.TryParse(Individual.InnerText, out isadmin);
                            isAdmin = isadmin;
                            break;
                        case "changepasswordatlogin":
                            bool changepw = false;
                            bool.TryParse(Individual.InnerText, out changepw);
                            ChangePassAtFirstLogin = changepw;
                            break;
                        case "password":
                            Passwords.Add(Individual.InnerText);
                            break;
                        case "settings":
                            UserSettings = NB.Deserialize<NBSettings>(Individual.InnerText);
                            break;
                        case "project":
                        case "schoolwork":
                            SchoolworkClass SWC = new SchoolworkClass(Individual);
                            Projects.Add(SWC);
                            break;
                        case "student":
                            PersonClass PC = new PersonClass(Individual);
                            Students.Add(PC);
                            break;
                    }
                }
            }
        }

        public void Save()
        {
            //Save to our pre-existing / pre-defined file
            string filename = Path.Combine(filepath, FileName);            
            Save(filename);
        }

        public void Save(string filename)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.NewLineOnAttributes = true;
            XmlWriter writer = XmlWriter.Create(filename, settings);

            //Now we write the file:
            writer.WriteStartDocument();
            writer.WriteStartElement("EduNetworkBuilderUser");
            writer.WriteComment("This is a user file for EduNetworkBuilder.");
            Save(writer);
            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Flush();
            writer.Close();
        }


        public void Save(XmlWriter writer, bool AsStudent=false)
        {
            //Save the language name
            //save the number of items
            //Save all the items
            string Element = "User";
            if (AsStudent) Element = "Student";
            writer.WriteStartElement(Element);
            writer.WriteElementString("UserName", UserName);
            writer.WriteElementString("FullName", FullName);
            writer.WriteElementString("PasswordHint", PasswordHint);
            if(isAdmin) //only admins have students, so they are the only ones who need to store this path
                writer.WriteElementString("StudentFilePath", StudentFilePath);
            writer.WriteElementString("AltPassword", AltPassword);
            writer.WriteElementString("IsAdmin", isAdmin.ToString());
            writer.WriteElementString("ChangePasswordAtLogin", ChangePassAtFirstLogin.ToString());
            string settingsstring = NB.SerializeObject<NBSettings>(UserSettings);
            writer.WriteElementString("Settings", settingsstring);

            foreach(string One in Passwords)
                writer.WriteElementString("Password", One);
            foreach (PersonClass PC in Students)
                PC.Save(writer, true); //Save as a student entry
            //Save all the devices
            foreach (SchoolworkClass One in Projects)
            {
                One.Save(writer);
            }
            writer.WriteEndElement();
        }
        #endregion

        public bool AddHomework(SchoolworkClass ToAdd)
        {
            //Check to see if we already exist
            foreach(SchoolworkClass one in Projects)
            {
                if (one.ThisID == ToAdd.ThisID) return false;
            }
            Projects.Add(ToAdd);
            return true;
        }

        /// <summary>
        /// Organize the projects into a nice project tree.
        /// </summary>
        /// <returns></returns>
        public TreeNode WorkTree(TreeNode theTop=null)
        {
            Projects.Sort((q, p) => p.DueDate.CompareTo(q.DueDate));

            List<SchoolworkClass> DrawFrom = new List<SchoolworkClass>();
            List<SchoolworkClass> MasterList = new List<SchoolworkClass>();

            DrawFrom.AddRange(Projects);
            for (int i = DrawFrom.Count - 1; i >= 0; i--)
            {
                if (DrawFrom[i].isMaster)
                {
                    MasterList.Add(DrawFrom[i]);
                    DrawFrom.RemoveAt(i);
                }
            }
            //Now, all the masters are in Master, and submitted projects are in DrawFrom.

            TreeNode Node;
            TreeNode Top;
            TreeNode Master;
            //We have a class tree
            if (theTop == null)
            {
                Top = new TreeNode(NB.Translate("PPF_Class"));
                Top.Tag = "Class"; //Do not translate this
            }
            else
            {
                Top = theTop;
            }
            foreach(SchoolworkClass MasterSW in MasterList)
            {
                Master = new TreeNode(MasterSW.Name);
                Master.Tag = MasterSW;

                for (int i = DrawFrom.Count -1; i>=0; i--)
                {
                    if(DrawFrom[i].ThisID == MasterSW.ThisID)
                    {
                        Node = new TreeNode(DrawFrom[i].Name);
                        Node.Tag = DrawFrom[i];
                        Master.Nodes.Add(Node);
                    }
                }
                Top.Nodes.Add(Master);
            }

            return Top;
        }

    }
}
