#include <stdlib.h>
#include "cmdline.h"
#include "memutil.h"
#include "version.h"
#include "parse.h"
#include "symbol.h"
#include "emit.h"

void usage(int exit_code)
{
#define NL "\n"
  fprintf(stderr,                                                            NL
    "sketch [options] file1 [-D tag][-U tag] file2..."                       NL
    "-h                 Print this message to standard error"                NL
    "-v                 Print version info to standard output"               NL
    "-d                 Debug parser (for developers)"                       NL
    "-b                 Use BSP rather than Painters algorithm for HSR"      NL
    "-T[u|e][p[P|T]]    Produce a complete LaTeX document"                   NL
    "  u                U.S. paper size (8.5 x 11 inches) (default)"         NL
    "  e                European A4 paper size (297 x 210 mm)"               NL
    "  p                Print document template to stdout"                   NL
    "    P              Print PSTricks version of doc template (default)"    NL
    "    T              Print TikZ version of doc template"                  NL
    "-t templatefile    Load user document template"                         NL
    "                     (any text file with escape %%SKETCH_OUTPUT%%)"     NL
    "-o outfile         Put output in outfile (default is stdout)"           NL
    "-D tag             Define given tag"                                    NL
    "-U tag             Undefine given tag"                                  NL
    );
#undef NL
  exit(exit_code);
}

static int is_doc_template_file_name(char *s)
{
  return s[0] != '-' || s[1] == '\0';
}

// process argv[1..argc-1] to fill in env and prepare it for wrapping
void process_global_options(CMD_LINE_OPT_ENV *env, int argc, char **argv, SYMBOL_TABLE *sym_tab)
{
  int i, j;

  // i = 0
  // bsp_only_p = false
  // doc_template_name = NULL
  // out_file_name = NULL
  // skip_stdin_p = false
  // argc = 0;
  SET_STRUCT_ZERO(env);
  env->sym_tab = sym_tab;

  // we'll copy args that need to be processed in order with filenames here.
  // the convention will be that args with paramaters like -Dfoo will be 
  // separated into -D and foo, so we could end up doubling the number of args.
  env->argv = safe_malloc(2 * (argc - 1) * sizeof(char*));

  for (i = 1; i < argc; i++) {
    if (argv[i][0] == '-') {
      switch (argv[i][1]) {
      case 'b':
        env->bsp_only_p = 1;
        break;
      case 'd':
        yydebug = 1;
        break;
      case 'h':
        usage(0);
        break;
      case 'D':
      case 'U':
        env->argv[env->argc++] = argv[i];
        if (argv[i][2])
          env->argv[env->argc++] = &argv[i][2];
        else if (i + 1 < argc)
          env->argv[env->argc++] = argv[++i];
        else
          err(no_line, "missing tag after %s", argv[i]);
        break;
      case 'o':
        if (env->out_file_name)
          err(no_line, "only one use of -o is allowed");
        if (argv[i][2])
          env->out_file_name = &argv[i][2];
        else {
          if (i + 1 < argc)
            env->out_file_name = &argv[++i][0];
          else
            err(no_line, "missing file name after -o");
        }
        break;        
      case 't':
        if (argv[i][2])
          env->doc_template_file_name = &argv[i][2];
        else if (i + 1 < argc && is_doc_template_file_name(argv[i + 1]))
          env->doc_template_file_name = argv[++i];
        else 
          err(no_line, "missing document template file name after -t");
        break;
      case 'T':
        j = 2;
        if (argv[i][j] == 'e') {
          env->doc_template_file_name = standard_euro_doc_template_file_name_flag;
          ++j;
        }
        else if (argv[i][j] == 'u') {
          env->doc_template_file_name = standard_us_doc_template_file_name_flag;
          ++j;
        }
        else {
          env->doc_template_file_name = standard_us_doc_template_file_name_flag;
        }
        if (argv[i][j] == 'p') {
					switch (argv[i][j+1]) {
					case '\0':
					case 'P':
						printf("%% PSTricks document template:\n%s", 
							doc_template_from_file(env->doc_template_file_name, GEOL_PSTRICKS));
						break;
					case 'T':
						printf("%% TikZ document template:\n%s", 
							doc_template_from_file(env->doc_template_file_name, GEOL_TIKZ));
						break;
					default:
						err(no_line, "unrecognized language spec '%c' after -Tp", argv[i][j+1]);
						break;	
					}
          env->skip_stdin_p = 1;
        }
        else if (argv[i][j] != '\0') {
          err(no_line, "unrecognized modifier of option '-T%c'", argv[i][j]);
        }
        break;
      case 'v':
        fprintf(stdout, "sketch version %s", VER_STRING);
        env->skip_stdin_p = 1;
        break;
      default:
        err(no_line, "unrecognized option '%s'", argv[i]);
        break;
      }
    }
    else { // no leading -
      env->argv[env->argc++] = argv[i];
    }
  }
  env->argv = safe_realloc(env->argv, env->argc * sizeof(char*));
}

// advance the environment initialized above until the next filename has been found
char *advance_to_next_file_name(CMD_LINE_OPT_ENV *env)
{
  for ( ; env->i < env->argc; env->i++) {
    if (env->argv[env->i][0] == '-') {
      switch (env->argv[env->i][1]) {
      case 'D':
        ++env->i;
        (void)new_symbol(env->sym_tab, env->argv[env->i], NULL, new_tag_def(), no_line); 
        break;
      case 'U':
        // this will produce an error message if tag doesn't exist
        ++env->i;
        if (tag_exists_p(env->sym_tab, env->argv[env->i]))
          remove_symbol(env->sym_tab, env->argv[env->i], no_line);
        break;
      default:
        die(no_line, "advance_to_next_file_name: unexpected option %c", env->argv[env->i][1]);
        break;
      }
    }
    else {
      return env->argv[env->i++];
    }
  }
  return NULL;
}
