// ----------------------------------------------------------------------------
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ----------------------------------------------------------------------------

using System;
using System.IO;
using System.Text.RegularExpressions;

class App
{
    private static Regex clsDecl = new Regex("= CLASS MEMBERS DECLARATION =");
    private static Regex contract  = new Regex(@"\.class .* ([A-Za-z]\S*Contract)");
    private static Regex tagsBegin = new Regex(@"\.class .* Tags");
    private static Regex tagsEnd   = new Regex(@" \} \/\/ end of class Tags");
    private static Regex fieldTag  = new Regex(@"\.field .* ([A-z0-9_]*) = int32\(([^)]*)\)");
    private static string endOfContract = "{\n    ChannelId, ItemLong\n}\n";
    private static string HexDigits = "00112233445566778899aAbBcCdDeEfF";

    private static int HexToInt32(string s)
    {
        int value = 0;
        if (s.Length < 3 || s[0] != '0' || s[1] != 'x') {
            throw new ArgumentException();
        }

        for (int i = 2; i < s.Length; i++) {
            value = value * 16;
            int delta = HexDigits.IndexOf(s[i]);
            if (delta < 0) {
                throw new ArgumentException("Bad digit");
            }
            value += delta / 2;
        }
        return value;
    }

    public void Generate(TextReader input, string inputName, TextWriter output)
    {
        bool   inMembers       = false;
        bool   inContract      = false;
        bool   inTags          = false;
        string currentContract = "<none>";

        output.WriteLine(
            "// autogenerated by mkcontagmap.exe from {0}; do not edit!\n",
            inputName
            );

        string line;
        while (null != (line = input.ReadLine())) {
            if (!inMembers && clsDecl.Match(line).Success) {
                inMembers = true;
            }

            if (inMembers) {
                Match m = contract.Match(line);
                if (m.Success) {
                    if (inContract) {
                        output.WriteLine(endOfContract);
                    }
                    currentContract = m.Groups[1].Captures[0].Value;
                    output.WriteLine("0{0} {0}", currentContract);
                    inContract = true;
                    continue;
                }
            }

            if (inContract) {
                if (tagsBegin.Match(line).Success) {
                    output.WriteLine("#version 0");
                    inTags = true;
                    continue;
                }
            }

            if (inTags) {
                Match m = fieldTag.Match(line);
                if (m.Success) {
                    string tag = m.Groups[1].Captures[0].Value;
                    if ("Any" == tag || "$Tagbase" == tag || "$NextTag" == tag)
                        continue;
                    string val = m.Groups[2].Captures[0].Value;
                    output.WriteLine("#type {0} {1}", tag, HexToInt32(val));
                    continue;
                }

                if (tagsEnd.Match(line).Success) {
                    inTags = false;
                    continue;
                }
            }
        }

        if (inContract) {
            output.WriteLine(endOfContract);
        }
        output.Flush();
    }

    public static int Main(string [] args)
    {
        if (args.Length == 2) {
            using (StreamReader input = new StreamReader(args[0])) {
                using (StreamWriter output = new StreamWriter(args[1])) {
                    (new App()).Generate(input, args[0], output);
                }
            }
        }
        else if (args.Length == 1) {
            using (StreamReader input = new StreamReader(args[0])) {
                (new App()).Generate(input, args[0], Console.Out);
            }
        }
        else if (args.Length == 0) {
            (new App()).Generate(Console.In, "stdin", Console.Out);
        }
        else {
            Console.Error.WriteLine("Bad usage");
            return -1;
        }
        return 0;
    }
}
