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

namespace EduNetworkBuilder
{
    /// <summary>
    /// We have settings that need to be loaded and saved.  Mono has issues with 
    /// properties.settings.default stuff, so we need to load/save from an xml file
    /// when we are using mono.  So this class does that
    /// </summary>
    public class NBSettings
    {
        protected bool BelongsToUser = false;
        public int FileHistoryCount = 5;
        public string LastPath = "";
        public List<string> ScoreList = new List<string>();
        public List<string> RecentFiles = new List<string>();
        public List<string> PuzzlesPassed = new List<string>();
        public List<string> PuzzlesFailed = new List<string>();
        public bool AutoStartPuzzles = true;
        public string ChosenLanguage = "en";
        public bool LanguageHasBeenChosen = false;
        public int MainWindowX = -1;
        public int MainWindowY = -1;
        public int MainWindowWidth = -1;
        public int MainWindowHeight = -1;
        public string ProcessingLevel = "none";
        public UInt32 NextID = 100;
        public bool AutoDHCPAllMachinesAtNetworkLoad = false; //Mainly for teachers
        public string LastTrans1Lang = "";
        public string LastTrans2Lang = "";
        public string FormLastTransDir = "";
        public int MillisecondsBetweenPacketMoves = NB.MillisecondsBetweenPacketMoves; //How quick do packets move
        [XmlIgnore] //it is protected so it should not be serialized anyway.
        protected ActionCollection UserActions = new ActionCollection();
        [XmlIgnore]
        public bool ReplayMode = false; //Whether or not we are able to do replays
        
        public NBSettings()
        {
            //We need this for reflection
            BelongsToUser = true; //Only true when using reflection (serialization)
        }
        public NBSettings(NBSettings fromSettings)
        {
            if (fromSettings == null) return; //Break if we are going to error out.
            Duplicate(fromSettings, this);
        }

        public void RegisterNetAsStarted(Network newnet)
        {
            UserActions.RegisterNet(newnet);
        }
        public void RegisterActionDone(ActionClass What)
        {
            UserActions.Add(What);
        }
        public void RegisterReplayPassed(string networkname = "")
        {
            if (UserActions == null) return;
            NetworkAction NA;
            if (networkname == "")
                NA = UserActions.GetCurrentNetAction();
            else NA = UserActions.FindAction(networkname);
            if (NA != null)
            {
                NA.SetPassed();
                if (!PuzzlesPassed.Contains(NA.NetworkName)) PuzzlesPassed.Add(NA.NetworkName);
                if (PuzzlesFailed.Contains(NA.NetworkName)) PuzzlesFailed.Remove(NA.NetworkName);
            }
        }
        public void RegisterReplayFailed(string networkname = "")
        {
            if (UserActions == null) return;
            NetworkAction NA;
            if (networkname == "")
                NA = UserActions.GetCurrentNetAction();
            else NA = UserActions.FindAction(networkname);
            if (NA != null)
            {
                NA.SetFailed();
                if (!PuzzlesFailed.Contains(NA.NetworkName)) PuzzlesFailed.Add(NA.NetworkName);
                if (PuzzlesPassed.Contains(NA.NetworkName)) PuzzlesPassed.Remove(NA.NetworkName);
            }
        }

        public void ClearReplayStatus()
        {
            if (UserActions == null) return;
            foreach(NetworkAction NA in UserActions.NetActions)
            {
                NA.HasFailed = false;
                NA.HasPassed = false;
            }
            PuzzlesPassed.Clear();
            PuzzlesFailed.Clear();

        }

        public ActionCollection GetUserActionCollection()
        {
            return UserActions;
        }

