using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.XPath;



namespace NSFW.XmlToIdc
{
    class Program
    {
        private static HashSet<string> names = new HashSet<string>();

        static void Main(string[] args)
        {

            if (args.Length == 0)
            {
                Usage();
                return;
            }

            if (CategoryIs(args, "tables"))
            {
                if (args.Length != 2)
                {
                    UsageTables();
                }

                DefineTables(args[1]);
            }
            else if (CategoryIs(args, "stdparam"))
            {
                if (args.Length != 3)
                {
                    UsageStdParam();
                }

                DefineStandardParameters(args[1], args[2]);
            }
            else if (CategoryIs(args, "extparam"))
            {
                if (args.Length != 2)
                {
                    UsageExtParam();
                }

                DefineExtendedParameters(args[1]);
            }
        }

        #region DefineXxxx functions

        private static void DefineTables(string calId)
        {
            if (!File.Exists(calId + ".xml"))
            {
                Console.Write("Error: " + calId + ".xml must be in the current directory.");
                return;
            }
            calId = calId.ToUpper();

            WriteHeader("main", "Table definitions for " + calId);
            WriteTableNames(calId);
            WriteFooter();
        }

        private static void DefineStandardParameters(string calId, string ssmBaseString)
        {
            if (!File.Exists("logger.xml"))
            {
                Console.Write("Error: logger.xml must be in the current directory.");
                return;
            }

            if (!File.Exists("logger.dtd"))
            {
                Console.Write("Error: logger.dtd must be in the current directory.");
                return;
            }

            calId = calId.ToUpper();
            ssmBaseString = ssmBaseString.ToUpper();
            uint ssmBase = uint.Parse(ssmBaseString, System.Globalization.NumberStyles.HexNumber);

            WriteHeader("StdParams_" + calId, "Standard parameter definitions for " + calId + " with SSM read vector base " + ssmBaseString);
            WriteStandardParameters(calId, ssmBase);
            WriteFooter();
        }

        private static void DefineExtendedParameters(string ecuId)
        {
            if (!File.Exists("logger.xml"))
            {
                Console.Write("Error: logger.xml must be in the current directory.");
                return;
            }

            if (!File.Exists("logger.dtd"))
            {
                Console.Write("Error: logger.dtd must be in the current directory.");
                return;
            }

            ecuId = ecuId.ToUpper();

            WriteHeader("ExtParams_" + ecuId, "Extended parameter definitions for " + ecuId);
            WriteExtendedParameters(ecuId);
            WriteFooter();
        }

        #endregion

        public struct ECUscale
        {
            public string name;
            public uint elemSize;

            public ECUscale(string n = "", uint eS = 0)
            {
                name = n;
                elemSize = eS;
            }

            public void clr()
            {
                name = "";
                elemSize = 0;
            }
        }

        public struct ECUaxis
        {
            public string name;
            public UInt32 dataAdress;
            public string scaling;
            public uint elemSize;

            public ECUaxis(string n="", UInt32 dA = 0, string s = "", uint eS=0)
            {
                name = n;
                dataAdress = dA;
                scaling = s;
                elemSize = eS;
            }

            public void clr()
            {
                name = "";
                dataAdress = 0;
                scaling = "";
                elemSize = 0;
            }
        }

        public struct ECUtable
        {
            public string name;
            public UInt32 dataAdress;
            public uint type;
            public string scaling;
            public uint elemSize;
            public ECUaxis axis1;
            public ECUaxis axis2;

            public ECUtable(string n = "", UInt32 dA = 0, uint t = 0, string s = "", uint eS = 0, ECUaxis a1 = new ECUaxis(), ECUaxis a2 = new ECUaxis())
            {
                name = n;
                dataAdress = dA;
                type = t;
                scaling = s;
                elemSize = eS;
                axis1 = a1;
                axis2 = a2;
            }

            public void clr()
            {
                name = "";
                dataAdress = 0;
                type = 0;
                scaling = "";
                elemSize = 0;
                axis1.clr();
                axis2.clr();
            }
        }

