// ---------------------------------------------------------------------------
// - 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-2023 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"
#include "transient.tcc"

namespace afnix {

  // exit this process with an exit code

  Object* sys_exit (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 1) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with exit");
    }
    // exit the process
    long val = argv->getlong (0);
    System::exit (val);
    return nullptr;
  }

  // return a formated options

  Object* sys_getopt (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 1) {
      throw Exception ("argument-error",
		       "invalid number of arguments with getopt");
    }
    // get the option
    t_quad opte = argv->getchar (0);
    return new String (System::getopt (opte));
  }

  // return the process id

  Object* sys_getpid (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 0) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with getpid");
    }
    // get the pid
    return new Integer (System::getpid ());
  }

  // pause for a certain time

  Object* sys_sleep (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 1) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with sleep");
    }
    // pause by time
    long time = argv->getlong (0);
    System::sleep (time);
    return nullptr;
  }

  // get a real time stamp

  Object* sys_rtget (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 0) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with real-time-stamp");
    }
    // get the real time stamp
    return new Real (System::rtget ());
  }

  // get a real time stamp in seconds

  Object* sys_rtsec (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 0) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with real-time-round");
    }
    // get the real time stamp
    return new Real (System::rtsec ());
  }
  
  // sleep until real time stamp

  Object* sys_rtslp (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 1) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with real-time-sleep");
    }
    // sleep util time stamp
    t_real stmp = argv->getreal (0);
    System::rtslp (stmp);
    return nullptr;
  }
  
  // return an environment variable value

  Object* sys_getenv (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 1) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with getenv");
    }
    // get the environment variable
    String val = argv->getstring (0);
    return new String (System::getenv (val));
  }

  // get a unique id from the system

  Object* sys_uniqid (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 0) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with get-unique-id");
    }
    // get a unique id
    return new Integer (System::uniqid ());
  }

  // return the host fqdn

  Object* sys_hostfqdn (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 0) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with get-host-fqdn");
    }
    // get the host fqdn
    return new String (System::hostfqdn ());
  }

  // return the host domain name

  Object* sys_domainname (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 0) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with get-domain-name");
    }
    // get the domain name
    return new String (System::domainname ());
  }
  // return the host name

  Object* sys_hostname (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 0) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with get-host-name");
    }
    // get the host name
    return new String (System::hostname ());
  }

  // return the user name

  Object* sys_username (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 0) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with get-user-name");
    }
    // get the user name
    return new String (System::username ());
  }

  // return the user home directory

  Object* sys_userhome (Evaluable* zobj, Nameset* nset, Cons* args) {
    // get the arguments
    t_transient<Vector> argv = Vector::eval (zobj, nset, args);
    long argc = argv.valid() ? argv->length () : 0L;
    if (argc != 0) {
      throw Exception ("argument-error", 
		       "invalid number of arguments with get-user-home");
    }
    // get the user home directory
    return new String (System::userhome ());
  }
}
