/**
 * Describes and handles the value of a field of a Clazz.
 * <p>
 * A model used for a field value may be different from that used
 * for the owner of the field.  For instance, the owner may be
 * a DynaBean while the field is a Map.
 */
public abstract class Field
{
    /**
     * Returns field name
     */
    public String getName(){
    }

    /**
     * Type-based clazz of the field in the specified model
     */
    public abstract Clazz getClazz(String modelURI);

    /**
     * Type-based clazz of the field in the default model
     */
    public abstract Clazz getClazz();

    /**
     * Instance-based clazz of the field in the specified model
     */
    public abstract Clazz getInstanceClazz(Object instance, String modelURI);

    /**
     * Instance-based clazz of the field in the default model
     */
    public abstract Clazz getInstanceClazz(Object instance);

    /**
     * Treating this Field as a collection, returns the type-based
     * clazz for the element
     */
    public abstract Clazz getIndexedElementClazz(String modelURI);

    public abstract Clazz getIndexedElementClazz();

    /**
     * Treating this Field as a collection, returns the instance-based
     * clazz for the element
     */
    public abstract Clazz getIndexedElementInstanceClazz(Object instance, int index, String modelURI);

    public abstract Clazz getIndexedElementInstanceClazz(Object instance, int index);

    /**
     * Treating this Field as a Map, returns the type-based
     * clazz for the element
     */
    public abstract Clazz getMappedElementClazz(String modelURI);

    public abstract Clazz getMappedElementClazz();

    /**
     * Treating this Field as a Map, returns the instance-based
     * clazz for the element
     */
    public abstract Clazz getMappedElementInstanceClazz(Object instance, Object key, String modelURI);

    public abstract Clazz getMappedElementInstanceClazz(Object instance, Object key);

    /**
     * Returns attributes for this Field
     */
    public abstract Attribute[] getAttributes();



    // **********************************************************************
    // Methods for field value handling

    /**
     * Returns the value of the field
     */
    public abstract Object get(Object instance);

    /**
     * Returns the number of elements of this field if the field is
     * a collection, otherwise returns 1.
     */
    public abstract int getSize(Object instance);

    /**
     * Returns the value of the index'th element of the field.
     * If the field is not a collection and index == 0, returns the
     * field value.
     * Otherwise if the field is not a collection, throws an exception
     */
    public abstract Object get(Object instance, int index);

    /**
     * Returns all keys for a mapped field.  If this is not a mapped
     * field, throws an exception.
     */
    public abstract Object[] getKeys(Object instance);

    /**
     * Returns the value of the element of the field for the supplied key.
     * If the field is not mapped, throws an exception
     */
    public abstract Object get(Object instance, Object key);

    /**
     * Changes the field value of the field
     */
    public abstract void set(Object instance, Object value);

    /**
     * Creates a new value using the specified Clazz and assigns it to
     * the field.
     */
    public abstract Object setNew(Object instance, Clazz clazz, Object[] parameters);


    /**
     * Changes the value of the index'th element of the field
     */
    public abstract void set(Object instance, int index, Object value);

    /**
     * Creates a new value using the specified Clazz and assigns it to
     * the index'th element of the field
     */
    public abstract Object setNew(Object instance, int index, Object[] parameters);

    /**
     * Inserts the value in the field's collection. If the field is
     * not a collection, throws an exception.
     */
    public abstract Object add(Object instance, int index, Object value);

    /**
     * Creates a new value and inserts it in the field's collection.
     * If the field is not a collection, throws an exception.
     */
    public abstract Object addNew(Object instance, int index,
                Clazz clazz, Object[] parameters);

    /**
     * Removes the index'th element of the collection
     */
    public abstract void remove(Object instance, int index);

    /**
     * Changes the value of an element of this mapped field.
     * If the field is not mapped, throws an exception.
     */
    public abstract void set(Object instance, Object key, Object value);

    /**
     * Creates a new value and assigns it to an element of this mapped field.
     * If the field is not mapped, throws an exception.
     */
    public abstract Object setNew(Object instance, Object key, Clazz clazz, Object[] parameters);
}