using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.IO;
using System.Windows.Forms;
using static System.Console;
using static System.Threading.Thread;

namespace cce {
    class Transcoder {
        static internal string result = "";
        static private Dictionary<string, string> extended_dict = null;
        static private Dictionary<string, string> common_dict = null;
        static private Dictionary<char, char> substitution = new Dictionary<char, char>{
            {'a','a' },
            {'b','t' },
            {'c','y' },
            {'d','p' },
            {'e','e' },
            {'f','t' },
            {'g','j' },
            {'h','k' },
            {'i','i' },
            {'j','t' },
            {'k','k' },
            {'l','p' },
            {'m','s' },
            {'n','t' },
            {'o','o' },
            {'p','k' },
            {'q','r' },
            {'r','t' },
            {'s','y' },
            {'t','p' },
            {'u','u' },
            {'v','t' },
            {'w','j' },
            {'x','k' },
            {'y','y' },
            {'z','b' }
        };
        static private Dictionary<char, string> decode_key = new Dictionary<char, string>{
            {'a',"a" },
            {'t',"bfjnrv"},
            {'y',"csy" },
            {'p',"dlt" },
            {'e',"e" },
            {'j',"gw" },
            {'k',"hkpx" },
            {'i',"i" },
            {'s',"m" },
            {'o',"o" },
            {'r',"q" },
            {'u',"u" },
            {'b',"z" }

        };
        static internal void Teacher() {
            var pos = CursorTop;
            Write("Please enter the encrypted word: ");
            var cyphered = Console.ReadLine().ToLower();
            if (cyphered == "") return;
            CursorTop = pos;
            string translation = "";
            while (true) {
                Write($"Please enter a translation for \"{cyphered}\": ");
                translation = ReadLine().ToLower();
                if (raw_encode(cyphered).ToLower() == cyphered) {
                    Console.BackgroundColor = ConsoleColor.Green; Console.ForegroundColor = ConsoleColor.Black;
                    WriteLine("Cypher Match!"); ResetColor(); break;
                }
                Console.BackgroundColor = ConsoleColor.Red;
                WriteLine("Words don't match");
                ResetColor();
            }
            var entered = false;
            char cki;
            do {
                Utils.LagWrite(@"Where do you want to save the translation?
[1] Common words dictionary
[2] Extended words dictionary
>>> ".Replace("\r\n", "\n"));
                cki = ReadKey().KeyChar;
                WriteLine();
                if (extended_dict == null || common_dict == null) init();
                switch (cki) {
                    case '1':
                        if (common_dict.ContainsKey(translation)) {
                            WriteLine("Error: Unable to add a new translation. Translation already present.");
                        } else common_dict.Add(translation, cyphered);
                        entered = true;
                        break;
                    case '2':
                        if (extended_dict.ContainsKey(translation)) {
                            WriteLine("Error: Unable to add a new translation. Translation already present.");
                        } else extended_dict.Add(translation, cyphered);
                        entered = true;
                        break;
                    default:
                        CursorLeft--; WriteLine("Not a valid option");
                        break;
                }
            } while (!entered);
            Console.BackgroundColor = cki == '1' ? ConsoleColor.Green : ConsoleColor.Blue; Console.ForegroundColor = ConsoleColor.Black;
            WriteLine("Translation Added"); ResetColor();
            update();
        }
        static internal void Encode(string entry) {
            result = raw_encode(entry);
            WriteLine("Transcoding:\n{0}\n", entry);
            Utils.LagWrite(result);
        }
        static internal void Decode(string entry) {
            var sentence = entry.ToLower();
            //120x30, buffer 240x60
            if (sentence.Length >= 120) { BufferWidth = sentence.Length * 2; WindowWidth = sentence.Length + 20; }
            Clear();
            CursorVisible = false;
            var checker = init();
            if (!checker) {
                WriteLine("Unable to load dictionaries");
                return;
            }
            var cleaned = new char[sentence.Length];
            var symbols = new char[sentence.Length];
            var writeout = new char[sentence.Length];
            for (int i = 0; i < sentence.Length; i++) {
                if (sentence[i] >= 'a' && sentence[i] <= 'z') { cleaned[i] = sentence[i]; symbols[i] = 'x'; writeout[i] = '_'; } else { writeout[i] = symbols[i] = sentence[i]; cleaned[i] = ' '; }
            }
            var decode = string.Join("", cleaned).ToLower().Split(' ');
            //var decoded = new List<List<string>>();
            Console.BackgroundColor = ConsoleColor.Green;
            Console.Write("  "); ResetColor(); Console.WriteLine(" Frequent Words");
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write("  "); ResetColor(); Console.WriteLine(" Infrequent Words");
            Console.BackgroundColor = ConsoleColor.Red;
            Console.Write("  "); ResetColor(); Console.WriteLine(" Letter decypher");
            WriteLine("Transcoding:\n{0}\n", entry);
            int memTop = CursorTop;
            int left = 0;
            Write(string.Join("", writeout));
            for (int i = 0; i < decode.Length; i++) {
                if (symbols[left] != 'x') left++;
                //var options = new List<string>();
                CursorTop = memTop;
                Console.BackgroundColor = ConsoleColor.Green;
                Console.ForegroundColor = ConsoleColor.Black;
                wordwrite(common_dict, decode[i], entry, left, i);
                /*foreach (var item in common_dict) {
                    if (item.Value == decode[i]) {
                        CursorLeft = left;
                        //options.Add(item.Key);
                        for (int j = 0; j < item.Key.Length; j++) {
                            Write(Char.IsUpper(entry[i]) ? char.Parse(item.Key[j].ToString().ToUpper()) : char.Parse(item.Key[j].ToString().ToLower()));
                        }
                        Write(item.Key.ToUpper());
                        Sleep(100);
                        CursorTop++;
                    }
                }*/
                Console.BackgroundColor = ConsoleColor.Blue;
                Console.ForegroundColor = ConsoleColor.Black;
                wordwrite(extended_dict, decode[i], entry, left, i);
                ResetColor();
                List<List<char>> letter_decode = new List<List<char>>();
                for (int j = 0; j < decode[i].Length; j++) {
                    if (decode_key.TryGetValue(decode[i][j], out string substituted)) {
                        var letterlist = new List<char>();
                        for (int h = 0; h < substituted.Length; h++) {
                            letterlist.Add(substituted[h]);
                        }
                        letter_decode.Add(letterlist);
                    } else {
                        letter_decode.Add(new List<char> { sentence[j] });
                    }
                }
                int top = CursorTop;
                int letterleft = left;
                Console.BackgroundColor = ConsoleColor.Red;
                Console.ForegroundColor = ConsoleColor.Black;
                for (int j = 0; j < letter_decode.Count; j++) {
                    for (int h = 0; h < letter_decode[j].Count; h++) {
                        CursorLeft = letterleft;
                        Write(Char.IsUpper(entry[CursorLeft]) ? Char.ToUpper(letter_decode[j][h]) : Char.ToLower(letter_decode[j][h]));
                        Sleep(10);
                        CursorTop++;
                    }
                    CursorTop = top;
                    letterleft++;
                }
                Sleep(80);
                left += decode[i].Length;
            }
            ResetColor();
            //return string.Join(" ", decoded);
        }
        static internal void head_transcribe() {
            if(!File.Exists("dev")) {
                Clear();
                BackgroundColor = ConsoleColor.Red;
                Utils.LagWrite("                                       \n" +
                          "  Unable to comply. Not a dev version  \n"+
                          "                                       ", true);
                ResetColor();
                return;
            }
            raw_transcribe("common_dict.txt", "common_dict.json");
            raw_transcribe("extended_dict.txt", "extended_dict.json");
            uniquire();
        }
        static private void update() {
            uniquire();
            File.WriteAllText(AppSettings.Extended, JsonConvert.SerializeObject(extended_dict));
            File.WriteAllText(AppSettings.Common, JsonConvert.SerializeObject(common_dict));
        }
        static private string raw_encode(string entry) {
            var sentence = entry.ToLower();
            char[] encoded = new char[entry.Length];
            for (int i = 0; i < sentence.Length; i++) {
                if (substitution.TryGetValue(sentence[i], out char substituted)) {
                    encoded[i] = Char.IsUpper(entry[i]) ? Char.ToUpper(substituted) : Char.ToLower(substituted);
                } else {
                    encoded[i] = entry[i];
                }
            }
            return String.Join("", encoded);
        }
        static internal bool init() {
            if (common_dict != null && extended_dict != null) return true;
            var checker = true;
            WriteLine("[Loading Dictionary]");
            if (File.Exists(AppSettings.Extended)) extended_dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(AppSettings.Extended));
            else { WriteLine("File missing"); checker = false; }
            if (File.Exists(AppSettings.Common)) common_dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(AppSettings.Common));
            else { WriteLine("File missing"); checker = false; }
            return checker;
        }
        static private void uniquire() {
            init();
            foreach (var item in common_dict) {
                if (extended_dict.ContainsKey(item.Key)) extended_dict.Remove(item.Key);
            }
        }
        static private void raw_transcribe(string input, string output) {
            var lines = File.ReadAllLines(input);
            for (int i = 0; i < lines.Length; i++) {
                lines[i] = lines[i].ToLower();
            }
            var English = new string[lines.Length];
            lines.CopyTo(English, 0);
            for (int i = 0; i < English.Length; i++) {
                var word = new char[English[i].Length];
                for (int j = 0; j < English[i].Length; j++) {
                    if (substitution.TryGetValue(English[i][j], out char substituted)) {
                        word[j] = substituted;
                    }
                    else {
                        word[j] = English[i][j];
                    }
                }
                lines[i] = String.Join("", word);
                WriteLine($"{English[i]}:{lines[i]}");
            }
            Dictionary<string, string> vals = new Dictionary<string, string>();
            for (int i = 0; i < English.Length; i++) {
                if (vals.ContainsKey(English[i])) continue;
                vals.Add(English[i], lines[i]);
            }
            File.WriteAllText(output, JsonConvert.SerializeObject(vals));
        }
        static internal void concat() {
            init();
            var dict = new Dictionary<string, Dictionary<string, string>>();
            dict.Add("short", common_dict);
            dict.Add("long", extended_dict);
            File.WriteAllText("dictionary.json", JsonConvert.SerializeObject(dict));

        }
        static private void wordwrite(Dictionary<string, string> collection, string decode, string entry,int left, int i) {
            foreach (var item in collection) {
                if (item.Value == decode) {
                    CursorLeft = left;
                    //options.Add(item.Key);
                    for (int j = 0; j < item.Key.Length; j++) {
                        Write(Char.IsUpper(entry[CursorLeft]) ? Char.ToUpper(item.Key[j]) : Char.ToLower(item.Key[j]));
                    }
                    Utils.VarSleep(10, low: 20,high:100);
                    CursorTop++;
                }
            }
        }
    }
}
