#include "icode2ast.h"
#include "writeicode.h"
#include "filter.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *progname = "icode2ast";
static int verbose = 0;
static int debug = 0;

static void usage(FILE *fp)
{
  fprintf(fp,
    "Usage: %s [options] [icode-file]\n"
    "\n"
    "Filter an icode file (default extension: .icd).\n"
    "\n"
    "Options:\n"
    "  -o outfile       Write filtered icode to outfile\n"
    "  -d, --debug      Dump the AST after loading it\n"
    "  -v, --verbose    Enable verbose icode output\n"
    "  -h, --help       Display this help and exit\n"
    "\n"
    "If icode-file is supplied, it is read instead of standard input.\n"
    "Examples:\n"
    "      cat input.icd | icode2ast\n"
    "      icode2ast input.icd\n"
    "      icode2ast -o filtered.icd input.icd\n"
    "      icode2ast -dv -o filtered.icd input.icd\n"
    "      icode2ast --debug --verbose --help\n"
    "      icode2ast -- -filename-starting-with-dash.icd\n",
    progname);
}

int main(int argc, char **argv)
{
  IMPAST *Program;
  char *icode_filename = "test-out.icd";
  FILE *icode_file;
  const char *input_filename = NULL;
  int i;

  /* Set progname from argv[0], discarding any directory component. */
  progname = strrchr(argv[0], '/');
  progname = (progname != NULL) ? progname + 1 : argv[0];

  /*
   * Parse options.  A bare "--" ends option parsing, allowing a filename
   * beginning with '-' to be used as the input filename.
   */
  for (i = 1; i < argc; i++) {
    char *arg = argv[i];

    if (strcmp(arg, "--") == 0) {
      i++;
      break;
    }

    if (strcmp(arg, "-d") == 0 || strcmp(arg, "--debug") == 0) {
      debug = 1;
      continue;
    }

    if (strcmp(arg, "-v") == 0 || strcmp(arg, "--verbose") == 0) {
      verbose = 1;
      continue;
    }

    if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
      usage(stdout);
      exit(EXIT_SUCCESS);
    }

    if (strcmp(arg, "-o") == 0) {
      if (++i >= argc) {
        fprintf(stderr, "%s: syntax error: -o requires an output filename\n",
                progname);
        usage(stderr);
        exit(EXIT_FAILURE);
      }
      icode_filename = argv[i];
      continue;
    }

    /*
     * Treat any other option-looking argument as an error.  Non-option
     * arguments are the optional input filename.
     */
    if (arg[0] == '-') {
      fprintf(stderr, "%s: syntax error: unknown option '%s'\n",
              progname, arg);
      usage(stderr);
      exit(EXIT_FAILURE);
    }

    if (input_filename != NULL) {
      fprintf(stderr, "%s: syntax error: more than one input filename given\n",
              progname);
      usage(stderr);
      exit(EXIT_FAILURE);
    }

    input_filename = arg;
  }

  /*
   * Handle positional arguments following "--", if any.
   */
  for (; i < argc; i++) {
    if (input_filename != NULL) {
      fprintf(stderr, "%s: syntax error: more than one input filename given\n",
              progname);
      usage(stderr);
      exit(EXIT_FAILURE);
    }
    input_filename = argv[i];
  }

  /*
   * Reopen stdin on the supplied icode file.  load_icode_file() can then
   * continue to read from stdin without any interface changes.
   */
  if (input_filename != NULL) {
    if (freopen(input_filename, "r", stdin) == NULL) {
      fprintf(stderr, "%s: cannot open icode input %s - %s\n",
              progname, input_filename, strerror(errno));
      exit(EXIT_FAILURE);
    }
  }

  Program = load_icode_file();
  /* The entire program is now in a linear IMPAST. */

  if (debug) {
    fprintf(stdout, "\n========================================== INPUT ==========================================\n\n");
    dump_ast(Program, stdout);
  }

  // PERFORM AST MANIPULATION HERE.
  Program = filter_icode(Program);
  
  if (debug) {
    fprintf(stdout, "\n========================================== OUTPUT ==========================================\n\n");
    dump_ast(Program, stdout);
  }
  
  icode_file = fopen(icode_filename, "w");
  if (icode_file == NULL) {
    fprintf(stderr, "%s: cannot save icode output to %s - %s\n",
            progname, icode_filename, strerror(errno));
    exit(EXIT_FAILURE);
  }
  for (;;) {
    write_icode(Program, verbose, icode_file);
    if (verbose)
      fprintf(stderr, "\n");

    Program = Program->next_icode;
    if (Program == NULL)
      break;
  }

  fprintf(icode_file, "\n");
  fclose(icode_file);

  fprintf(stderr, "Icode written to %s\n", icode_filename);
  exit(EXIT_SUCCESS);
  return 0;
}
