using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Text.RegularExpressions;
using System.Resources;
using System.Collections;
using System.ComponentModel.Design;


namespace EduNetworkBuilder
{
  

    public partial class TranslationWindow : Form
    {
        Network myNet = null;
        string[,] LanguageChoices = NB.LanguageChoices;
        string FormChosenDir = "";
        List<TranslationResxFile> TranslationResxFiles = new List<TranslationResxFile>();
        List<TranslationFormData> FormData = new List<TranslationFormData>();
        string EnglishTargetFile = "edustrings.resx";
        bool ChangedFormData = false;
        bool ChangedPuzzleData = false;
        ToolTip myTooltip = new ToolTip();


        public TranslationWindow(Network ToEdit)
        {
            InitializeComponent();
            this.KeyPreview = true;
            myNet = ToEdit;

            LocalSetup();
        }

        void LocalSetup()
        {
            FillTranslationFormData();

            myTooltip.AutoPopDelay = 5000;
            myTooltip.InitialDelay = 1000;
            myTooltip.ReshowDelay = 500;

            cb1Language.Items.Clear();
            cb2Language.Items.Clear();

            cbFormLang1Choice.Items.Clear();
            cbFormLang2Choice.Items.Clear();

            cbFormHighPriority.CheckedChanged += PopulateFormTranslationItems;
            cbFormShowTranslated.CheckedChanged += PopulateFormTranslationItems;

            cbFormFilter.Items.Clear();
            foreach(TranslationFormData TFD in FormData)
            {
                cbFormFilter.Items.Add(TFD.Prefix);
            }
            panelTranslateFormItems.Enabled = false;

            NBSettings mySettings = NB.GetSettings();

            //See if the file we are editing has the right folder.  If so, we do not need to choose one
            FormChosenDir = mySettings.FormLastTransDir;
            if (!TryToChooseFormDir(FormChosenDir))
                TryToChooseFormDir(Path.GetDirectoryName(myNet.NetworkFilename));

            for (int i = 0; i < LanguageChoices.GetLength(0); i++)
            {
                cb1Language.Items.Add(LanguageChoices[i, 0]);
                cb2Language.Items.Add(LanguageChoices[i, 0]);
                cbFormLang1Choice.Items.Add(LanguageChoices[i, 0]);
                cbFormLang2Choice.Items.Add(LanguageChoices[i, 0]);

                if (mySettings.LastTrans1Lang == LanguageChoices[i, 1])
                {
                    cb1Language.SelectedItem = LanguageChoices[i, 0];
                    cbFormLang1Choice.SelectedItem = LanguageChoices[i, 0];
                }
                if (mySettings.LastTrans2Lang == LanguageChoices[i, 1])
                {
                    cb2Language.SelectedItem = LanguageChoices[i, 0];
                    cbFormLang2Choice.SelectedItem = LanguageChoices[i, 0];
                }
            }
            if (cb1Language.SelectedIndex == -1) cb1Language.SelectedIndex = 0;
            if (cb2Language.SelectedIndex == -1) cb2Language.SelectedIndex = 0;
            Icon = Properties.Resources.NBIco;
            lblStatus.Text = "";
            LanguagifyComponents();

            cbFormFilter.Text = "Any";
        }

        private void LanguagifyComponents()
        {
            Text = NB.Translate("TW_Translate");
            btnSave.Text = NB.Translate("_Save");
            btnClose.Text = NB.Translate("_Done");
            tpMessageTitle.Text = NB.Translate("TW_Message");
            tpFormStuff.Text = NB.Translate("TW_Form");
        }

