/*
 * Jakelib2 - General purpose C++ library
 * Copyright (C) 2001 Florian Wolff  (florian@donuz.de)
 *
 * 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, or (at your option) any later version.
 *
 * 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
 *
 * $Id: jakelib2.h,v 1.93 2003/09/26 15:47:36 florian Exp $
 */

#ifndef JAKELIB2_H
#define JAKELIB2_H


/**
 * Borland C++
 */
#ifdef __BORLANDC__
# undef WIN32
# define WIN32
# define BORLAND
# define HAVE_WINTHREADS
#endif

/**
 * Microsoft Visual C++
 */
#ifdef _MSC_VER
# undef WIN32
# define WIN32
# define MSVC
# define SIZEOF_CHAR 1
# define SIZEOF_INT 4
# define SIZEOF_SHORT 2
# define SIZEOF_INT64 8
# define SIZEOF_FLOAT 4
# define SIZEOF_DOUBLE 8
# define SIZEOF_WCHAR_T 4
# define HAVE_WINTHREADS 1
# define HAVE_MATH_H
# include <jakelib2/win32config.h>
#endif

/**
 * Include some standard include files
 */

#if !defined(BORLAND) && !defined(MSVC)
# ifdef COMPILE_JAKELIB
#  include "jakelib2/config.h"
# else
#  include <jakelib2/config.h>
# endif
#endif

#define JAKELIB_UNICODE

#include <stdio.h>
#include <stdlib.h>

// For GCC 3:
#undef printf

/**
 * Linux/Unix Environment
 */
#if !defined(WIN32)
# define SOCKET_ERROR -1
# define INVALID_SOCKET -1
  typedef int JL2_SOCKET;

/**
 * Windows32 Environment
 */
#else
  typedef unsigned int JL2_SOCKET;
#endif


/**
 * Define the primitive types
 */

#ifndef false
# define false ((jboolean)0)
#endif
#ifndef true
# define true ((jboolean)1)
#endif
#ifndef null
# define null NULL
#endif


/** Define jbyte to be 8 bit wide */
#if SIZEOF_CHAR == 1
  typedef char jbyte;
#elif SIZEOF_SHORT == 1
  typedef short jbyte;
#elif SIZEOF_INT == 1
  typedef int jbyte;
#else
# error Cannot detect 8-bit integer type for 'jbyte'
#endif

/** Define jchar to be 16 bit wide */
# if SIZEOF_CHAR == 2
  typedef unsigned char jchar;
# elif SIZEOF_SHORT == 2
  typedef unsigned short jchar;
# elif SIZEOF_INT == 2
  typedef unsigned int jchar;
# else
#   error Cannot detect 16-bit unsigned type for 'jchar'
# endif

/** Define jshort to be 16 bit wide */
#if SIZEOF_CHAR == 2
  typedef char jshort;
#elif SIZEOF_SHORT == 2
  typedef short jshort;
#elif SIZEOF_INT == 2
  typedef int jshort;
#else
# error Cannot detect 16-bit integer type for 'jshort'
#endif

/** Define jint to be 32 bit wide */
#if SIZEOF_INT == 4
  typedef int jint;
#elif SIZEOF_LONG == 4
  typedef long jint;
#elif SIZEOF_SHORT == 4
  typedef short jint;
#else
# error Cannot detect 32-bit integer type for 'jint'
#endif

/** Define jlong to be 64 bit wide */
#if SIZEOF_INT == 8
  typedef int jlong;
#elif SIZEOF_LONG == 8
  typedef long jlong;
#elif SIZEOF_LONG_LONG == 8
  typedef long long jlong;
#elif SIZEOF_INT64 == 8
  typedef __int64 jlong;
#else
# error Cannot detect 64-bit integer type for 'jlong'
#endif

/** Define jfloat to be 32 bit wide */
#if SIZEOF_FLOAT == 4
  typedef float jfloat;
#elif SIZEOF_DOUBLE == 4
  typedef double jfloat;
#else
# error Cannot detect 32-bit floating point type for 'jfloat'
#endif

/** Define jdouble to be 64 bit wide */
#if SIZEOF_FLOAT == 8
  typedef float jdouble;
#elif SIZEOF_DOUBLE == 8
  typedef double jdouble;
#else
# error Cannot detect 64-bit floating point type for 'jdouble'
#endif

//typedef int jboolean;
typedef unsigned char jboolean;

