// ---------------------------------------------------------------------------
// - Utility.cpp                                                             -
// - standard object library - utility function class 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-2011 amaury darsch                                   -
// ---------------------------------------------------------------------------

#include "Utility.hpp"
#include "Exception.hpp"
#include "cgen.hpp"
#include "ccnv.hpp"
#include "cmth.hpp"

namespace afnix {

  // return the maximum long integer value

  long Utility::maxlong (void) {
    // shift index to trick the compiler
    long sidx = 0;
    if (sizeof (long) == 8) sidx = 63;
    if (sizeof (long) == 4) sidx = 31;
    if (sidx == 0) {
      throw Exception ("internal-error", "unknown integer size");
    }
    // compute max value
    return ~(1L << sidx);
  }

  // return the minimum long integer value

  long Utility::minlong (void) {
    // shift index to trick the compiler
    long sidx = 0;
    if (sizeof (long) == 8) sidx = 63;
    if (sizeof (long) == 4) sidx = 31;
    if (sidx == 0) {
      throw Exception ("internal-error", "unknown integer size");
    }
    // compute min value
    return (1L << sidx);
  }

  // convert a string to a boolean

  bool Utility::tobool (const String& value) {
    if (value.tolower () == "true")  return true;
    if (value.tolower () == "false") return false;
    throw Exception ("literal-error", "cannot convert to boolean", value);
  }

  // convert a string to an integer

  t_long Utility::tolong (const String& value) {
    bool  status     = false;
    const char* data = value.tochar ();
    t_long result = c_atoll (data, status);
    delete [] data;
    if (status == false) {
      throw Exception ("literal-error",
		       "illegal string integer number", value);
    }
    return result;
  }

  // convert a string to a real

  t_real Utility::toreal (const String& value) {
    bool status = false;
    const char* data = value.tochar ();
    t_real result = c_atod (data, status);
    delete [] data;
    if (status == false) {
      throw Exception ("literal-error", "illegal string real number", value);
    }
    return result;
  }

  // convert an integer to a string

  String Utility::tostring (const long value) {
    char*  buffer = c_ltoa (value);
    String result = buffer;
    delete [] buffer;
    return result;
  }

  // convert an integer to a string

  String Utility::tostring (const t_long value) {
    char*  buffer = c_lltoa (value);
    String result = buffer;
    delete [] buffer;
    return result;
  }

  // convert a real to a string

  String Utility::tostring (const t_real value) {
    return Utility::tostring (value, false);
  }

  // convert a real to a string, eventually in scientific notation

  String Utility::tostring (const t_real value, const bool sflg) {
    char* buffer = sflg ? c_dtos (value) : c_dtoa (value);
    String result (buffer);
    delete [] buffer;
    return result;
  }

  // convert a real to a string with a certain precision

  String Utility::tostring (const t_real value, const long psize) {
    return Utility::tostring (value, psize, false);
  }

  // convert a real to a string with a certain precision

  String Utility::tostring (const t_real value, const long psize, 
			    const bool   sflg) {
    // check the precision
    if (psize < 0) {
      throw Exception ("precision-error", 
		       "invalid negative precision with conversion");
    }
    // check for null precision
    if ((psize == 0) && (c_isnan (value) == false) && 
	(c_isinf (value) ==false)) {
      t_long data = (t_long) value;
      return Utility::tostring (data, sflg);
    }
    // use base precision
    char* buffer = sflg ? c_dtosp (value, psize) : c_dtoap (value, psize);
    String result (buffer);
    delete [] buffer;
    return result;
  }

  // convert a quad to a hexadecimal string

  String Utility::tohexa (const t_quad value) {
    char*  buffer = c_qtoh (value, false);
    String result = buffer;
    delete [] buffer;
    return result;
  }

  // convert a quad to a hexadecimal string and normalize it

  String Utility::tohexa (const t_quad value, const bool nflag) {
    String result = Utility::tohexa (value);
    return nflag ? result.lfill ('0', 8) : result;
  }

  // convert an octa to a hexadecimal string

  String Utility::tohexa (const t_octa value) {
    char*  buffer = c_otoh (value, false);
    String result = buffer;
    delete [] buffer;
    return result;
  }

  // convert an octa to a hexadecimal string and normalize it

  String Utility::tohexa (const t_octa value, const bool nflag) {
    String result = Utility::tohexa (value);
    return nflag ? result.lfill ('0', 16) : result;
  }

  // return a control character from a printable character

  t_quad Utility::toctrl (const char value) {
    return (t_quad) (value - 'a' + 1);
  }

  // return a long random number

  long Utility::longrnd (void) {
    long result = 0;
    // check for quad
    if (sizeof (long) == 8) {
      result = c_octarnd ();
    } else {
      result = c_quadrnd ();
    }
    // force to a positive value
    if (result < 0) result = -result;
    // here it is
    return result;
  }

  // return a long random number upto a maximum

  long Utility::longrnd (const long max) {
    long result = (long) (c_realrnd (true) * max);
    // force to a positive value
    if (result < 0) result = -result;
    // here it is
    return result;
  }

  // return a real random number

  t_real Utility::realrnd (const bool iflg) {
    return c_realrnd (iflg);
  }

  // return a byte random number

  t_byte Utility::byternd (void) {
    return c_byternd ();
  }

  // return a word random number

  t_word Utility::wordrnd (void) {
    return c_wordrnd ();
  }

  // return a quad random number

  t_quad Utility::quadrnd (void) {
    return c_quadrnd ();
  }

  // return an octa random number

  t_octa Utility::octarnd (void) {
    return c_octarnd ();
  }
}