        private void FillTranslationFormData()
        {
            FormData.Clear();
            FormData.Add(new TranslationFormData("TW_", "Translation Window.  The Window where translation into another language is done.", 1));
            FormData.Add(new TranslationFormData("_", "Phrases which are used on multiple windows", 10));
            FormData.Add(new TranslationFormData("Any", "Not Filtered by form", 0));
            FormData.Add(new TranslationFormData("DC_", "Device Config Window.  This is where you configure the switch, firewall, PC, etc.", 10));
            FormData.Add(new TranslationFormData("H_", "The Help system.", 1));
            FormData.Add(new TranslationFormData("IPAE_", "IP Address Editor.  This is the IP Address Edit Window where you set the IP, subnet, gateway, etc", 9));
            FormData.Add(new TranslationFormData("LBW_", "ListBox Window.  This is mainly the list of puzzles.", 8));
            FormData.Add(new TranslationFormData("LE_", "LinkEditor.  This is where you define a network link between two devices", 6));
            FormData.Add(new TranslationFormData("N_", "Network.  The Network is basically the collection of devices, links, tests and the like.  Most of the things translated are status or error messages.", 4));
            FormData.Add(new TranslationFormData("NB_", "NetworkBuilder Window.  This is the main window and the menus on that window.", 10));
            FormData.Add(new TranslationFormData("NC_", "NetworkCard. The card itself mainly just generates error messages.", 4));
            FormData.Add(new TranslationFormData("NCE_", "Network Card Editor.  The window where you define the network card (VPN, Wireless card, etc)", 7));
            FormData.Add(new TranslationFormData("ND_", "Network Device.  The device is what generates most of the main error messages.", 8));
            FormData.Add(new TranslationFormData("NI_", "Network Interface.  This generates some error messages (VLAN, etc)", 3));
            FormData.Add(new TranslationFormData("NL_", "Network Link.  Generates some error messages when packets are corrupt.", 7));
            FormData.Add(new TranslationFormData("NT_", "Network Test.  These are the things that make the puzzles puzzling.", 10));
            FormData.Add(new TranslationFormData("NTE_", "Network Test Editor.  This is the window where you edit the network tests.", 2));
            FormData.Add(new TranslationFormData("OW_", "Options Window.  Where the puzzle options are configured.  Teachers use this, but most students would not", 3));
            FormData.Add(new TranslationFormData("Options_", "A few options which are used both on the options window, but also on the main window", 9));
            FormData.Add(new TranslationFormData("P_", "Packet.  The error messages that the packet itself generates.", 7));
            FormData.Add(new TranslationFormData("PC_", "Person Class.  When working with students and faculty.", 2));
            FormData.Add(new TranslationFormData("PM_", "Packet Messages.  The system for dealing with packet messages", 4));
            FormData.Add(new TranslationFormData("PPF_", "Person Profile Form.  When dealing with faculty / students.", 1));
            FormData.Add(new TranslationFormData("RPC_", "Random Puzzle Chooser.  The form for generating a random puzzle", 5));
            FormData.Add(new TranslationFormData("RTFW_", "RichText Window.  A multipurpose window.  Used for displaying help or the puzzle description.", 7));
            FormData.Sort((a, b) => a.Prefix.CompareTo(b.Prefix) );
        }

        private void ClosingStuff()
        {
            NBSettings mySettings = NB.GetSettings();
            for (int i = 0; i < LanguageChoices.GetLength(0); i++)
            {
                if (cb1Language.Text == LanguageChoices[i, 0])
                {
                    mySettings.LastTrans1Lang = LanguageChoices[i, 1];
                }
                if (cb2Language.Text == LanguageChoices[i, 0])
                {
                    mySettings.LastTrans2Lang = LanguageChoices[i, 1];
                }
                mySettings.FormLastTransDir = FormChosenDir;
            }
            mySettings.Save();
        }

        string CodeFromLang(string language)
        {
            for (int i = 0; i < LanguageChoices.GetLength(0); i++)
            {
                if (language == LanguageChoices[i, 0]) return LanguageChoices[i, 1];
            }
            return "";
        }

        string LangFromCode(string Code)
        {
            for (int i = 0; i < LanguageChoices.GetLength(0); i++)
            {
                if (Code == LanguageChoices[i, 1]) return LanguageChoices[i, 0];
            }
            return "";
        }

        private void btnClose_Click(object sender, EventArgs e)
        {            
            Close();
        }

        private void Save()
        {
            if (ChangedPuzzleData && File.Exists(myNet.NetworkFilename))
            {
                myNet.Save();
                //Console.WriteLine("Saved");
                lblStatus.Text = NB.Translate("_Saved");
            }
            if(ChangedFormData)
            {
                foreach (TranslationResxFile one in TranslationResxFiles)
                    one.Save();
                ChangedFormData = false;
                lblStatus.Text = NB.Translate("_Saved");
            }
        }

