// ---------------------------------------------------------------------------
// - Main.cpp                                                                -
// - the afnix debugger main program                                         -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - This program  is  distributed in  the hope  that it will be useful, but -
// - without  any  warranty;  without  even   the   implied    warranty   of -
// - merchantability or fitness for a particular purpose.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2008 amaury darsch                                   -
// ---------------------------------------------------------------------------

#include "System.hpp"
#include "Debugger.hpp"

namespace afnix {

  // -------------------------------------------------------------------------
  // - private section                                                       -
  // -------------------------------------------------------------------------

  // the options messages
  static const String U_CLS_MSG = "axd [options] [file] [arguments]";
  static const String F_EMC_MSG = "    [f  emacs]\t enable emacs mode";
  static const String F_INI_MSG = "    [f runini]\t run initial file";

  // get the interpreter options
  static Options* get_options (Output& os,const long argc,const char** argv) {
    // create a new option instance
    Options* opts = Interp::getopts ();
    // set debugger specific options
    opts->setumsg (U_CLS_MSG);
    opts->add ('f', "emacs",  F_EMC_MSG);
    opts->add ('f', "runini", F_INI_MSG);

    // parse the options
    try {
      opts->parse (argc, argv);
      // check for verbose and version
      if (opts->getoflg ('h') == true) {
	opts->usage (os);
	delete opts;
	System::exit (0);
      }
      if (opts->getoflg ('v') == true) {
	os << "afnix cross debugger, " << System::osname ();
	os << ", revision " << System::version () << eolc;
	delete opts;
	System::exit (0);
      }
      // check for empty arguments
      if (opts->empty () == true) {
	opts->usage (os);
	delete opts;
	System::exit (1);
      }
    } catch (...) {
      opts->usage (os);
      delete opts;
      System::exit (1);
    }
    return opts;
  }

  // this procedure process the options
  static bool run_options (Options* opts) {
    // get the options arguments
    Strvec args = opts->getargs ();
    String name = args.pop ();
    
    // create a new debugger
    Debugger* dbg = new Debugger;

    // eventually add the initial path
    if (opts->getoflg ('f', "nopath") == false) {
      dbg->addpath (System::xdir (name));
    }
    // set some interpreter flags
    dbg->setargs  (args);
    dbg->setasrt  (opts->getoflg ('f', "assert"));
    dbg->setpath  (opts->getoptv ('i'));
    dbg->setemacs (opts->getoflg ('f', "emacs"));
    if (opts->getoflg ('e') == true) {
      dbg->setemod (opts->getopts ('e'));
    }
    // loop depending on the initial status
    bool status = false;
    if (opts->getoflg ('f', "runini") == false) {
      dbg->setinitial (name);
      status = dbg->loop ();
    } else {
      status = dbg->Interp::loop (name);
    }
    // clean the interpreter and return
    delete dbg;
    return status;
  }
}

// ---------------------------------------------------------------------------
// - main process section                                                    -
// ---------------------------------------------------------------------------

int main (int argc, const char** argv) {
  using namespace afnix;
  OutputTerm terr (OutputTerm::ERROR);

  // main processing loop
  try {
    // register the program name
    System::initialize (argv[0]);
    // get the options and run them
    Options* opts = get_options (terr, argc, argv);
    // process the options
    bool status = run_options (opts);
    // clean everything and return
    delete opts;
    if (status == false) return 3;
  } catch (const Exception& e) {
    terr.errorln (e);
    return 1;
  } catch (...) {
    terr << "fatal: unknown exception trapped\n";
    return 2;
  }
  // so far, so good
  return 0;
}
