#include <string.h>
#include <sys/time.h>
#ifdef SCOUT
#include <scout_config.h>
#include <scout/aio.h>
#include <scout/basic.h>
#include <scout/fsfattr.h>
#include <scout/fsfname.h>
#include <scout/msg.h>
#include <scout/path.h>
#include <scout/net.h>
#include <scout/netListen.h>
#include <scout/ns.h>
#include <scout/part.h>
#include <scout/protid.h>
#include <netinet/in.h>
#include <scout/semaphore.h>
#include <scout/system.h>
#include <scout/winmgr.h>
#include <scout/mgrEvent.h>
#include <scout/trace.h>
#include <scout/ctl.h>
#include <scout/event.h>
#include <scout/errno.h>
#include <awt.h>
#include <joust_i.h>
#else /* SCOUT */
#include <stdlib.h>
#include <sys/utsname.h>
#include <sys/param.h>
#include <unistd.h>
#include <pwd.h>
#endif /* SCOUT */

#include "toba.h"
#include "runtime.h"
#include "java_lang_System.h"
#include "java_lang_Error.h"
#include "java_util_Hashtable.h"
#include "java_util_Properties.h"

#ifdef SCOUT
extern JOUSTRouter global_jr;
#endif /* SCOUT */

/* java/lang/System currentTimeMillis ()J */
Long currentTimeMillis__gBRCJ() 
{
    Long res;
#ifdef SCOUT
    struct Time t;
#else /* SCOUT */
    struct timeval tv;
#endif /* SCOUT */

    /* STATIC Method */
    init_java_lang_System();

#ifdef SCOUT
    gettimeofday(&t);
    res = (Long)t.usec / 1000 + (Long)t.sec * 1000;
#else /* SCOUT */
    gettimeofday(&tv, 0);
    res = (Long)tv.tv_usec / 1000 + (Long)tv.tv_sec * 1000;
#endif /* SCOUT */
    return res;
}

/* java/lang/System arraycopy (Ljava/lang/Object;ILjava/lang/Object;II)V */
Void arraycopy_OiOii_JRbqy(Object Harg1, Int src_pos, Object Harg3, Int dst_pos, Int len) 
{
    struct barray *src = (struct barray *)Harg1;
    struct barray *dst = (struct barray *)Harg3;
    int elemsize;

    /* STATIC Method */
    init_java_lang_System();

    if(!src || !dst)
        throwNullPointerException("arraycopy");

    /* src and dst must both be arrays */
    if(!(src->class->flags & IS_ARRAY) ||
       !(dst->class->flags & IS_ARRAY))
        throwArrayStoreException("Object is not an array");

    /* pos and length must be in range */
    if(src_pos < 0 || src_pos > src->length ||
       len < 0 || src_pos+len > src->length ||
       dst_pos < 0 || dst_pos > dst->length ||
       dst_pos+len > dst->length)
        throwIndexOutOfBoundsException("bad bounds for arraycopy");
    
    /* make sure its legal to do the copy between arrays */
    if(instanceof(src, dst->class->elemclass, 1)) {
       /* 
        * element types are either equivalent or the
        * destination type is a superclass of the source type.
        * the copy is guaranteed to be legal and we can do a
        * memmove (but not memcpy, because src and dst may overlap).
        */
        elemsize = src->class->instsize;
        memmove(dst->data + dst_pos * elemsize,
               src->data + src_pos * elemsize,
               len * elemsize);
    } else if(instanceof(dst, src->class->elemclass, 1)) {
        /*
         * the element type of the source is a super type of
         * the element type of the destination.  Copies
         * are legal only if each copied element from the src
         * is already of a type assignable to the dest array.
         *
         * We know that we have arrays of objects at this point.
         */
        struct aarray *asrc = (struct aarray *)src;
        struct aarray *adst = (struct aarray *)dst;

        while(len--) {
            /* note: asrc->data[src_pos] can be a null reference */
            if(asrc->data[src_pos] &&
               !instanceof(asrc->data[src_pos], adst->class->elemclass, 0))
                throwArrayStoreException("incompatible element types");
            
            adst->data[dst_pos++] = asrc->data[src_pos++];
        }
    } else {
        /* the types didn't match */
        throwArrayStoreException("incompatible element types");
    }
}

struct prop {
    char *key, *val;
};

