/*
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.reflection;

import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;

import net.ranides.assira.annotations.Meta;
import net.ranides.assira.generic.Wrapper;
import net.ranides.assira.reflection.impl.FField;

/**
 * This class represents field declared by class.
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public interface IField extends IElement {

    /**
     * Factory: creates IMethod from java.reflection field
     *
     * @param field field
     * @return IField
     */
    static IField typeinfo(Field field) {
        return FField.newField(IContext.getDefault(), field);
    }
    
    @Override
    IFields collect();

    /**
     * Returns declared field type
     *
     * @return IClass
     */
    IClass<?> type();

    /**
     * Returns declaring class
     *
     * @return IClass
     */
    @Override
    IClass<?> parent();

    /**
     * Assumes that object contains this non-static field and reads it
     *
     * Throws IReflectiveException if field does not exist
     *
     * @param that that
     * @return Object
     */
    Object get(Object that);

    /**
     * Assumes that field is static and reads its value
     *
     * Throws IReflectiveException if field does not exist
     *
     * @return Object
     */
    Object getStatic();

    /**
     * Assumes that object contains this non-static field and modifies it
     *
     * Throws IReflectiveException if field does not exist
     *
     * @param that that
     * @param value value
     */
    void set(Object that, Object value);

    /**
     * Assumes that object contains this non-static field and modifies it
     * Returns previously assigned value.
     *
     * Throws IReflectiveException if field does not exist
     *
     * @param that that
     * @param value value
     * @return Object
     */
    Object replace(Object that, Object value);

    /**
     * Assumes that object contains this non-static field and creates Wrapper for it
     * Returned wrapper supports read and write operations.
     *
     * @param that that
     * @return Wrapper
     */
    Wrapper<Object> bind(Object that);

    /**
     * Returns reflective Field assocciated with this IMethod.
     *
     * @return Field
     */
    Field reflective();

    /**
     * Makes this IField writable.
     * It can throw exception, if it is not allowed because of SecurityException.
     *
     * Please note, that bypassing "final" modifier is undefined behaviour.
     *
     * @return this
     */
    @Meta.UnstableAPI
    IField rewritable();

    /**
     * Forces reflective access if field is non-public.
     * It can throw exception, if it is not allowed because of SecurityException.
     *
     * @return this
     */
    IField accessible();

    boolean isAccessible();

    /**
     * Returns MethodHandle for read operation.
     *
     * Returned MethodHandle is unbinded and takes one argument: "this"
     *
     * @return MethodHandle
     */
    MethodHandle getter();

    /**
     * Returns MethodHandle for write operation.
     *
     * Returned MethodHandle is unbinded and takes two arguments: "this" and "value"
     *
     * @return MethodHandle
     */
    MethodHandle setter();

    /**
     * Alias for {@code attribute(IAttribute.VOLATILE)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(VOLATILE)")
    boolean isVolatile();

    /**
     * Alias for {@code attribute(IAttribute.TRANSIENT)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(TRANSIENT)")
    boolean isTransient();

}
