/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
  <file> Program.cs </file>
  <brief>
    Demonstrate the C# API of Uls
  </brief>
  <author>
    Stanley Hong <link2next@gmail.com>, Dec. 2013.
  </author>
*/

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

using uls.polaris;
using uls.collection;

namespace DumpToks
{
    public class Util
    {
        // <brief>
        // Get the basename of file-path!
        // Returns 'basename.c when the 'filepath' is '\a\b\basename.c'.
        // </brief>
        // <parm name="filepath">input path string</parm>
        public static String uls_filename(String filepath)
        {
            String fname;
            int i;

            if ((i = filepath.LastIndexOf('\\')) < 0)
            {
                fname = filepath;
            }
            else
            {
                fname = filepath.Substring(i + 1);
            }

            return fname;
        }

        // <brief>
        // This appends the line-feed character '\n' at the message formatted by 'fmtstr'.
        // </brief>
        public static void err_log(String fmtstr, params object[] objs)
        {
            String dotstr;
            dotstr = String.Format(fmtstr, objs);
            Console.WriteLine(dotstr);
        }

        // <brief>
        // This calls err_log() above and terminates the program to abnormal state.
        // </brief>
        public static void err_panic(String fmtstr, params object[] objs)
        {
            err_log(fmtstr, objs);
            Environment.Exit(1);
        }
    }

    class Program
    {
        static String progname = "DumpToks";
        static String input_file;
        
        public delegate void NodeOpDelegate(IntPtr a, IntPtr b);

        class sample_xdef : Object {
	        public int tok_id;
	        public int prec;
	        public int node_id;
	        public NodeOpDelegate node_op;
        };

        static void mul_nodetree(IntPtr a, IntPtr b) {}
        static void add_nodetree(IntPtr a, IntPtr b) {}
        static void div_nodetree(IntPtr a, IntPtr b) {}
        static void and_nodetree(IntPtr a, IntPtr b) {}
        static void xor_nodetree(IntPtr a, IntPtr b) {}

        static sample_xdef[] xdefs = new sample_xdef[5];

        static void init_xdefs()
        {
            sample_xdef xdef;

            xdef = new sample_xdef();
            xdef.tok_id = '*';
            xdef.prec = 27;
            xdef.node_id = 1;
            xdef.node_op = new NodeOpDelegate(mul_nodetree);
            xdefs[0] = xdef;

            xdef = new sample_xdef();
            xdef.tok_id = '+';
            xdef.prec = 26;
            xdef.node_id = 2;
            xdef.node_op = new NodeOpDelegate(add_nodetree);
            xdefs[1] = xdef;

            xdef = new sample_xdef();
            xdef.tok_id = '/';
            xdef.prec = 25;
            xdef.node_id = 3;
            xdef.node_op = new NodeOpDelegate(div_nodetree);
            xdefs[2] = xdef;

            xdef = new sample_xdef();
            xdef.tok_id = '&';
            xdef.prec = 24;
            xdef.node_id = 4;
            xdef.node_op = new NodeOpDelegate(and_nodetree);
            xdefs[3] = xdef;

            xdef = new sample_xdef();
            xdef.tok_id = '^';
            xdef.prec = 23;
            xdef.node_id = 5;
            xdef.node_op = new NodeOpDelegate(xor_nodetree);
            xdefs[4] = xdef;
        }

        static void test_uls(SimpleLex sam1, String fpath)
        {
            int i;
            sample_xdef  xdef;

            for (i = 0; i < 5; i++) {
                Console.WriteLine("The tok-info for tok-id({0}) registered.", xdefs[i].tok_id);
                sam1.setExtraTokdef(xdefs[i].tok_id, xdefs[i]);
            }

            sam1.pushFile(fpath);

            for ( ; ; ) {
                if (sam1.getTok() == SimpleLex.EOI) break;

                xdef = (sample_xdef) sam1.getExtraTokdef();

                sam1.dumpTok("\t", "");

                if (xdef != null)
                    Console.WriteLine(" prec={0} node_id={1}", xdef.prec, xdef.node_id);
                else
                    Console.WriteLine("");
            }
        }

