/* 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>
    Tokenize and dump the shell-script file.
  </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 uls
{
    namespace tests
    {
        namespace ShellToks
        {
            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 PACKAGE_NAME = "ShellToks";
                static String config_name = "shell.ulc";

                static void usage()
                {
                    Util.err_log("Usage: {0} <shell-file>", PACKAGE_NAME);
                    Util.err_log("   Dumping the tokens in shell-script file.");
                }

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

                    switch (opt)
                    {
                        case 'v':
                            break;
                        case 'h':
                            usage();
                            stat = -1;
                            break;
                        case 'V':
                            stat = -1;
                            break;
                        default:
                            Util.err_log("undefined option -%c", opt);
                            stat = -1;
                            break;
                    }

                    return stat;
                }

                static void dumpToken(ShellLex shlex)
                {
                    int t = shlex.token;
                    String tstr = shlex.lexeme;

                    switch (t)
                    {
                        case ShellLex.WORD:
                            shlex.dumpTok("\t", "WORD", tstr, "\n");
                            break;
                        case ShellLex.NUM:
                            shlex.dumpTok("\t", "NUM", tstr, "\n");
                            break;
                        case ShellLex.REDIRECT:
                            shlex.dumpTok("\t", "REDIR", tstr, "\n");
                            break;
                        case ShellLex.EQ:
                            shlex.dumpTok("\t", "==", tstr, "\n");
                            break;
                        case ShellLex.NE:
                            shlex.dumpTok("\t", "!=", tstr, "\n");
                            break;
                        default:
                            shlex.dumpTok("\t", "\n");
                            break;
                    }
                }

                static void dumpTokens(ShellLex shlex)
                {
                    for ( ; ; )
                    {
                        if (shlex.getTok() == ShellLex.EOI)
                        {
                            break;
                        }
                        dumpToken(shlex);
                    }
                }

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

                    using (UlsContext run_context = new UlsContext("vhV"))
                    {

                        UlsContext.DelegateOptProc opt_proc = new UlsContext.DelegateOptProc(shelltoks_options);
                        if ((i0 = run_context.parseOpts(args, opt_proc)) != 0)
                        {
                            usage();
                            return;
                        }

                        if (i0 < args.Length)
                        {
                            input_file = args[i0];
                        }
                        else
                        {
                            usage();
                            return;
                        }

                        try {
                            shelllex = new ShellLex(config_name);

                            if (shelllex.source(input_file) == false)
                            {
                                Util.err_log("can't open '%s'\n", input_file);
                            }
                            else
                            {
                                dumpTokens(shelllex);
                            }
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("An exception caught: {0}", e);
                        }
                    }
                }
            }
        }
    }
}