        static void Duplicate(NBSettings FromClass, NBSettings ToClass)
        {
            if (FromClass == null) return; //Break if we are going to error out.
            if (ToClass == null) return; //Break if we are going to error out.
                                         //
            if (Properties.Settings.Default.ScoreList == null)
                Properties.Settings.Default.ScoreList = new System.Collections.Specialized.StringCollection();
            if (Properties.Settings.Default.RecentFiles == null)
                Properties.Settings.Default.RecentFiles = new System.Collections.Specialized.StringCollection();
            if (Properties.Settings.Default.PuzzlesFailed == null)
                Properties.Settings.Default.PuzzlesFailed = new System.Collections.Specialized.StringCollection();
            if (Properties.Settings.Default.PuzzlesPassed == null)
                Properties.Settings.Default.PuzzlesPassed = new System.Collections.Specialized.StringCollection();

            ToClass.LastPath = FromClass.LastPath;
            ToClass.AutoStartPuzzles = FromClass.AutoStartPuzzles;
            ToClass.ChosenLanguage = FromClass.ChosenLanguage;
            ToClass.LanguageHasBeenChosen = FromClass.LanguageHasBeenChosen;
            ToClass.MainWindowX = FromClass.MainWindowX;
            ToClass.MainWindowY = FromClass.MainWindowY;
            ToClass.MainWindowHeight = FromClass.MainWindowHeight;
            ToClass.MainWindowWidth = FromClass.MainWindowWidth;
            ToClass.BelongsToUser = FromClass.BelongsToUser;
            ToClass.AutoDHCPAllMachinesAtNetworkLoad = FromClass.AutoDHCPAllMachinesAtNetworkLoad;
            ToClass.FormLastTransDir = FromClass.FormLastTransDir;
            ToClass.MillisecondsBetweenPacketMoves = FromClass.MillisecondsBetweenPacketMoves;

            foreach (string one in FromClass.ScoreList)
            {
                if (!ToClass.ScoreList.Contains(one))
                    ToClass.ScoreList.Add(one);
            }
            foreach (string one in FromClass.RecentFiles)
            {
                if (!ToClass.RecentFiles.Contains(one))
                    ToClass.RecentFiles.Add(one);
            }
            foreach (string one in FromClass.PuzzlesPassed)
            {
                if (!ToClass.PuzzlesPassed.Contains(one))
                    ToClass.PuzzlesPassed.Add(one);
            }
            foreach (string one in FromClass.PuzzlesFailed)
            {
                if (!ToClass.PuzzlesFailed.Contains(one))
                    ToClass.PuzzlesFailed.Add(one);
            }
        }