        private static UInt32 convertToUInt32(string var)
        {
            UInt32 tmp = 0;
            
            try
            {
                tmp = UInt32.Parse(var, System.Globalization.NumberStyles.HexNumber);
            }

            catch (System.ArgumentNullException) { tmp = 0; }
            catch (System.FormatException)       { tmp = 0; }
            catch (System.OverflowException)     { tmp = 0; }

            return tmp;
        }

        private static bool ParseTables(List<ECUtable> ECUtables, string xmlId, List<ECUscale> ECUscales)
        {

            int i;
            string ecuid = null;
//            ECUtable curTbl;
//            ECUtable c2Tbl = new ECUtable();
            ECUtable tTbl = new ECUtable();
            ECUscale tScl = new ECUscale();

            Console.WriteLine("// parse " + xmlId);
            
            using (Stream stream = File.OpenRead(xmlId + ".xml"))
            {
                XPathDocument doc = new XPathDocument(stream);
                XPathNavigator nav = doc.CreateNavigator();
                string path = "/rom/romid[xmlid='" + xmlId + "']";
                XPathNodeIterator iter = nav.Select(path);
                iter.MoveNext();
                nav = iter.Current;
                nav.MoveToChild(XPathNodeType.Element);

                do
                {
                    if (nav.Name == "xmlid")
                    {
                        ecuid = nav.InnerXml;
                        break;
                    }
                } while (nav.MoveToNext());

                if (string.IsNullOrEmpty(ecuid))
                {
                    Console.WriteLine("Could not find definition for " + xmlId);
                    return false;
                }

                nav.MoveToParent();
                while (nav.MoveToNext())
                {
                    switch (nav.Name)
                    {
                        case "include":
                            ParseTables(ECUtables, nav.Value, ECUscales);
                            break;

// <scaling name="AFR" units="AFR" toexpr="14.7*128/x" frexpr="14.7*128/x" format="%.1f" min="8" max="20" inc="0.1" storagetype="uint8" endian="big"/>
// <table name="Immobilizer" category="Misc" address="3ffce" type="1D" scaling="Hex16"/>

                        case "scaling":
                            tScl.clr();
                            tScl.name = nav.GetAttribute("name", "");

                            switch (nav.GetAttribute("storagetype", "").ToUpper())
                            {
                                case "UINT8":
                                    tScl.elemSize = 1;
                                    break;
                                case "UINT16":
                                    tScl.elemSize = 2;
                                    break;
                            }

                            bool sFound = false;
                            for (i = 0; i < ECUscales.Count; i++)
                            {
                                if (ECUscales[i].name == tScl.name)
                                {
                                    sFound = true;
                                    ECUscale cScl = ECUscales[i];
                                    if (tScl.elemSize > 0) cScl.elemSize = tScl.elemSize;
                                    ECUscales[i] = cScl;
                                }
                            }
                            if (!sFound)
                            {
                                ECUscales.Add(tScl);
                            }
                            
                            break;


                        case "table":

                            tTbl.clr();
                            tTbl.name = nav.GetAttribute("name", "");
                            tTbl.dataAdress = convertToUInt32(nav.GetAttribute("address", ""));

                            switch (nav.GetAttribute("type", "").ToUpper())
                            {
                                case "1D":
                                    tTbl.type = 1;
                                    break;
                                case "2D":
                                    tTbl.type = 2;
                                    break;
                                case "3D":
                                    tTbl.type = 3;
                                    break;
                            }

                            tTbl.scaling = nav.GetAttribute("scaling", "");

                            switch (nav.GetAttribute("storagetype", "").ToUpper())
                            {
                                case "UINT8":
                                    tTbl.elemSize = 1;
                                    break;
                                case "UINT16":
                                    tTbl.elemSize = 2;
                                    break;
                                case "UINT32":
                                    tTbl.elemSize = 4;
                                    break;
                            }

                            if (nav.HasChildren)
                            {
                                nav.MoveToChild(XPathNodeType.Element);

                                tTbl.axis1.name = tTbl.name + "_" + nav.GetAttribute("name", "");
                                tTbl.axis1.dataAdress = convertToUInt32(nav.GetAttribute("address", ""));
                                tTbl.axis1.scaling = nav.GetAttribute("scaling", "");

                                switch (nav.GetAttribute("storagetype", "").ToUpper())
                                {
                                    case "UINT8":
                                        tTbl.axis1.elemSize = 1;
                                        break;
                                    case "UINT16":
                                        tTbl.axis1.elemSize = 2;
                                        break;
                                    case "UINT32":
                                        tTbl.axis1.elemSize = 4;
                                        break;
                                }

                                if (nav.MoveToNext())
                                {
                                    tTbl.axis2.name = tTbl.name + "_" + nav.GetAttribute("name", "");
                                    tTbl.axis2.dataAdress = convertToUInt32(nav.GetAttribute("address", ""));
                                    tTbl.axis2.scaling = nav.GetAttribute("scaling", "");

                                    switch (nav.GetAttribute("storagetype", "").ToUpper())
                                    {
                                        case "UINT8":
                                            tTbl.axis2.elemSize = 1;
                                            break;
                                        case "UINT16":
                                            tTbl.axis2.elemSize = 2;
                                            break;
                                        case "UINT32":
                                            tTbl.axis2.elemSize = 4;
                                            break;
                                    }
                                }
                                nav.MoveToParent();
                            }
                            

                            bool tFound = false;
                            for (i = 0; i < ECUtables.Count; i++)
                            { 
                                if (ECUtables[i].name == tTbl.name)
                                {
                                    ECUtable curTbl = ECUtables[i];

                                    if (tTbl.dataAdress != 0) curTbl.dataAdress = tTbl.dataAdress;
                                    if (tTbl.type > 0) curTbl.type = tTbl.type;
                                    if (tTbl.scaling != "") curTbl.scaling = tTbl.scaling;
                                    if (tTbl.elemSize > 0) curTbl.elemSize = tTbl.elemSize;

                                    bool aFound = false;
                                    if (tTbl.axis1.name != "")
                                    {
                                        if (curTbl.axis1.name != "")
                                        {
                                            if (curTbl.axis1.name == tTbl.axis1.name)
                                            {
                                                aFound = true;
                                                if (tTbl.axis1.dataAdress > 0) curTbl.axis1.dataAdress = tTbl.axis1.dataAdress;
                                                if (tTbl.axis1.scaling != "") curTbl.axis1.scaling = tTbl.axis1.scaling;
                                                if (tTbl.axis1.elemSize > 0) curTbl.axis1.elemSize = tTbl.axis1.elemSize;
                                            }
                                            if (!aFound && curTbl.axis2.name != "" && curTbl.axis2.name == tTbl.axis1.name)
                                            {
                                                aFound = true;
                                                if (tTbl.axis1.dataAdress > 0) curTbl.axis2.dataAdress = tTbl.axis1.dataAdress;
                                                if (tTbl.axis1.scaling != "") curTbl.axis2.scaling = tTbl.axis1.scaling;
                                                if (tTbl.axis1.elemSize > 0) curTbl.axis2.elemSize = tTbl.axis1.elemSize;
                                            }
                                        }

                                        if (!aFound)
                                        {
                                            if (curTbl.axis1.name == "") curTbl.axis1 = tTbl.axis1;
                                            if (curTbl.axis2.name == "") curTbl.axis2 = tTbl.axis1;
                                        }
                                    }

                                    aFound = false;
                                    if (tTbl.axis2.name != "")
                                    {
                                        if (curTbl.axis1.name != "")
                                        {
                                            if (curTbl.axis1.name == tTbl.axis2.name)
                                            {
                                                aFound = true;
                                                if (tTbl.axis2.dataAdress > 0) curTbl.axis1.dataAdress = tTbl.axis2.dataAdress;
                                                if (tTbl.axis2.scaling != "") curTbl.axis1.scaling = tTbl.axis2.scaling;
                                                if (tTbl.axis2.elemSize > 0) curTbl.axis1.elemSize = tTbl.axis2.elemSize;

                                            }
                                            if (!aFound && curTbl.axis2.name != "" && curTbl.axis2.name == tTbl.axis2.name)
                                            {
                                                aFound = true;
                                                if (tTbl.axis2.dataAdress > 0) curTbl.axis2.dataAdress = tTbl.axis2.dataAdress;
                                                if (tTbl.axis2.scaling != "") curTbl.axis2.scaling = tTbl.axis2.scaling;
                                                if (tTbl.axis2.elemSize > 0) curTbl.axis2.elemSize = tTbl.axis2.elemSize;
                                            }
                                        }

                                        if (!aFound)
                                        {
                                            if (curTbl.axis1.name == "") curTbl.axis1 = tTbl.axis2;
                                            if (curTbl.axis2.name == "") curTbl.axis2 = tTbl.axis2;
                                        }
                                    }

                                    ECUtables[i] = curTbl;

                                    tFound = true;
                                    break;
                                }
                            }

                            if (!tFound)
                            {
                                ECUtables.Add(tTbl);
                                //c2Tbl.clr();
                                //c2Tbl.name = tTbl.name;
                                //if (tTbl.dataAdress != 0) c2Tbl.dataAdress = tTbl.dataAdress;
                                //if (tTbl.type > 0) c2Tbl.type = tTbl.type;
                                //ECUtables.Add(c2Tbl);
                            }

                            break;
                    }
                }

            }
            
            return true;
        }

