/*
 * The Spar Library - a maths applications framework 
 * Copyright (C) 2000,2001 Davide Angelocola <davide178@inwind.it>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License.
 *
 * This library 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.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 *
 */

#include <spar/sl_application.h>
#include <stdlib.h>
#include <string.h>

/*
 *  If this system doesn't have the getopt library,
 */
#ifdef HAVE_GETOPT_H
#include "getopt.h"
#else
#include <getopt.h>
#endif

extern void _init_term (void);
extern void _restore_term (void);

static int _quiet_flag = 0;
static int _prec_decimal = SL_DEFAULT_INTEGER_PRECISION;
static int _prec_integer = SL_DEFAULT_DECIMAL_PRECISION;

/* 
 *  The SL Application
 *  
 *  this is a pointer to user sl_application struct
 *  it contains all application infos
 */
static sl_application *_app = NULL;

/*
 *  Getopt Library Interface
 */
extern int optind;
extern char *optarg;

static struct option long_options[] = {
  {"quiet", 0, 0, 'q'},
  {"help", 0, 0, 'h'},
  {"warranty", 0, 0, 'w'},
  {"decimals", 0, 0, 'd'},
  {"integers", 0, 0, 'i'},
  {"config", 0, 0, 'c'},
  {"version", 0, 0, 'v'},
  {0, 0, 0, 0}
};

static void
_usage (void)
{
  sl_writeln ("This program was developed using the Spar Library");
  sl_writeln ("Copyright (C) 2000,2001 Davide Angelocola");
  sl_writeln ("");
  sl_writeln ("%s version %s", _app->name, _app->version);
  sl_writeln ("%s [options] expression", _app->name);
  sl_writeln ("");
  sl_writeln ("Author ....... : %s", _app->author);
  sl_writeln ("Description .. : %s", _app->description);
  sl_writeln ("");
  sl_writeln ("Options:");
  sl_writeln ("  --help       show this message");
  sl_writeln ("  --version    show program version");
  sl_writeln ("  --warranty   show warranty");
  sl_writeln ("  --config     specify a user modules config file");
  sl_writeln ("  --quiet      don't show welcome message");
  sl_writeln ("");
  sl_writeln ("Precision:");
  sl_writeln ("  --decimals   set number of decimals digits");
  sl_writeln ("  --integers   set number of integers digits");
  sl_writeln ("");

  exit (0);
}

static void
_version (void)
{
  sl_writeln ("%s version %s", _app->name, _app->version);
  sl_info ();
  sl_writeln ("");
  sl_writeln
    ("Additional information about Spar is avaiable via the WWW at:");
  sl_writeln ("main site URL   : %s", SL_HOMEPAGE_URL);
  sl_writeln ("mirror site URL : %s", SL_MIRROR_HOMEPAGE_URL);
  sl_writeln ("");
  sl_writeln ("Please report bugs to <%s>", SL_AUTHOR_EMAIL);

  exit (0);
}

static void
_welcome (void)
{
  sl_writeln ("This is free software with ABSOLUTELY NO WARRANTY.");
  if (_app->welcome != NULL)
    {
      sl_writeln ("%s", _app->welcome);
    }
  else
    {
      sl_writeln ("%s version %s", _app->name, _app->version);
      sl_writeln ("Author:   %s", _app->author);
      sl_writeln ("Description: %s", _app->description);
    }

  sl_writeln ("");

  return;
}

void
_init_getopt (int argc, char **argv)
{
  char c;
  int option_index = 0;

  while (1)
    {
      c = getopt_long (argc, argv, "i:d:c:qhv", long_options, &option_index);

      if (c == -1)
	break;

      switch (c)
	{
	case 'w':
	  sl_warranty ();
	  exit (0);
	  break;

	case 'h':
	  _usage ();
	  break;
	case 'v':
	  _version ();
	  break;

	case 'c':
	  strcpy (_app->modules_config_file, optarg);
	  break;

	case 'q':
	  _quiet_flag = 1;
	  break;

	case 'd':
	  {
	    int d = atoi (optarg);

	    if (d > 0)
	      {
		_prec_decimal = d;
	      }
	    else
	      {
		_prec_decimal = -d;
	      }

	    break;
	  }

	case 'i':
	  {
	    int i = atoi (optarg);

	    if (i > 0)
	      {
		_prec_decimal = i;
	      }
	    else
	      {
		_prec_decimal = -i;
	      }

	    break;
	  }

	default:
	  exit (1);
	}

      if (optind < argc)
	{
	  char expression[1024] = "";

	  while (optind < argc)
	    strcat (expression, argv[optind++]);

	  sl_parser_evaluate (expression);

	  exit (0);
	}
    }
}

int
_init_modules (void)
{
  if (_app->modules_config_file == NULL)
    {
      /*
       *  Load modules from the default module config file
       *  defined in sl_conf.h
       */
      return sl_module_loader_load_config (SL_MODULE_CONFIG_FILE);
    }
  else
    {
      /*
       *  A modules configuration file was specified
       *  try to loading it ...
       */
      return sl_module_loader_load_config (_app->modules_config_file);
    }
}

void
_init_precision (void)
{
  /*
   *  If this flag was specified the applications gets:
   *  the "standard" precision
   *  the user precision (from the command line)
   */

  sl_writer_set_precision (_prec_decimal, _prec_integer);
}

void
_init_application (sl_application * t, int argc, char **argv)
{
  sl_assert (t != NULL);
  _app = t;

  switch (_app->options)
    {
    case SL_APP_GETOPT:
      _init_getopt (argc, argv);
      break;

    case SL_APP_MODULES:
      _init_modules ();
      break;

    case SL_APP_PRECISION:
      _init_precision ();
      break;

    case (SL_APP_GETOPT | SL_APP_MODULES):
      _init_getopt (argc, argv);
      _init_modules ();
      break;

    case (SL_APP_GETOPT | SL_APP_PRECISION):
      _init_getopt (argc, argv);
      _init_precision ();

    case (SL_APP_MODULES | SL_APP_PRECISION):
      _init_modules ();
      _init_precision ();
      break;

    case (SL_APP_GETOPT | SL_APP_MODULES | SL_APP_PRECISION):
      _init_getopt (argc, argv);
      _init_modules ();
      _init_precision ();
      break;

    default:
      sl_writeln ("error in application flags");
      sl_application_exit (SL_ERROR);
      break;
    }
  
}

int
sl_application_run (sl_application * t, int argc, char **argv)
{
  int rc;

  rc = sl_init ();
  sl_assert (rc == SL_SUCCESS);

  _init_application (t, argc, argv);
  _init_term ();

  if (!_quiet_flag)
    _welcome ();

/*
 *  If an "application init" function was provided...
 */
  if (_app->init != NULL)
    {
      _app->init ();
    }

  _app->main (argc, argv);

  if (_app->de_init != NULL)
    {
      _app->de_init ();
    }

  rc = sl_de_init ();
  sl_assert (rc == SL_SUCCESS);

  return SL_SUCCESS;
}

void
sl_application_exit (int _exit_code)
{
  int rc;

  if (_app->de_init != NULL)
    {
      _app->de_init ();
    }

  rc = sl_de_init ();
  sl_assert (rc == SL_SUCCESS);

  exit (_exit_code);
}


syntax highlighted by Code2HTML, v. 0.9.1