#if (SIZEOF_WCHAR_T == 4)
# define JAKELIB_WCHAR_T
#endif

/**
 * Include garbage collector stuff.
 * We use Boehm Garbage Collector (http://www.hpl.hp.com/personal/Hans_Boehm/gc/index.html).
 */
#if defined(POSIX)
# define GC_LINUX_THREADS
# ifndef _REENTRANT
#   define _REENTRANT
# endif
#endif
#include <jakelib2/gc/gc_cpp.h>

/**
 * JNI stuff
 */
typedef union jvalue
{
  jboolean z;
  jbyte    b;
  jchar    c;
  jshort   s;
  jint     i;
  jlong    j;
  jfloat   f;
  jdouble  d;
} jvalue;

/*
 * 64 bit integer (long long) stuff
 */
#ifdef MSVC
# define LL(n) n##I64
#else
# define LL(n) n##LL
#endif

/**
 * Define some macros for convenience
 */
#define JAKELIB_AT2(__methodname) jakelib2_exception_0001->plus(__methodname)->plus(jakelib2_exception_0002)->plus(__FILE__)->plus(jakelib2_exception_0003)->plus((jlong)__LINE__)->plus(jakelib2_exception_0004 )
#define JAKELIB_AT JAKELIB_AT2


/**
 * Returns a pointer to the latin1 c-style string of the given \c String.
 *
 * @param s A \c String object.
 * @return A pointer to the latin1 string or \c null if \c s is \c null.
 */
#define JAKELIB_LATIN1(s) ((s) != null ? (s)->latin1() : null)


/**
 * Asserts that the given argument is not \c null.
 *
 * @param obj The argument to be checked.
 * @param method The fully-qualified method name.
 * @throw NullPointerException If argument is \c null.
 */
#define JAKELIB_NPE(obj, method) if ((obj) == null) throw new jakelib::lang::NullPointerException(jakelib::lang::String(#obj).JAKELIB_AT2(method))


/**
 * Asserts that the specified expression is \b not \c true.
 *
 * @param expr The expression to be checked.
 * @param method The fully-qualified method name.
 * @throw IllegalArgumentException If expression is \c true.
 */
//#define JAKELIB_IAE(expr, method) if (expr) throw new jakelib::lang::IllegalArgumentException(jakelib::lang::String(#expr).JAKELIB_AT2(method))


/**
 * @brief Declare methods for RTTI.
 *
 * @param name The classname (like \c String )
 */