        public NBSettings(bool UsingMono)
        {
            if(UsingMono)
            {
                try
                {
                    //Try loading from xml file
                    string filename = GetFilename();
                    if (File.Exists(filename))
                    {
                        XmlSerializer sr = new XmlSerializer(this.GetType());
                        TextReader Reader = new StreamReader(filename);
                        NBSettings settings = (NBSettings)sr.Deserialize(Reader);
                        Duplicate(settings, this);
                        Reader.Close();
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show("Error Loading Settings:\n" + e.ToString(),"Error Loading Settings");
                }
            }
            else
            {
                if (Properties.Settings.Default.ScoreList == null)
                    Properties.Settings.Default.ScoreList = new System.Collections.Specialized.StringCollection();
                if (Properties.Settings.Default.RecentFiles == null)
                    Properties.Settings.Default.RecentFiles = new System.Collections.Specialized.StringCollection();
                if (Properties.Settings.Default.PuzzlesFailed == null)
                    Properties.Settings.Default.PuzzlesFailed = new System.Collections.Specialized.StringCollection();
                if (Properties.Settings.Default.PuzzlesPassed == null)
                    Properties.Settings.Default.PuzzlesPassed = new System.Collections.Specialized.StringCollection();

                LastPath = Properties.Settings.Default.LastPath;
                AutoStartPuzzles = Properties.Settings.Default.AutoStartPuzzles;
                ChosenLanguage = Properties.Settings.Default.ChosenLanguage;
                LanguageHasBeenChosen = Properties.Settings.Default.LanguageHasBeenChosen;
                MainWindowX = Properties.Settings.Default.MainWindowX;
                MainWindowY = Properties.Settings.Default.MainWindowY;
                MainWindowHeight = Properties.Settings.Default.MainWindowHeight;
                MainWindowWidth = Properties.Settings.Default.MainWindowWidth;
                AutoDHCPAllMachinesAtNetworkLoad = Properties.Settings.Default.AutoDHCP;
                LastTrans1Lang = Properties.Settings.Default.LastTrans1Lang;
                LastTrans2Lang = Properties.Settings.Default.LastTrans2Lang;
                FormLastTransDir = Properties.Settings.Default.FormTransLastDir;
                //MillisecondsBetweenPacketMoves = Properties.Settings.Default.MSBetweenPacketMoves; //For the moment we do not have a place to edit this.  Do not save it so we can change it easier through code

                foreach (string one in Properties.Settings.Default.ScoreList)
                {
                    if (!ScoreList.Contains(one))
                        ScoreList.Add(one);
                }
                foreach (string one in Properties.Settings.Default.PuzzlesFailed)
                {
                    if (!PuzzlesFailed.Contains(one))
                        PuzzlesFailed.Add(one);
                }
                foreach (string one in Properties.Settings.Default.PuzzlesPassed)
                {
                    if (!PuzzlesPassed.Contains(one))
                        PuzzlesPassed.Add(one);
                }
            }
        }

        public void MarkAsDone(string PuzzleName)
        {            
            //we just mark it in the settings class
            if (!ScoreList.Contains(PuzzleName))
            {
                ScoreList.Add(PuzzleName);
                Save();
            }
        }

        public void LoadReplays()
        {
            ReplayMode = true;
            UserActions = NB.ReadFromXmlResource<ActionCollection>("EduNetworkReplay");
            foreach (NetworkAction NetAction in UserActions.NetActions)
            {
                NetAction.HasBeenStored = true; //All of them start out stored
                NetAction.HasFailed = false;
                NetAction.HasPassed = false;
            }
            UserActions.HasUnsavedChanges = false; //we have just loaded a clean thing.  Nothing to save
        }

        public bool HasReplay(string networkname)
        {
            if (UserActions == null) return false;
            NetworkAction NA = UserActions.FindAction(networkname);
            if (NA == null) return false;
            return true;
        }
        public bool HasPassed(string networkname)
        {
            if (UserActions == null) return false;
            if (PuzzlesPassed.Contains(networkname)) return true;
            NetworkAction NA = UserActions.FindAction(networkname);
            if (NA == null) return false;
            return NA.HasPassed;
        }
        public bool HasFailed(string networkname)
        {
            if (UserActions == null) return false;
            if (PuzzlesFailed.Contains(networkname)) return true;

            NetworkAction NA = UserActions.FindAction(networkname);
            if (NA == null) return false;
            return NA.HasFailed;
        }
        public void SetPassed(string networkname)
        {
            RegisterReplayPassed(networkname);
        }
        public void SetFailed(string networkname)
        {
            RegisterReplayFailed(networkname);
        }
        public bool CheckIfDone(string PuzzleName)
        {            
            //we just mark it in the settings class
            if (ScoreList.Contains(PuzzleName))
                return true;
            else
                return false;

        }

        public static string GetFilename()
        {
            string BaseDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            string FileName = "EduNetworkBuilder_config.xml";
            return Path.Combine(BaseDir, FileName);
        }

        public void RegisterFileAsLoaded(string FilenameWithPath)
        {
            //Remove it from these settings
            if (RecentFiles.Contains(FilenameWithPath)) RecentFiles.Remove(FilenameWithPath);
            RecentFiles.Insert(0,FilenameWithPath);
            if(RecentFiles.Count > FileHistoryCount)
                for (int index = RecentFiles.Count - 1; index >= FileHistoryCount; index--)
                    RecentFiles.RemoveAt(index);

            if (!NB.IsRunningOnMono())
            {
                if (Properties.Settings.Default.RecentFiles.Contains(FilenameWithPath))
                    Properties.Settings.Default.RecentFiles.Remove(FilenameWithPath);
                Properties.Settings.Default.RecentFiles.Insert(0, FilenameWithPath);
                if (Properties.Settings.Default.RecentFiles.Count > FileHistoryCount)
                {
                    for (int index = Properties.Settings.Default.RecentFiles.Count - 1; index >= FileHistoryCount; index--)
                        Properties.Settings.Default.RecentFiles.RemoveAt(index);
                }
                Properties.Settings.Default.Save();
            }
        }

        public List<string> GetRecentFiles()
        {
            //If we do not have a user and are not using mono, grab the settings from properties.settings
            //Otherwise, we grab the settings from this settings object
            List<string> TheFiles = new List<string>();
            if(NB.GetUser() == null && !NB.IsRunningOnMono())
            {
                foreach (string one in Properties.Settings.Default.RecentFiles)
                    TheFiles.Add(one);
            }
            else
            {
                //This is the repository of recent files.  Use it
                TheFiles.AddRange(RecentFiles);
            }
            return TheFiles;
        }

        public void Save()
        {
            Save(NB.IsRunningOnMono());
        }

        public UInt64 IssueID()
        {
            //return the id and increment it.
            return NextID++;
        }

        /// <summary>
        /// We are saving the ReplayActions.  Right now, we are doing this for automatic testing
        /// of the puzzles.  Regression Testing
        /// </summary>
        public void SaveActions()
        {
            NB.WriteToXmlFile(@"c:\Users\TimYo\Desktop\EduNetworkReplay.xml", UserActions);
        }

        public void Save(bool UsingMono)
        {
            if(UsingMono)
            {
                //Save it to an XML file.
                try
                {
                    string filename = GetFilename();
                    if(!Directory.Exists(Path.GetDirectoryName(filename)))
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(filename));
                    }
                    XmlSerializer sr = new XmlSerializer(this.GetType());
                    TextWriter writer = new StreamWriter(filename);
                    sr.Serialize(writer, this);
                    writer.Close();
                }
                catch(Exception e)
                {
                    MessageBox.Show("ERROR Saving Settings:\n" + e.ToString(),"Error saving settings.");
                }
            }
            else
            {
                if (Properties.Settings.Default.ScoreList == null)
                    Properties.Settings.Default.ScoreList = new System.Collections.Specialized.StringCollection();
                if(NB.GetUser() == null)
                {
                    Properties.Settings.Default.AutoStartPuzzles = AutoStartPuzzles;
                    Properties.Settings.Default.LanguageHasBeenChosen = LanguageHasBeenChosen;
                }
                else
                {
                    Properties.Settings.Default.AutoStartPuzzles = AutoStartPuzzles;
                    Properties.Settings.Default.LanguageHasBeenChosen = LanguageHasBeenChosen;
                }
                Properties.Settings.Default.LastPath = LastPath;
                Properties.Settings.Default.ChosenLanguage = ChosenLanguage;
                Properties.Settings.Default.MainWindowX = MainWindowX;
                Properties.Settings.Default.MainWindowY = MainWindowY;
                Properties.Settings.Default.MainWindowHeight = MainWindowHeight;
                Properties.Settings.Default.MainWindowWidth = MainWindowWidth;
                Properties.Settings.Default.AutoDHCP = AutoDHCPAllMachinesAtNetworkLoad;
                Properties.Settings.Default.LastTrans1Lang = LastTrans1Lang;
                Properties.Settings.Default.LastTrans2Lang = LastTrans2Lang;
                Properties.Settings.Default.FormTransLastDir = FormLastTransDir;
                Properties.Settings.Default.MSBetweenPacketMoves = MillisecondsBetweenPacketMoves;

                Properties.Settings.Default.ScoreList.Clear();
                foreach(string One in ScoreList)
                {
                    Properties.Settings.Default.ScoreList.Add(One);
                }

                Properties.Settings.Default.PuzzlesFailed.Clear();
                foreach (string One in PuzzlesFailed)
                {
                    Properties.Settings.Default.PuzzlesFailed.Add(One);
                }
                Properties.Settings.Default.PuzzlesPassed.Clear();
                foreach (string One in PuzzlesPassed)
                {
                    Properties.Settings.Default.PuzzlesPassed.Add(One);
                }

                Properties.Settings.Default.Save();
            }
        }

    }
}