        private static string WriteTableNames(string xmlId)
        {
            List<ECUtable> ECUtables = new List<ECUtable>();
            List<ECUscale> ECUscales = new List<ECUscale>();

            if (ParseTables(ECUtables, xmlId, ECUscales))
            {
                for (int i = 0; i < ECUtables.Count; i++)
                {
                    ECUtable curTbl = ECUtables[i];

                    if (curTbl.dataAdress != 0)
                    {

                        if (curTbl.elemSize == 0)
                        {
                            if (curTbl.scaling == "") curTbl.elemSize = 1;
                            else
                            {
                                foreach (ECUscale tScl in ECUscales)
                                {
                                    if (tScl.name == curTbl.scaling)
                                    {
                                        curTbl.elemSize = tScl.elemSize;
                                        break;
                                    }
                                }
                                if (curTbl.elemSize == 0) curTbl.elemSize = 1;
                            }
                        }

                        Console.WriteLine();
//                        Console.WriteLine("// Table:" + curTbl.name + ", type: " + curTbl.type + "D, element size: " + curTbl.elemSize.ToString() + " byte"); // + ", Scaling:" + curTbl.scaling);
                        string sTmp;

                        switch (curTbl.type)
                        {
                            case 2:
                                sTmp = "Table2D";
                                break;
                            case 3:
                                sTmp = "Table3D";
                                break;
                            default:
                                sTmp = "";
                                break;
                        }
                        if(sTmp != "")
                        {
                            switch (curTbl.elemSize)
                            {
                                case 1:
                                    sTmp += "B";
                                    break;
                                case 2:
                                    sTmp += "W";
                                    break;
                            }
                        }

                        MakeName2("0x" + curTbl.dataAdress.ToString("x08"), ConvertName(curTbl.name), sTmp);
                        if (curTbl.axis1.dataAdress != 0)
                        {
                            if (curTbl.axis1.elemSize == 0)
                            {
                                if (curTbl.axis1.scaling == "") curTbl.axis1.elemSize = 1;
                                else
                                {
                                    foreach (ECUscale tScl in ECUscales)
                                    {
                                        if (tScl.name == curTbl.axis1.scaling)
                                        {
                                            curTbl.axis1.elemSize = tScl.elemSize;
                                            break;
                                        }
                                    }
                                    if (curTbl.axis1.elemSize == 0) curTbl.axis1.elemSize = 1;
                                }
                            }
//                            Console.WriteLine("// Axis:" + curTbl.axis1.name + ", Scaling:" + curTbl.axis1.scaling + ", eSize " + curTbl.axis1.elemSize.ToString());
                            switch (curTbl.axis1.elemSize)
                            {
                                case 1:
                                    sTmp = "AxisB";
                                    break;
                                case 2:
                                    sTmp = "AxisW";
                                    break;
                                default:
                                    sTmp = "";
                                    break;
                            }
                            MakeName2("0x" + curTbl.axis1.dataAdress.ToString("x08"), ConvertName(curTbl.axis1.name), sTmp);
                        }
                        if (curTbl.axis2.dataAdress != 0)
                        {
                            if (curTbl.axis2.elemSize == 0)
                            {
                                if (curTbl.axis2.scaling == "") curTbl.axis2.elemSize = 1;
                                else
                                {
                                    foreach (ECUscale tScl in ECUscales)
                                    {
                                        if (tScl.name == curTbl.axis2.scaling)
                                        {
                                            curTbl.axis2.elemSize = tScl.elemSize;
                                            break;
                                        }
                                    }
                                    if (curTbl.axis2.elemSize == 0) curTbl.axis2.elemSize = 1;
                                }
                            }
//                            Console.WriteLine("// Axis:" + curTbl.axis2.name + ", Scaling:" + curTbl.axis2.scaling + ", eSize " + curTbl.axis2.elemSize.ToString());
                            switch (curTbl.axis2.elemSize)
                            {
                                case 1:
                                    sTmp = "AxisB";
                                    break;
                                case 2:
                                    sTmp = "AxisW";
                                    break;
                                default:
                                    sTmp = "";
                                    break;
                            }
                            MakeName2("0x" + curTbl.axis2.dataAdress.ToString("x08"), ConvertName(curTbl.axis2.name), sTmp);
                        }
                    }

                }
            }



             
//            Console.WriteLine("auto referenceAddress;");

//            string ecuid = null;
//            using (Stream stream = File.OpenRead(xmlId + ".xml"))
//            {
//                XPathDocument doc = new XPathDocument(stream);
//                XPathNavigator nav = doc.CreateNavigator();
//                string path = "/rom/romid[xmlid='" + xmlId + "']";
//                XPathNodeIterator iter = nav.Select(path);
//                iter.MoveNext();
//                nav = iter.Current;
//                nav.MoveToChild(XPathNodeType.Element);

//                ecuid = xmlId;

///*

//                while (nav.MoveToNext())
//                {
//                    if (nav.Name == "ecuid")
//                    {
//                        ecuid = nav.InnerXml;
//                        break;
//                    }
//                }

//                if (string.IsNullOrEmpty(ecuid))
//                {
//                    Console.WriteLine("Could not find definition for " + xmlId);
//                    return null;
//                }
//*/

////                nav.MoveToRoot();

//                nav.MoveToParent();
//                while (nav.MoveToNext())
//                {
//                    if (nav.Name == "table")
//                    {
//                        Console.WriteLine();

//                        string name = nav.GetAttribute("name", "");
//                        string storageAddress = nav.GetAttribute("storageaddress", "");

//                        name = ConvertName(name);
//                        MakeName(storageAddress, name);

//                        List<string> axes = new List<string>();
//                        if (nav.HasChildren)
//                        {
//                            nav.MoveToChild(XPathNodeType.Element);

//                            do
//                            {
//                                string axis = nav.GetAttribute("type", "");
//                                axes.Add(axis);
//                                string axisAddress = nav.GetAttribute("storageaddress", "");

//                                axis = ConvertName(name + "_" + axis);
//                                MakeName(axisAddress, axis);
//                            } while (nav.MoveToNext());

//                            if (axes.Count == 2 &&
//                                axes[0] == "Y Axis" &&
//                                axes[1] == "X Axis")
//                            {
//                                Console.WriteLine("referenceAddress = DfirstB(" + storageAddress + ");");
//                                Console.WriteLine("if (referenceAddress > 0)");
//                                Console.WriteLine("{");
//                                Console.WriteLine("    referenceAddress = referenceAddress - 12;");
//                                string tableName = ConvertName("Table" + name);
//                                string command = string.Format("    MakeNameEx(referenceAddress, \"{0}\", SN_CHECK);", tableName);
//                                Console.WriteLine(command);
//                                Console.WriteLine("}");
//                                Console.WriteLine("else");
//                                Console.WriteLine("{");
//                                Console.WriteLine("    Message(\"No reference to " + name + "\\n\");");
//                                Console.WriteLine("}");
//                            }
//                            else if (axes.Count == 1 &&
//                                axes[0] == "Y Axis")
//                            {
//                                Console.WriteLine("referenceAddress = DfirstB(" + storageAddress + ");");
//                                Console.WriteLine("if (referenceAddress > 0)");
//                                Console.WriteLine("{");
//                                Console.WriteLine("    referenceAddress = referenceAddress - 8;");
//                                string tableName = ConvertName("Table" + name);
//                                string command = string.Format("    MakeNameEx(referenceAddress, \"{0}\", SN_CHECK);", tableName);
//                                Console.WriteLine(command);
//                                Console.WriteLine("}");
//                                Console.WriteLine("else");
//                                Console.WriteLine("{");
//                                Console.WriteLine("    Message(\"No reference to " + name + "\\n\");");
//                                Console.WriteLine("}");
//                            }

//                            nav.MoveToParent();
//                        }
//                    }
//                }
//            }

            return xmlId;
        }