#define JAKELIB_DECLARE_CLASS(name) \
  public: static jakelib::lang::Class _##name##_Class; \
          jakelib::lang::Class* getClass() { return &_##name##_Class; }; 


/**
 * @brief Define static Class variable for RTTI.
 * 
 * @param fullname Fully qualified class name (like \c "jakelib.lang.String" )
 * @param name The classname (like \c String )
 * @param baseclass The classname of the base class (like \c Object)
 */
#define JAKELIB_IMPLEMENT_CLASS(fullname, name, baseclass) \
  jakelib::lang::Class name::_##name##_Class(jakelib::lang::Class::CLASS, fullname, &baseclass::_##baseclass##_Class, null);

#define JAKELIB_IMPLEMENT_CLASS_1(fullname, name, baseclass, i1) \
  jakelib::lang::Class name::_##name##_Class(jakelib::lang::Class::CLASS, fullname, &baseclass::_##baseclass##_Class, &i1::_##i1##_Class, null);

#define JAKELIB_IMPLEMENT_CLASS_2(fullname, name, baseclass, i1, i2) \
  jakelib::lang::Class name::_##name##_Class(jakelib::lang::Class::CLASS, fullname, &baseclass::_##baseclass##_Class, &i1::_##i1##_Class, &i2::_##i2##_Class, null);

#define JAKELIB_IMPLEMENT_CLASS_3(fullname, name, baseclass, i1, i2, i3) \
  jakelib::lang::Class name::_##name##_Class(jakelib::lang::Class::CLASS, fullname, &baseclass::_##baseclass##_Class, &i1::_##i1##_Class, &i2::_##i2##_Class, &i3::_##i3##_Class, null);

#define JAKELIB_IMPLEMENT_CLASS_4(fullname, name, baseclass, i1, i2, i3, i4) \
  jakelib::lang::Class name::_##name##_Class(jakelib::lang::Class::CLASS, fullname, &baseclass::_##baseclass##_Class, &i1::_##i1##_Class, &i2::_##i2##_Class, &i3::_##i3##_Class, &i4::_##i4##_Class, null);

#define JAKELIB_IMPLEMENT_MEMBER_CLASS(fullname, name, baseclass) \
  jakelib::lang::Class baseclass::name::_##name##_Class(jakelib::lang::Class::CLASS, fullname, &baseclass::_##baseclass##_Class, &name::_##name##_Class, null);
/**
 * @brief Declare methods for RTTI.
 *
 * @param name The classname (like \c String )
 */
#define JAKELIB_DECLARE_INTERFACE(name) \
  public: static jakelib::lang::Class _##name##_Class;


#define JAKELIB_IMPLEMENT_INTERFACE(fullname, name) \
  jakelib::lang::Class name::_##name##_Class(jakelib::lang::Class::INTERFACE, fullname, null);

#define JAKELIB_IMPLEMENT_INTERFACE_1(fullname, name, si1) \
  jakelib::lang::Class name::_##name##_Class(jakelib::lang::Class::INTERFACE, fullname, &si1::_##si1##_Class, null);

#define JAKELIB_IMPLEMENT_INTERFACE_2(fullname, name, si1, si2) \
  jakelib::lang::Class name::_##name##_Class(jakelib::lang::Class::INTERFACE, fullname, &si1::_##si1##_Class, &si2::_##si2##_Class, null);

#define JAKELIB_IMPLEMENT_INTERFACE_3(fullname, name, si1, si2, si3) \
  jakelib::lang::Class name::_##name##_Class(jakelib::lang::Class::INTERFACE, fullname, &si1::_##si1##_Class, &si2::_##si2##_Class, &si3::_##si3##_Class, null);

#define JAKELIB_IMPLEMENT_INTERFACE_4(fullname, name, si1, si2, si3, si4) \
  jakelib::lang::Class name::_##name##_Class(jakelib::lang::Class::INTERFACE, fullname, &si1::_##si1##_Class, &si2::_##si2##_Class, &si3::_##si3##_Class, &si4::_##si4##_Class, null);


#define JAKELIB_IMPLEMENT_MEMBER_INTERFACE(fullname, name, mi1) \
  jakelib::lang::Class name::mi1::_##mi1##_Class(jakelib::lang::Class::INTERFACE, fullname, &name::mi1::_##mi1##_Class, null);

/**
 * Define static class variable for an array class.
 * 
 * @param elementClass The class (like \c String) of the elements
 */
#define JAKELIB_IMPLEMENT_ARRAYCLASS(elementClass) \
  jakelib::lang::Class elementClass##s::_##elementClass##s_Class(&elementClass::_##elementClass##_Class);


/**
 * Define static class variable for an array class.
 * 
 * @param typename The type name (like \c jint) of the elements
 */
#define JAKELIB_IMPLEMENT_PRIMITIVE_ARRAYCLASS(typename) \
  jakelib::lang::Class typename##s::_##typename##s_Class(#typename);

#define JAKELIB_ONDEMAND(var, constructor) (var != null ? var : (var = constructor))

#define JAKELIB_INIT initJakelib2(argc, argv)


/**
 * Include our header files
 */
#include <jakelib2/lang/Object.h>
#include <jakelib2/lang/Array.h>
#include <jakelib2/lang/Class.h>
#include <jakelib2/lang/Interface.h>
#include <jakelib2/lang/Comparable.h>
#include <jakelib2/lang/String.h>
#include <jakelib2/lang/StringBuffer.h>
#include <jakelib2/lang/Exception.h>
#include <jakelib2/lang/StackTraceElement.h>
#include <jakelib2/io/IOException.h>


/**
 * Macros for StackTrace creation:
 */

#ifdef MSVC
# if _MSC_VER <= 0x04B0  
#  define JAKELIB_METHODNAME "?"  
# else  
#  define JAKELIB_METHODNAME __FUNCTION__  
# endif
#else
# define JAKELIB_METHODNAME __PRETTY_FUNCTION__
#endif

#ifdef JAKELIB_STACKTRACE
# define JAKELIB_METHOD \
  jakelib::lang::TmpStackTraceElement _jakelib2_stackTraceElement(JAKELIB_METHODNAME, __FILE__, __LINE__);
#else
# define JAKELIB_METHOD
#endif


#endif
