/* -*- Mode: C; c-file-style: "gnu" -*- */
/*
 * This file contains the code necessary to fake out the rest
 * of the runtime into thinking that we actually do have array
 * classes.
 */
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1997, 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 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
  Library General Public License for more details.

  You should have received a copy of the GNU Library 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
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "alloc.h"
#include "jni.h"
#include "ClazzFile.h"
#include "log.h"
#include "resolve.h"
#include "arrays.h"
#include "array-class.h"
#include "class-repository.h"
#include "objects.h"

#include <string.h>
#include <stdlib.h>

#define MYLOG "ArrayClass"

static ClassConstant superclass_constant = {
  CONSTANT_Class,
  2
};

static Utf8Constant object_name_constant = {
  CONSTANT_Utf8,
  16, /* strlen("java/lang/Object") */
  NULL
};

ClazzFile*
createFakeArrayClass(JNIEnv *env, char *class_name)
{
  ClazzFile *clazz = find_class_in_repository(env, class_name);

  /* we've already created it. */
  if (clazz)
    return clazz;

  JAVARLOG1(MYLOG, 1, "creating array class %s\n",
	    class_name);

  clazz = (ClazzFile*)jcalloc(env, 1, sizeof(ClazzFile));
  if (NULL == clazz)
    return NULL;

  clazz->access_flags = ACC_ARRAY | ACC_PUBLIC;
  clazz->constant_pool_count = 4;
  clazz->superclass_index = 1;
  clazz->superclass = (ClazzFile*)find_class(env, "java/lang/Object");
  clazz->class_name = jstrdup(env, class_name);
  if (NULL == clazz->class_name)
    {
      jfree(env, clazz);
      return NULL;
    }

  clazz->initialization_state = CLASS_INIT_FINISHED;

  clazz->constants = (ConstantPoolEntry*)jcalloc(env, 3,
						 sizeof(ConstantPoolEntry));
  if (NULL == clazz->constants)
    {
      jfree(env, clazz->class_name);
      jfree(env, clazz);
      return NULL;
    }

  clazz->constants[1].clazz_info = superclass_constant;
  clazz->constants[2].utf8_info = object_name_constant;
  clazz->constants[2].utf8_info.bytes = (u1*)jstrdup(env, "java/lang/Object");
  if (NULL == clazz->constants[2].utf8_info.bytes)
    {
      jfree(env, clazz->constants);
      jfree(env, clazz->class_name);
      jfree(env, clazz);
      return NULL;
    }

  clazz->num_fields = 4;
  clazz->num_instance_fields = 4;

  clazz->fields = (FieldStruct**)jcalloc(env, clazz->num_fields,
					 sizeof(FieldStruct*));

  clazz->field_pool = (FieldStruct*)calloc(clazz->num_fields,
					   sizeof(FieldStruct));

  if (NULL == clazz->fields
      || NULL == clazz->field_pool)
    {
      jfree(env, clazz->constants[2].utf8_info.bytes);
      jfree(env, clazz->constants);
      jfree(env, clazz->class_name);
      jfree(env, clazz);
      if (clazz->fields)
	free (clazz->fields);
      if (clazz->field_pool)
	free (clazz->field_pool);
      return NULL;
    }

  clazz->fields[ ARRAY_LENGTH_INDEX ] = &clazz->field_pool[ARRAY_LENGTH_INDEX ];
  clazz->fields[ ARRAY_LENGTH_INDEX ]->clazz = clazz;
  clazz->fields[ ARRAY_LENGTH_INDEX ]->name = "length";
  clazz->fields[ ARRAY_LENGTH_INDEX ]->sig_str = "I";
  clazz->fields[ ARRAY_LENGTH_INDEX ]->access_flags = ACC_PUBLIC;
  clazz->fields[ ARRAY_LENGTH_INDEX ]->java_type = SIG_JINT;
  clazz->fields[ ARRAY_LENGTH_INDEX ]->field_offset = VALUE_UNRESOLVED;

  clazz->fields[ ARRAY_TYPE_INDEX ] = &clazz->field_pool[ ARRAY_TYPE_INDEX ];
  clazz->fields[ ARRAY_TYPE_INDEX ]->clazz = clazz;
  clazz->fields[ ARRAY_TYPE_INDEX ]->name = "type";
  clazz->fields[ ARRAY_TYPE_INDEX ]->sig_str = "I";
  clazz->fields[ ARRAY_TYPE_INDEX ]->access_flags = ACC_PUBLIC;
  clazz->fields[ ARRAY_TYPE_INDEX ]->java_type = SIG_JINT;
  clazz->fields[ ARRAY_TYPE_INDEX ]->field_offset = VALUE_UNRESOLVED;

  clazz->fields[ ARRAY_BODY_INDEX ] = &clazz->field_pool[ ARRAY_BODY_INDEX ];
  clazz->fields[ ARRAY_BODY_INDEX ]->clazz = clazz;
  clazz->fields[ ARRAY_BODY_INDEX ]->name = "body";
  clazz->fields[ ARRAY_BODY_INDEX ]->sig_str = "I";
  clazz->fields[ ARRAY_BODY_INDEX ]->access_flags = ACC_PUBLIC;
  /** XXX can't make it SIG_JOBJECT or the garbage collector
      will try to traverse to it... badness. */
  clazz->fields[ ARRAY_BODY_INDEX ]->java_type = SIG_JINT; 
  clazz->fields[ ARRAY_BODY_INDEX ]->field_offset = VALUE_UNRESOLVED;

  clazz->fields[ ARRAY_ELSIZE_INDEX ] = &clazz->field_pool[ ARRAY_ELSIZE_INDEX ];
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->clazz = clazz;
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->name = "elsize";
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->sig_str = "I";
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->access_flags = ACC_PUBLIC;
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->java_type = SIG_JINT;
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->field_offset = VALUE_UNRESOLVED;

  JAVARLOG0(MYLOG, 1, "  adding array class to repository\n");

  clazz->nesting_level = 1;

  calculate_instance_field_offsets(env, clazz);

  add_class_to_repository(env, clazz, class_name);

  return clazz;
}

ClazzFile*
createFakeArrayRemoveDimension(JNIEnv *env, jclass array)
{
  char *arrayclass_name = getClassName(env, (ClazzFile*)array);

  return createFakeArrayClass(env, arrayclass_name + 1);
}