        private static void WriteStandardParameters(string ecuid, uint ssmBase)
        {
            // Can this really go inside the function definition?
            Console.WriteLine("auto addr;");
            Console.WriteLine("");

            using (Stream stream = File.OpenRead("logger.xml"))
            {
                XPathDocument doc = new XPathDocument(stream);
                XPathNavigator nav = doc.CreateNavigator();
                string path = "/logger/protocols/protocol[@id='SSM']/parameters/parameter";
                XPathNodeIterator iter = nav.Select(path);
                while (iter.MoveNext())
                {
                    XPathNavigator navigator = iter.Current;
                    string name = navigator.GetAttribute("name", "");
                    string pointerName = ConvertName("PtrSsmGet" + name);
                    string functionName = ConvertName("SsmGet" + name);

                    if (!navigator.MoveToChild("address", ""))
                    {
                        break;
                    }

                    string addressString = iter.Current.InnerXml;
                    addressString = addressString.Substring(2);

                    uint address = uint.Parse(addressString, System.Globalization.NumberStyles.HexNumber);
                    address = address * 4;
                    address = address + ssmBase;
                    addressString = "0x" + address.ToString("X8");

                    MakeName(addressString, pointerName);

                    string getAddress = string.Format("addr = Dword({0});", addressString);
                    Console.WriteLine(getAddress);
                    MakeName("addr", functionName);
                    Console.WriteLine();
                }
            }
        }