        static bool test_streaming(SimpleLex sam1, string input_file)
        {
		    string uls_file = "a2.uls";
		    string lxm;
		    int t;

		    UlsOStream ofile = new UlsOStream(uls_file, sam1, "<<tag>>");
		    UlsIStream ifile = new UlsIStream(input_file);

		    ofile.startStream(ifile);
		    ifile.close();
		    ofile.close();

		    // Read the written input-stream previously.
		    ifile = new UlsIStream(uls_file);
		    sam1.pushInput(ifile);

		    for ( ; ; ) {
			    t = sam1.next();
			    if (t == sam1.toknum_EOI) break;
			    lxm = sam1.TokStr;
                Console.WriteLine("\t[{0}] {1}", t, lxm);
		    }

		    ifile.close();
		    return true;
        }

        static bool test_tokseq(SimpleLex sam1, string input_file)
        {
		    UlsTmplList  TmplLst = new UlsTmplList();
		    string uls_file = "a3.uls";
		    string lxm;
		    int t;

		    TmplLst.add("TVAR1", "unsigned long long");
		    TmplLst.add("TVAR2", "long double");

		    // Write a output-stream
		    UlsOStream ofile = new UlsOStream(uls_file, sam1, "<<tag>>");
		    sam1.pushFile(input_file);

		    for ( ; ; ) {
			    t = sam1.getTok();

			    if (t == sam1.toknum_ERR) {
				    return false;
			    }

			    if (t == sam1.toknum_EOF || t == sam1.toknum_EOI) {
				    break;
			    }

			    lxm = sam1.TokStr;

			    if (t == sam1.toknum_ID && TmplLst.exist(lxm) == true) {
				    t = sam1.toknum_TMPL;
			    }

			    ofile.printTok(t, lxm);
		    }

		    ofile.close();

		    // Read the written input-stream previously.
		    UlsIStream ifile = new UlsIStream(uls_file, TmplLst);

		    sam1.pushInput(ifile);

		    for ( ; ; ) {
			    t = sam1.getTok();
			    if (t == sam1.toknum_EOI) break;
			    lxm = sam1.TokStr;
			    Console.WriteLine("\t[{0}] {1}", t, lxm);
		    }

		    ifile.close();
		    return true;
        }

        static void usage()
        {
            Util.err_log("{0} v1.1", progname);
            Util.err_log("  Dumps tokens in the input-files");
            Util.err_log("");
            Util.err_log(" Usage:");
            Util.err_log("  {0} <inputfile> [config-file]", progname);
            Util.err_log("");
            Util.err_log("  For example,");
            Util.err_log("      {0} input1.txt", progname);
            Util.err_log("      {0} input1.txt simplest", progname);
            Util.err_log("      {0} input1.txt sample1.ulc", progname);
        }

        static int options(int opt, String optarg)
        {
            int stat = 0;

            switch (opt)
            {
                case 'm':
                    break;

                case 'v':
                    break;

                default:
                    Util.err_log("undefined option -%c", opt);
                    stat = -1;
                    break;
            }

            return stat;
        }

        static void Main(String[] args)
        {
            int i0;

            using (UlsContext run_context = new UlsContext("m:v")) {
                UlsContext.DelegateOptProc opt_proc = new UlsContext.DelegateOptProc(options);
                if ((i0 = run_context.parseOpts(args, opt_proc)) != 0 || i0 >= args.Length)
                {
                    usage();
                    return;
                }

                input_file = args[i0];

                init_xdefs();

                try
                {
                    Console.WriteLine("Dumping tokens of {0} with token defintion file.",
                        input_file);

                    SimpleLex sample1_lex = new SimpleLex();

                    test_uls(sample1_lex, input_file);
                    test_streaming(sample1_lex, input_file);
                    test_tokseq(sample1_lex, input_file);

                }
                catch (Exception e)
                {
                    Console.WriteLine("An exception caught: {0}", e);
                }
            }
        }
    }
}
