using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TELTest {
    internal static class QuizListing {
        static QuizListing() {
            tmr.Interval = 15000;
            tmr.Elapsed += Tmr_Elapsed;
            tmr.AutoReset = false;
            LoadAll();
        }

        private static void Tmr_Elapsed(Object sender, System.Timers.ElapsedEventArgs e) => DumpAll();

        private static System.Timers.Timer tmr = new System.Timers.Timer();
        private static void Retime() {
            tmr.Stop();
            tmr.Start();
        }
        public static bool UpdateEntry(string id, string name, Visibility visibility) {
            lock (Entries) {
                QuizEntry? qw = null;
                for (int i = 0; i < Entries.Count; i++) {
                    if (Entries[i].ID == id) {
                        var tmp = Entries[i];
                        qw = tmp;
                        tmp.Name = name;
                        tmp.Visibility = visibility;
                        Entries[i] = tmp;
                        Retime();
                        break;
                    }
                }
                if (qw != null) {
                    if (qw.Value.Visibility == Visibility.Public) {
                        for (Int32 i = 0; i < CachePublic.Count; i++) {
                            QuizEntry item = CachePublic[i];
                            if (item.ID == id) {
                                var tmp = CachePublic[i];
                                tmp.Name = name;
                                tmp.Visibility = visibility;
                                CachePublic[i] = tmp;
                                break;
                            }
                        }
                    }
                }
                return false;
            }
        }
        public static bool UpdateVisibility(string id, Visibility visibility) {
            lock (Entries) {
                for (int i = 0; i < Entries.Count; i++) {
                    if (Entries[i].ID == id) {
                        var tmp = Entries[i];
                        tmp.Visibility = visibility;
                        Entries[i] = tmp;
                        Retime();
                        return true;
                    }
                }
                return false;
            }
        }
        public static bool Contains(string id) {
            lock (Entries) {
                for (int i = 0; i < Entries.Count; i++) {
                    if (Entries[i].ID == id) {
                        return true;
                    }
                }
                return false;
            }
        }
        public static bool Remove(string id) {
            lock (Entries) {
                for (int i = 0; i < Entries.Count; i++) {
                    if (Entries[i].ID == id) {
                        Entries.RemoveAt(i);
                        return true;
                    }
                }
                return false;
            }
        }
        public static void Insert(string id, QuizContainer container) {
            Insert(id, container.Title, container.Visibility);
        }
        public static void Insert(string id, string name, Visibility visibility) {
            lock (Entries) {
                var entry = new QuizEntry() {
                    ID = id,
                    Name = name,
                    Visibility = visibility
                };
                Entries.Add(entry);
                if (visibility == Visibility.Public) {
                    CachePublic.Add(entry);
                }
                Retime();
            }
        }
        public static void DumpAll() {
            Program.WriteWithTime("Begin write all listings....");
            int tuplesOut = 0;
            lock (Entries) {
                using (FileStream fs = File.OpenWrite("Listing.bin")) {
                    fs.Seek(0, SeekOrigin.Begin);
                    BinaryWriter bw = new BinaryWriter(fs, System.Text.Encoding.UTF8, true);
                    foreach (var item in Entries) {
                        byte[] ib = System.Text.Encoding.ASCII.GetBytes(item.ID);
                        bw.Write(ib.Length);
                        bw.Write(ib);

                        byte[] nb = System.Text.Encoding.UTF8.GetBytes(item.Name);
                        bw.Write(nb.Length);
                        bw.Write(nb);

                        bw.Write((int)item.Visibility);
                        tuplesOut++;
                    }
                    bw.Write(0);
                    fs.Flush();
                    bw.Dispose();
                }
            }
            Program.WriteWithTime("Done, {0} records out.", tuplesOut);
        }
        public static void LoadAll() {
            if (!File.Exists("Listing.bin")) return;
            using (FileStream fs = File.OpenRead("Listing.bin")) {
                BinaryReader bw = new BinaryReader(fs, System.Text.Encoding.UTF8, true);
                while(true) {
                    QuizEntry qe = new QuizEntry();
                    int len = bw.ReadInt32();
                    if (len == 0) break;
                    byte[] ib = bw.ReadBytes(len);
                    qe.ID = System.Text.Encoding.ASCII.GetString(ib);

                    len = bw.ReadInt32();
                    ib = bw.ReadBytes(len);
                    qe.Name = System.Text.Encoding.UTF8.GetString(ib);

                    qe.Visibility = (Visibility)bw.ReadInt32();
                    Entries.Add(qe);
                    if (qe.Visibility == Visibility.Public) CachePublic.Add(qe);
                }
                bw.Dispose();
            }
        }

        public static List<QuizEntry> CachePublic = new List<QuizEntry>();
        public static List<QuizEntry> Entries = new List<QuizEntry>();
    }
    public struct QuizEntry {
        public string Name;
        public Visibility Visibility;
        public string ID;

    }
}