        private static void WriteExtendedParameters(string ecuid)
        {
            using (Stream stream = File.OpenRead("logger.xml"))
            {
                XPathDocument doc = new XPathDocument(stream);
                XPathNavigator nav = doc.CreateNavigator();
                string path = "/logger/protocols/protocol[@id='SSM']/ecuparams/ecuparam/ecu[@id='" + ecuid + "']/address";
                XPathNodeIterator iter = nav.Select(path);
                while (iter.MoveNext())
                {
                    string addressString = iter.Current.InnerXml;
                    addressString = addressString.Substring(2);
                    uint address = uint.Parse(addressString, System.Globalization.NumberStyles.HexNumber);
                    address |= 0xFF000000;
                    addressString = "0x" + address.ToString("X8");

                    XPathNavigator n = iter.Current;
                    n.MoveToParent();
                    n.MoveToParent();
                    string name = n.GetAttribute("name", "");
                    name = ConvertName(name);

                    MakeName(addressString, name);
                }
            }
        }

        #region Utility functions

        private static void WriteHeader(string functionName, string description)
        {
            Console.WriteLine("///////////////////////////////////////////////////////////////////////////////");
            Console.WriteLine("// " + description);
            Console.WriteLine("///////////////////////////////////////////////////////////////////////////////");
            Console.WriteLine("#include <idc.idc>");
            Console.WriteLine("#include \"xml2idc.idc\"");
            Console.WriteLine();
            Console.WriteLine("static " + functionName + "()");
            Console.WriteLine("{");
        }