        private void TranslationWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.Modifiers == Keys.Control && e.KeyCode == Keys.S)
            {
                //ctrl-s was pressed
                Save();
            }
        }

        private void TranslationWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(ChangedFormData || ChangedPuzzleData)
            {
                DialogResult answer = MessageBox.Show("Save?", "Save?", MessageBoxButtons.YesNoCancel);
                if(answer == DialogResult.Cancel)
                {
                    e.Cancel = true;
                    return;
                }
                if (answer == DialogResult.Yes)
                    Save();
            }
            ClosingStuff();
        }

        private void cb1Language_SelectedIndexChanged(object sender, EventArgs e)
        {
            string What = CodeFromLang(cb1Language.Text);
            if (What != "")
            {
                tb1Message.Text = myNet.NetMessage.GetText(What);
                tb1Title.Text = myNet.NetTitle.GetText(What);
                tb1URL.Text = myNet.NetURL.GetText(What);
            }
        }

        private void cb2Language_SelectedIndexChanged(object sender, EventArgs e)
        {
            string What = CodeFromLang(cb2Language.Text);
            if (What != "")
            {
                tb2Message.Text = myNet.NetMessage.GetText(What);
                tb2Title.Text = myNet.NetTitle.GetText(What);
                tb2URL.Text = myNet.NetURL.GetText(What);
            }
        }

        void RefreshContents()
        {
            cb1Language_SelectedIndexChanged(null, EventArgs.Empty);
            cb2Language_SelectedIndexChanged(null, EventArgs.Empty);
            lblStatus.Text = "";
        }

        private void tb1Message_Leave(object sender, EventArgs e)
        {
            string What = CodeFromLang(cb1Language.Text);
            if (What != "")
            {
                if (tb1Message.Text != myNet.NetMessage.GetText(What))
                {
                    ChangedPuzzleData = true;
                    myNet.NetMessage.ChangeText(What, tb1Message.Text);
                }
            }
            RefreshContents();
        }

        private void tb2Message_Leave(object sender, EventArgs e)
        {
            string What = CodeFromLang(cb2Language.Text);
            if (What != "")
            {
                if (tb2Message.Text != myNet.NetMessage.GetText(What))
                {
                    ChangedPuzzleData = true;
                    myNet.NetMessage.ChangeText(What, tb2Message.Text);
                }
            }
            RefreshContents();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            Save();
        }

        private void tb1Title_Leave(object sender, EventArgs e)
        {
            string What = CodeFromLang(cb1Language.Text);
            if (What != "")
            {
                myNet.NetTitle.ChangeText(What, tb1Title.Text);
            }
            RefreshContents();
        }

        private void tb2Title_Leave(object sender, EventArgs e)
        {
            string What = CodeFromLang(cb2Language.Text);
            if (What != "")
            {
                myNet.NetTitle.ChangeText(What, tb2Title.Text);
            }
            RefreshContents();
        }

        private void tb1URL_Leave(object sender, EventArgs e)
        {
            string What = CodeFromLang(cb1Language.Text);
            if (What != "")
            {
                myNet.NetURL.ChangeText(What, tb1URL.Text);
            }
            RefreshContents();
        }

        private void tb2URL_Leave(object sender, EventArgs e)
        {
            string What = CodeFromLang(cb2Language.Text);
            if (What != "")
            {
                myNet.NetURL.ChangeText(What, tb2URL.Text);
            }
            RefreshContents();
        }



        #region Form Translation Stuff
        //**********************************************************************//
        //******************* Form Translation Things **************************//
        //**********************************************************************//
        bool TryToChooseFormDir(string Choice)
        {
            if (Choice == null || Choice == "") return false;
            //We want to have a file named edustrings.resx there

            //There may be other files: edustrings.fr.resx
            //If these exist, we are OK.  Otherwise, see if there is a "languages" dir and try that if it does exist
            string toCheck = Path.GetFileName(Choice).ToLower();
            if (File.Exists(Choice))
                if (toCheck == EnglishTargetFile)
                {
                    FormChosenDir = Path.GetDirectoryName(Choice);
                    LoadResxFiles();
                    panelTranslateFormItems.Enabled = true;
                    lblFormDir.Text = "Dir: " + FormChosenDir;
                    lblFormDir.AutoSize = true;
                    lblFormDir.MaximumSize = new Size(250, 200);
                    return true;
                }
                
            if(Directory.Exists(Choice))
            {
                //It is a directory.  See if it has the correct file in it.
                if (TryToChooseFormDir(Path.Combine(Choice, EnglishTargetFile)))
                {
                    return true; //It was successful
                }
                //If we get here, it did not have the file.  See if there is a "languages" directory
                if (TryToChooseFormDir(Path.Combine(Choice, "languages", EnglishTargetFile))) 
                {
                    return true; //It was successful
                }
            }
            return false;
        }

        void LoadResxFiles()
        {
            if (!Directory.Exists(FormChosenDir)) return;
            var resxFiles = Directory.EnumerateFiles(FormChosenDir, "*.resx", SearchOption.AllDirectories);
            TranslationResxFiles.Clear();

            foreach (string currentFile in resxFiles)
            {
                TranslationResxFile TRF = new TranslationResxFile(currentFile);
                TranslationResxFiles.Add(TRF);
            }
            //Add any resx files that do not exist, but should
            for( int i=0; i< LanguageChoices.GetLength(0); i++)
            {
                TranslationResxFile one = FileFromLangCode(LanguageChoices[i, 1]);
                if(one == null)
                {
                    //We need to make an empty resx file
                    one = new TranslationResxFile();
                    one.language = LanguageChoices[i, 1];
                    string filename = "edustrings."+ LanguageChoices[i, 1] + ".resx";
                    one.filename = filename;
                    TranslationResxFiles.Add(one);
                }
            }
            //Populate any missing entries.
            TranslationResxFile EN = FileFromLangCode("en");
            if(EN != null) //Being null had better not happen...  But just in case.
            {
                TranslationItem tempTI = null;
                foreach(TranslationResxFile TRF in TranslationResxFiles)
                {
                    if (TRF.language == EN.language) continue; //skip eng since that is the master
                    //Make sure each language has each item that the Eng version has
                    foreach(TranslationItem TI in EN.Items)
                    {
                        tempTI = ItemFromKey(TRF, TI.Key);
                        if(tempTI == null) //It does not exist in this language.  Add it
                        {
                            tempTI = new TranslationItem(TI);
                            tempTI.translated = false; //Make sure it is set to false.
                            TRF.Items.Add(tempTI);
                            ChangedFormData = true; //We have changed something. We want to be able to save it
                        }
                    }
                }
            }
            //Populate the fields from our new data
            PopulateFormTranslationItems();
        }

        void PopulateFormTranslationItems(object sender, EventArgs e)
        {
            PopulateFormTranslationItems();
        }

        private void PopulateFormTranslationItems()
        {
            cbFormItemChoice.Items.Clear();
            TranslationResxFile en = FileFromLangCode("en");
            List<string> Priorities = new List<string>() { };
            foreach(TranslationFormData TFD in FormData)
            {
                if (TFD.Importance > 5) Priorities.Add(TFD.Prefix);
            }
            if(en != null)
            {
                foreach(TranslationItem TI in en.Items)
                {
                    bool AddTranslated = false;
                    bool AddHigh = false;
                    if (cbFormFilter.Text != "Any")
                    {
                        if (!TI.Key.StartsWith(cbFormFilter.Text))
                            continue;//Skip it if it does not match the filter.
                    }
                    if (!TI.translated || cbFormShowTranslated.Checked)
                        AddTranslated = true;
                    if (cbFormHighPriority.Checked)
                    {
                        foreach(string one in Priorities)
                        {
                            if(TI.Key.StartsWith(one))
                            {
                                AddHigh = true;
                                break;
                            }
                        }
                    }
                    else
                        AddHigh = true;
                    if(AddTranslated && AddHigh)
                        cbFormItemChoice.Items.Add(TI.Key);
                }                
            }
            if(cbFormItemChoice.SelectedIndex <0)
            {
                if (cbFormItemChoice.Items.Count > 0)
                    cbFormItemChoice.SelectedIndex = 1;
            }
            else { cbFormItemChoice.Text = ""; }
        }

        private TranslationResxFile FileFromLangCode(string code)
        {
            foreach (TranslationResxFile one in TranslationResxFiles)
                if (one.language == code) return one;
            return null;
        }

        private TranslationItem ItemFromKey(TranslationResxFile File, string Key)
        {
            if (File == null) return null;
            foreach(TranslationItem TI in File.Items)
            {
                if (TI.Key == Key)
                    return TI;
            }
            return null;
        }

        private TranslationItem GetEditedTranslationItem()
        {
            string code = CodeFromLang(cbFormLang2Choice.Text);
            TranslationResxFile TRf = FileFromLangCode(code);
            TranslationItem TI = ItemFromKey(TRf, cbFormItemChoice.Text);
            return TI;
        }

        private void btnChooseDir_Click(object sender, EventArgs e)
        {
            string startingDir = FormChosenDir;
            if (FormChosenDir == "" && File.Exists(myNet.NetworkFilename))
                startingDir = Path.GetDirectoryName(myNet.NetworkFilename);
            //Prompt for a directory.

            OpenFileDialog ofd = NB.SelectDirectoryDialog("Directory with language files", startingDir);
            if(ofd.FileName != "")
            {
                //try to see if the chosen filename has appropriate files.  We need the English, at least
                if(!TryToChooseFormDir(Path.GetDirectoryName(ofd.FileName)))
                {
                    MessageBox.Show("Invalid Directory.");
                }
            }
        }

        private void cbFormItemChoice_SelectedIndexChanged(object sender, EventArgs e)
        {
            string code = CodeFromLang(cbFormLang1Choice.Text);
            TranslationResxFile TRf = FileFromLangCode(code);
            TranslationItem TI = ItemFromKey(TRf, cbFormItemChoice.Text);
            if(TRf != null && TI != null)
            {
                tbFormItem1.Text = TI.Value;
            }

             code = CodeFromLang(cbFormLang2Choice.Text);
             TRf = FileFromLangCode(code);
             TI = ItemFromKey(TRf, cbFormItemChoice.Text);
            if (TRf != null && TI != null)
            {
                tbFormItem2.Text = TI.Value;
                cbFormItemTranslated.Checked = TI.translated;
            }

        }

        private void cbFormItemTranslated_CheckedChanged(object sender, EventArgs e)
        {
            TranslationItem TI = GetEditedTranslationItem();
            if(TI != null)
            {
                TI.translated = cbFormItemTranslated.Checked;
                ChangedFormData = true;
            }
        }

        private void tbFormItem2_Leave(object sender, EventArgs e)
        {
            //If the text no longer matches, we want to update it.
            TranslationItem TI = GetEditedTranslationItem();
            if (TI != null)
            {
                //only make a note if it has changed
                if (TI.Value != tbFormItem2.Text)
                {
                    TI.Value = tbFormItem2.Text;
                    ChangedFormData = true;
                }
            }
        }

        private void cbFormFilter_SelectedIndexChanged(object sender, EventArgs e)
        {
            //We want to filter the form based on what we have here.
            PopulateFormTranslationItems();
            string tooltip = "";
            foreach(TranslationFormData one in FormData)
            {
                if(one.Prefix == cbFormFilter.Text)
                {
                    tooltip = one.Description;
                    break;
                }
            }
            myTooltip.SetToolTip(cbFormFilter,tooltip);
        }
    }
    #endregion

    #region TranslationClasses
    public class TranslationItem
    {
        public string Key = "";
        public string Value = "";
        public string Comment = "";
        public bool translated = false;
        public TranslationItem() { }
        public TranslationItem(TranslationItem Source)
        {
            Key = Source.Key;
            Value = Source.Value;
            Comment = Source.Comment;
            translated = Source.translated;
        }
    }

    public class TranslationResxFile
    {
        public string filename;
        public List<TranslationItem> Items = new List<TranslationItem>();
        public string language = "";
        string beginning = "translated: ";

        public TranslationResxFile() { }

        public TranslationResxFile(string File)
        {
            filename = File;
            Load();
            string fn = Path.GetFileName(File);
            if (fn == "edustrings.resx")
            {
                language = "en";
            }
            else
                language = fn.Substring(11, 2);
        }

        void Load()
        {
            if(! File.Exists(filename))
            {
                //The file does not exist yet.  Nothing to load.  Exit gracefully
                return;
            }
            Items.Clear();
            ResXResourceReader InResx = new ResXResourceReader(filename);
            InResx.UseResXDataNodes = true;
            System.Reflection.Assembly currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();

            foreach (DictionaryEntry d in InResx)
            {
                ResXDataNode rdn = (ResXDataNode)d.Value;
                TranslationItem TI = new TranslationItem();
                TI.Comment = rdn.Comment;
                if (TI.Comment.StartsWith(beginning))
                {
                    //trim off the beginning "translated" tag
                    TI.Comment = rdn.Comment.Substring(0, beginning.Length - 1);
                    TI.translated = true;
                }
                TI.Key = rdn.Name;
                TI.Value = (string)rdn.GetValue(new System.Reflection.AssemblyName[] { currentAssembly.GetName() });
                Items.Add(TI);
            }
            Items.Sort((a,b) => a.Key.CompareTo(b.Key));
            InResx.Close();
        }

        public void Save()
        {
            string tmpfile = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename) + "-tmp" + Path.GetExtension(filename));
            ResXResourceWriter WriteResx = new ResXResourceWriter(tmpfile);

            foreach (TranslationItem d in Items)
            {
                ResXDataNode rdn = new ResXDataNode(d.Key, d.Value);
                if (d.translated)
                    rdn.Comment = beginning + d.Comment;
                else
                    rdn.Comment = d.Comment;                
                WriteResx.AddResource(rdn);
                //Console.WriteLine("Adding " + toWrite.Name);
            }
            WriteResx.Generate();
            WriteResx.Close();
            //If we have an error, we should have exited and gone to "catch."
            //Proceed to put the new file
            if(File.Exists(filename))
                File.Delete(filename);
            File.Move(tmpfile, filename);
        }
    }

    public class TranslationFormData
    {
        public string Prefix;
        public string Description;
        public int Importance;  //10 is most important, 0 is least important

        public TranslationFormData(string prefix, string description, int importance)
        {
            Prefix = prefix;
            Description = description;
            Importance = importance;
        }
    }
    #endregion
}
