using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace Cartographer.Scripts
{
    public class ScriptDatabase
    {
        Scripts parent;
        public static ValueTypeDatabase valueTypes;
        public static DiscoveredCommands discovered;
        public static CommandDatabase cmdDatabase;

        public ScriptDatabase(Scripts that)
        {
            parent = that;
            that.database = this;
        }

        static ScriptDatabase()
        {
            valueTypes = new ValueTypeDatabase();
            discovered = new DiscoveredCommands();
            cmdDatabase = new CommandDatabase();
        }

        public static void Add(int number, string str, byte[] value)
        {
            valueTypes.Add(number, str, value);
        }

        public static void Add(int identity, string cmd, int returnType, List<ValueType> children)
        {
            discovered.Add(identity, cmd, returnType, children);
        }

        public static void Flush()
        {
            valueTypes.Sort();
            discovered.Sort();

            FileStream fs = new FileStream(Application.StartupPath + "\\valueTypes.txt", FileMode.Create, FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs);
            for(int i = 0; i < valueTypes.db.Count; i++)
            {
                string output = valueTypes.db[i].num + "\t" + valueTypes.db[i].str + "\t\t0x";
                Array.Reverse(valueTypes.db[i].value);
                for(int x = 0; x < 4; x++)
                {
                    output += string.Format("{0:x2}", valueTypes.db[i].value[x]);
                }
                Array.Reverse(valueTypes.db[i].value);
                sw.WriteLine(output);
            }
            sw.Flush();
            sw.Close();
            fs.Close();
            fs = new FileStream(Application.StartupPath + "\\commands.txt", FileMode.Create, FileAccess.Write);
            sw = new StreamWriter(fs);
            for (int i = 0; i < discovered.db.Count; i++)
            {
                Command cmd = discovered.db[i];
                string output = cmd.identity + "\t" + cmd.str;
                int count = cmd.discoveredParams.Count > cmd.returnTypes.Count ? cmd.discoveredParams.Count : cmd.returnTypes.Count;
                for (int j = 0; j < count; j++)
                {
                    output += "\n\t";
                    if (j < cmd.returnTypes.Count)
                    {
                        output += cmd.returnTypes[j].name;
                    }
                    output += "\t";
                    if (j < cmd.discoveredParams.Count)
                    {
                        for (int x = 0; x < cmd.discoveredParams[j].Count; x++)
                        {
                            ValueType vt = cmd.discoveredParams[j][x];
                            output += "<" + vt.name + "> ";
                        }
                    }
                }
                output += "\n";
                sw.WriteLine(output);
            }
            sw.Flush();
            sw.Close();
            fs.Close();
        }
    }

    //For researching Value Types
    public class ValueTypeDatabase
    {
        public List<ValueType> db;

        public ValueTypeDatabase() { db = new List<ValueType>(); }

        public void Add(int number, string str, byte[] value)
        {
            db.Add(new ValueType(number, str, value));
        }

        public void Sort()
        {
            db.Sort(new Sorter());
        }
        class Sorter : IComparer<ValueType>
        {
            int IComparer<ValueType>.Compare(ValueType x, ValueType y)
            {
                if (x.num == y.num)
                {
                    if (x.str == y.str)
                    {
                        for (int i = 0; i < 4; i++)
                        {
                            if (x.value[i] != y.value[i])
                                return x.value[i].CompareTo(y.value[i]);
                        }
                    }
                    return x.str.CompareTo(y.str);
                }
                return x.num.CompareTo(y.num);
            }
        }

        public class ValueType
        {
            public int num;
            public string str;
            public byte[] value;

            public ValueType(int number, string str, byte[] value)
            {
                this.num = number;
                this.str = str;
                this.value = value;
            }
        }
    }

    //For keeping a record of commands read from the maps
    public class DiscoveredCommands
    {
        public List<Command> db;

        public DiscoveredCommands() { db = new List<Command>(); }

        public void Add(int identity, string str, int returnType, List<ValueType> children)
        {
            int found = Search(identity, returnType, children);
            if (found == 0)
            {
                Command cmd = new Command();
                cmd.identity = identity;
                cmd.str = str;
                cmd.returnTypes = new List<ValueType>();
                cmd.returnTypes.Add(new ValueType(returnType));
                cmd.discoveredParams = new List<List<ValueType>>();
                cmd.discoveredParams.Add(children);
                db.Add(cmd);
            }
            else if (found < 3)
            {
                Command cmd = GetByIdentity(identity);
                if (found == 1)
                {
                    cmd.returnTypes.Add(new ValueType(returnType));
                }
                cmd.discoveredParams.Add(children);
            }
        }

        public int Search(int identity, int returnType, List<ValueType> children)
        {
            for (int i = 0; i < db.Count; i++)
            {
                Command cmd = db[i];
                if (cmd.identity == identity)
                {
                    if (cmd.returnTypes.Count > 0)
                    {
                        bool found = false;
                        for (int x = 0; x < cmd.returnTypes.Count; x++)
                        {
                            if (cmd.returnTypes[x].number == returnType)
                            {
                                found = true;
                                break;
                            }
                        }
                        if (found)
                        {
                            if (cmd.discoveredParams == null || cmd.discoveredParams.Count == 0)
                                return 2;
                            for (int j = 0; j < cmd.discoveredParams.Count; j++)
                            {
                                List<ValueType> parameters = cmd.discoveredParams[j];
                                if (parameters == null && children == null)
                                    return 3;
                                else if (parameters.Count == children.Count)
                                {
                                    found = false;
                                    for (int x = 0; x < parameters.Count; x++)
                                    {
                                        if (parameters[x].number != children[x].number)
                                        {
                                            found = true;
                                            break;
                                        }
                                    }
                                    if (!found)
                                        return 3;
                                }
                            }
                            return 2;
                        }
                    }
                    return 1;
                }
            }
            return 0;
        }

        public Command GetByIdentity(int identity)
        {
            for (int i = 0; i < db.Count; i++)
            {
                if (db[i].identity == identity)
                    return db[i];
            }
            return null;
        }

        class Sorter : IComparer<Command>
        {
            int IComparer<Command>.Compare(Command x, Command y)
            {
                return x.identity.CompareTo(y.identity);
            }
        }
        public void Sort()
        {
            db.Sort(new Sorter());
        }
}

    //For reading from a file
    public class CommandDatabase
    {
    }

    //Base class
    public class Command
    {
        public int identity;
        public string str;
        public List<ValueType> returnTypes;
        public List<ValueType> parameters;
        public List<List<ValueType>> discoveredParams;
    }
}