        private static void WriteFooter()
        {
            Console.WriteLine("}");
        }

        private static void MakeName(string address, string name)
        {
            string command = string.Format("MakeNameEx({0}, \"{1}\", SN_CHECK);",
                address,
                name);
            Console.WriteLine(command);
        }

        private static void MakeName2(string address, string name, string type = "")
        {
            string command = string.Format("myName{0}({1}, \"{2}\");",
                type, 
                address,
                name);
            Console.WriteLine(command);
        }

        private static string ConvertName(string original)
        {
            StringBuilder builder = new StringBuilder(original.Length);
            foreach (char c in original)
            {
                if (char.IsLetterOrDigit(c))
                {
                    builder.Append(c);
                    continue;
                }

                if (c == '_')
                {
                    builder.Append(c);
                    continue;
                }

                if (c == '*')
                {
                    builder.Append("Ext");
                    continue;
                }
            }

            // Make sure it's unique
            string name = builder.ToString();
            while (names.Contains(name))
            {
                name = name + "_";
            }
            names.Add(name);

            return name;
        }

        private static bool CategoryIs(string[] args, string category)
        {
            return string.Compare(args[0], category, StringComparison.OrdinalIgnoreCase) == 0;
        }

        #endregion

        #region Usage instructions

        private static void Usage()
        {
            Console.WriteLine("XmlToIdc Usage:");
            Console.WriteLine("XmlToIdc.exe <category> ...");
            Console.WriteLine();
            Console.WriteLine("Where <category> is one of the following:");
            Console.WriteLine("    tables <cal-id>");
            Console.WriteLine("    stdparam <cal-id> <ssm-base>");
            Console.WriteLine("    extparam <ecu-id>");
            Console.WriteLine();
            Console.WriteLine("ecu-id: ECU identifier, e.g. 2F12785606");
            Console.WriteLine("cal-id: Calibration id, e.g. A2WC522N");
            Console.WriteLine("ssm-base: Base address of the SSM 'read' vector, e.g. 4EDDC");
            Console.WriteLine();
            Console.WriteLine("And you'll want to redirect stdout to a file, like:");
            Console.WriteLine("XmlToIdc.exe ... > Whatever.idc");
        }

