/* Copyright (C) 1998, 1999  Cygnus Solutions

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */

package java.lang.reflect;

/**
 * @author Per Bothner <bothner@cygnus.com>
 * @date September 1998;  February 1999.
 */
/* Status:  Mostly implemented.
 * However, access checks are not implemented.  See natField.cc for
 * _Jv_CheckFieldAccessibility as well as the missing getCaller.
 * Note that the idea is to have to compiler convert calls to
 * setXXX(...) and getXXX(...) to setXXX(CALLER, ...) and getXXX(CALLER, ...),
 * where CALLER is reference to the class that contains the calls to
 * setXXX or getXXX.  This is easy for the compiler, and replaces
 * expensive stack and table searching with a constant.
 */

public final class Field extends AccessibleObject implements Member
{
  private Class declaringClass;

  // This is filled in by getName.
  private String name;

  // Offset in bytes from the start of declaringClass's fields array.
  private int offset;

  public boolean equals (Object fld)
    {
      if (! (fld instanceof Field))
	return false;
      Field f = (Field) fld;
      return declaringClass == f.declaringClass && offset == f.offset;
    }

  public Class getDeclaringClass ()
  {
    return declaringClass;
  }

  public native String getName ();

  public native Class getType ();

  public native int getModifiers ();

  public int hashCode()
  {
    return (declaringClass.hashCode() ^ offset);
  }

  // The idea is that the compiler will magically translate
  // fld.getShort(obj) to fld.getShort(THISCLASS, obj).
  // This makes checking assessiblity more efficient,
  // since we don't have to do any stack-walking.

  public boolean getBoolean (Object obj)
    throws IllegalArgumentException, IllegalAccessException
  {
    return getBoolean(null, obj);
  }
  public char getChar (Object obj)
    throws IllegalArgumentException, IllegalAccessException
  {
    return getChar(null, obj);
  }

  public byte getByte (Object obj)
    throws IllegalArgumentException, IllegalAccessException
  {
    return getByte(null, obj);
  }

  public short getShort (Object obj)
    throws IllegalArgumentException, IllegalAccessException
  {
    return getShort(null, obj);
  }

  public int getInt (Object obj)
    throws IllegalArgumentException, IllegalAccessException
  {
    return getInt(null, obj);
  }

  public long getLong (Object obj)
    throws IllegalArgumentException, IllegalAccessException
  {
    return getLong(null, obj);
  }

  public float getFloat (Object obj)
    throws IllegalArgumentException, IllegalAccessException
  {
    return getFloat(null, obj);
  }

  public double getDouble (Object obj)
    throws IllegalArgumentException, IllegalAccessException
  {
    return getDouble(null, obj);
  }

  public Object get (Object obj)
    throws IllegalArgumentException, IllegalAccessException
  {
    return get(null, obj);
  }

  private native boolean getBoolean (Class caller, Object obj)
    throws IllegalArgumentException, IllegalAccessException;

  private native char getChar (Class caller, Object obj)
    throws IllegalArgumentException, IllegalAccessException;

  private native byte getByte (Class caller, Object obj)
    throws IllegalArgumentException, IllegalAccessException;

  private native short getShort (Class caller, Object obj)
    throws IllegalArgumentException, IllegalAccessException;

  private native int getInt (Class caller, Object obj)
    throws IllegalArgumentException, IllegalAccessException;

  private native long getLong (Class caller, Object obj)
    throws IllegalArgumentException, IllegalAccessException;

  private native float getFloat (Class caller, Object obj)
    throws IllegalArgumentException, IllegalAccessException;

  private native double getDouble (Class caller, Object obj)
    throws IllegalArgumentException, IllegalAccessException;

  public native Object get (Class caller, Object obj)
    throws IllegalArgumentException, IllegalAccessException;

  public void setByte (Object obj, byte b)
    throws IllegalArgumentException, IllegalAccessException
  {
    setByte(null, obj, b);
  }

  public void setShort (Object obj,  short s)
    throws IllegalArgumentException, IllegalAccessException
  {
    setShort(null, obj, s);
  }

  public void setInt (Object obj, int i)
    throws IllegalArgumentException, IllegalAccessException
  {
    setInt(null, obj, i);
  }

  public void setLong (Object obj, long l)
    throws IllegalArgumentException, IllegalAccessException
  {
    setLong(null, obj, l);
  }

  public void setFloat (Object obj, float f)
    throws IllegalArgumentException, IllegalAccessException
  {
    setFloat(null, obj, f);
  }

  public void setDouble (Object obj, double d)
    throws IllegalArgumentException, IllegalAccessException
  {
    setDouble(null, obj, d);
  }

  public void setChar (Object obj, char c)
    throws IllegalArgumentException, IllegalAccessException
  {
    setChar(null, obj, c);
  }

  public void setBoolean (Object obj, boolean b)
    throws IllegalArgumentException, IllegalAccessException
  {
    setBoolean(null, obj, b);
  }

  public native void setByte (Class caller, Object obj, byte b)
    throws IllegalArgumentException, IllegalAccessException;

  public native void setShort (Class caller, Object obj, short s)
    throws IllegalArgumentException, IllegalAccessException;

  public native void setInt (Class caller, Object obj, int i)
    throws IllegalArgumentException, IllegalAccessException;

  public native void setLong (Class caller, Object obj, long l)
    throws IllegalArgumentException, IllegalAccessException;

  public native void setFloat (Class caller, Object obj, float f)
    throws IllegalArgumentException, IllegalAccessException;

  public native void setDouble (Class caller, Object obj, double d)
    throws IllegalArgumentException, IllegalAccessException;

  public native void setChar (Class caller, Object obj, char c)
    throws IllegalArgumentException, IllegalAccessException;

  public native void setBoolean (Class caller, Object obj, boolean b)
    throws IllegalArgumentException, IllegalAccessException;

  private native void set (Class caller, Object obj, Object val, Class type)
    throws IllegalArgumentException, IllegalAccessException;

  public void set (Object object, Object value)
    throws IllegalArgumentException, IllegalAccessException
  {
    set(null, object, value);
  }

  public void set (Class caller, Object object, Object value)
    throws IllegalArgumentException, IllegalAccessException
  {
    Class type = getType();
    if (! type.isPrimitive())
      set(caller, object, value, type);
    else if (value instanceof Byte)
      setByte(caller, object, ((Byte) value).byteValue());
    else if (value instanceof Short)
      setShort (caller, object, ((Short) value).shortValue());
    else if (value instanceof Integer)
      setInt(caller, object, ((Integer) value).intValue());
    else if (value instanceof Long)
      setLong(caller, object, ((Long) value).longValue());
    else if (value instanceof Float)
      setFloat(caller, object, ((Float) value).floatValue());
    else if (value instanceof Double)
      setDouble(caller, object, ((Double) value).doubleValue());
    else if (value instanceof Character)
      setChar(caller, object, ((Character) value).charValue());
    else if (value instanceof Boolean)
      setBoolean(caller, object, ((Boolean) value).booleanValue());
    else
      throw new IllegalArgumentException();
  }

  public String toString ()
  {
    StringBuffer sbuf = new StringBuffer ();
    int mods = getModifiers();
    if (mods != 0)
      Modifier.toString(mods, sbuf);
    sbuf.append(getType());
    sbuf.append(' ');
    sbuf.append(getDeclaringClass());
    sbuf.append('.');
    sbuf.append(getName());
    return sbuf.toString();
  }
}