/* java/lang/System initProperties (Ljava/util/Properties;)Ljava/util/Properties; */
Object initProperties_P_hGJ5i(Object Harg1) 
{
    static struct prop prop[] = {
        /* NB: For scout, if this toolkit changes, the patch to java.awt.Toolkit
         * must be updated. */
        { "awt.toolkit",	AWT_TOOLKIT },
        { "java.vendor",        TOBA_VENDOR },
        { "java.vendor.url",    TOBA_URL },
        { "java.vendor.version",TOBA_VERSION },
        { "java.version",       JAVA_VERSION },
        { "java.class.version", CLASS_VERSION },
        { "file.separator",     FILE_SEPARATOR },
        { "path.separator",     PATH_SEPARATOR },
        { "line.separator",     LINE_SEPARATOR },
        { "os.name",            "" },
        { "os.version",         "" },
        { "java.home",          "" },
        { "java.class.path",    "" },
        { "toba.class.path",    "" },
        { 0, 0 } /*last*/
    };
    struct in_java_util_Properties *arg1 = 
        (struct in_java_util_Properties *)Harg1;
    Object (*putfunc)(Object, Object, Object);
    int i;
#ifndef SCOUT
    struct utsname uts;
    struct passwd *pw;
    int res;
    char *cp, *name, *val, buf[MAXPATHLEN + 1];
    extern char **environ;
#endif /* ! SCOUT */

    /* STATIC Method */
    init_java_lang_System();

    /* get the method for put() from Properties' method table */
    putfunc = cl_java_util_Properties.M.put_OO_4Xy3U.f;

    /* sanity - putfunc should be the same as java_util_Hashtable.put() */
    if(putfunc != put_OO_4Xy3U) {
        throwMesg(&cl_java_lang_Error.C, 
                   "initProperites: API lib out of date");
    }

/* Macro to simplify setting properties which may or may not have a defined
 * value. */
#define AddProperty(_src,_prop) { \
    char * xprop = (_src); \
    if (0 != xprop) { \
       putfunc (arg1, javastring(_prop), javastring(xprop)); \
    } \
}

    /* static properties */
    for(i = 0; prop[i].key; i++) {
        AddProperty(prop[i].val, prop[i].key);
    }

#ifdef SCOUT
    AddProperty(global_jr->user_name, "user.name");
    AddProperty(global_jr->user_home, "user.home");
    AddProperty(global_jr->toba_class_path, "toba.class.path");
    AddProperty(global_jr->java_class_path, "java.class.path");

    AddProperty("Scout", "os.name");
    AddProperty("1.0", "os.version");

    /* dynamic properties */
#if (defined(OPTION_ALPHA_CABRIOLET) || defined(OPTION_ALPHA_FLAMINGO) || \
     defined(OPTION_ALPHA_NONAME) || defined(OPTION_ALPHA_AVANTI))
    AddProperty("alpha", "os.arch");
#elif defined(OPTION_X86_PENTIUM)
    AddProperty("x86", "os.arch");
#endif /* OPTION_architecture */
     
    /* No environment support in Scout. */
#else /* SCOUT */

    /* dynamic properties */
    res = uname(&uts);
    AddProperty (res != -1 ? uts.sysname : "", "os.name");
    AddProperty (res != -1 ? uts.release : "", "os.version");
    AddProperty (res != -1 ? uts.machine : "", "os.arch");

    pw = getpwuid(getuid());
    AddProperty (pw ? pw->pw_name : "unknown", "user.name");
    AddProperty (pw ? pw->pw_dir : "unknown", "user.home");
    AddProperty (getcwd(buf, MAXPATHLEN + 1), "user.dir");

    AddProperty (getenv ("CLASSPATH"), "java.class.path");
    AddProperty (getenv ("TOBAPATH"), "toba.class.path");
    AddProperty (getenv ("JAVA_HOME"), "java.home");

    /* translate any TOBA_ environmental variables to properties */
    for(i = 0; environ[i]; i++) {
        if(strncmp(environ[i], TOBA_PREFIX, TOBA_PREFIX_LEN) == 0) {
            char *tmpcopy;

            cp = environ[i] + TOBA_PREFIX_LEN;
            tmpcopy = allocate(strlen(cp) + 2);
            strcpy(tmpcopy, cp);

            name = strtok(tmpcopy, "=");
            val =  strtok(0, "");
            if(name && val) {
                AddProperty(val,name);
            }
        }
    }
#endif /* SCOUT */

#undef AddProperty
    
    return arg1;
}