        private static void UsageTables()
        {
            Console.WriteLine("XmlToIdc Usage:");
            Console.WriteLine("XmlToIdc.exe tables <cal-id>");
            Console.WriteLine();
            Console.WriteLine("cal-id: Calibration id, e.g. A2WC522N");
            Console.WriteLine();
            Console.WriteLine("And you'll want to redirect stdout to a file, like:");
            Console.WriteLine("XmlToIdc.exe tables A2WC522N > Tables.idc");
        }

        private static void UsageStdParam()
        {
            Console.WriteLine("StdParam Usage:");
            Console.WriteLine("XmlToIdc.exe stdparam <cal-id> <ssm-base>");
            Console.WriteLine();
            Console.WriteLine("cal-id: Calibration id, e.g. A2WC522N");
            Console.WriteLine("ssm-base: Base address of the SSM 'read' vector, e.g. 4EDDC");
            Console.WriteLine();
            Console.WriteLine("And you'll want to redirect stdout to a file, like:");
            Console.WriteLine("XmlToIdc.exe stdparam A2WC522N 4EDDC > StdParam.idc");
        }

        private static void UsageExtParam()
        {
            Console.WriteLine("ExtParam Usage:");
            Console.WriteLine("XmlToIdc.exe extparam <ecu-id>");
            Console.WriteLine();
            Console.WriteLine("ecu-id: ECU identifier, e.g. 2F12785606");
            Console.WriteLine();
            Console.WriteLine("And you'll want to redirect stdout to a file, like:");
            Console.WriteLine("XmlToIdc.exe extparam 2F12785606 > ExtParam.idc");
        }

        #endregion
    }
}
