// ---------------------------------------------------------------------------
// - SysCalls.cpp                                                            -
// - afnix:sys module - system call implementation                           -
// ---------------------------------------------------------------------------
// - 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 "Cons.hpp"
#include "Real.hpp"
#include "Vector.hpp"
#include "System.hpp"
#include "Utility.hpp"
#include "Integer.hpp"
#include "SysCalls.hpp"
#include "Exception.hpp"
 
namespace afnix {

  // exit this process with an exit code

  Object* sys_exit (Runnable* robj, Nameset* nset, Cons* args) {
    // get the arguments
    Vector* argv = Vector::eval (robj, nset, args);
    long    argc = (argv == nilp) ? 0 : argv->length ();
    if (argc != 1) {
      delete argv;
      throw Exception ("argument-error", 
		       "invalid number of arguments with exit");
    }
    try {
      long val = argv->getint (0);
      delete argv; argv = nilp;
      System::exit (val);
      return nilp;
    } catch (...) {
      delete argv;
      throw;
    }
  }

  // return a formated options

  Object* sys_getopt (Runnable* robj, Nameset* nset, Cons* args) {
    // get the arguments
    Vector* argv = Vector::eval (robj, nset, args);
    long    argc = (argv == nilp) ? 0 : argv->length ();
    if (argc != 1) {
      delete argv;
      throw Exception ("argument-error",
		       "invalid number of arguments with getopt");
    }
    try {
      t_quad opte = argv->getchar (0);
      delete argv; argv = nilp;
      return new String (System::getopt (opte));
    } catch (...) {
      delete argv;
      throw;
    }
  }

  // return the process id

  Object* sys_getpid (Runnable* robj, Nameset* nset, Cons* args) {
    // get the arguments
    long argc = (args == nilp) ? 0 : args->length ();
    if (argc != 0) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with getpid");
    }
    return new Integer (System::getpid ());
  }

  // pause for a certain time

  Object* sys_sleep (Runnable* robj, Nameset* nset, Cons* args) {
    // get the arguments
    Vector* argv = Vector::eval (robj, nset, args);
    long    argc = (argv == nilp) ? 0 : argv->length ();
    if (argc != 1) {
      delete argv; argv = nilp;
      throw Exception ("argument-error", 
		       "invalid number of arguments with sleep");
    }
    try {
      long val = argv->getint (0);
      delete argv; argv = nilp;
      System::sleep (val);
      return nilp;
    } catch (...) {
      delete argv;
      throw;
    }
  }

  // return an environment variable value

  Object* sys_getenv (Runnable* robj, Nameset* nset, Cons* args) {
    // get the arguments
    Vector* argv = Vector::eval (robj, nset, args);
    long    argc = (argv == nilp) ? 0 : argv->length ();
    if (argc != 1) {
      delete argv;
      throw Exception ("argument-error", 
		       "invalid number of arguments with getenv");
    }
    try {
      String val = argv->getstring (0);
      delete argv; argv = nilp;
      return new String (System::getenv (val));
    } catch (...) {
      delete argv;
      throw;
    }
  }

  // return a long random number

  Object* sys_longrnd (Runnable* robj, Nameset* nset, Cons* args) {
    // get the arguments
    Vector* argv = Vector::eval (robj, nset, args);
    long    argc = (argv == nilp) ? 0 : argv->length ();
    try {
      // check for 0 argument
      if (argc == 0) {
	delete argv; argv = nilp;
	return new Integer (Utility::longrnd ());
      }
      // check for 1 argument
      if (argc == 1) {
	long max = argv->getint (0);
	delete argv; argv = nilp;
	return new Integer (Utility::longrnd (max));
      }
      throw Exception ("argument-error", "too many argument with get-random");
    } catch (...) {
      delete argv;
      throw;
    }
  }

  // return a real random number between 0.0 and 1.0

  Object* sys_realrnd (Runnable* robj, Nameset* nset, Cons* args) {
    return new Real (Utility::realrnd ());
  }

  // get a unique id from the system

  Object* sys_uniqid (Runnable* robj, Nameset* nset, Cons* args) {
    return new Integer (System::uniqid ());
  }

  // return the host name

  Object* sys_hostname (Runnable* robj, Nameset* nset, Cons* args) {
    return new String (System::hostname ());
  }

  // return the user name

  Object* sys_username (Runnable* robj, Nameset* nset, Cons* args) {
    return new String (System::username ());
  }
}
