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

package net.ranides.assira.reflection;

/**
 * Model for JavaBean property.
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public interface BeanProperty {

    /**
     * Returns type of object declaring this property
     *
     * @return IClass
     */
    IClass<?> parent();

    /**
     * Property name, derived from getter & setter name, using various JavaBean conventions.
     * @return string
     */
    String name();

    /**
     * Property type, derived from getter & setter signature.
     * @return type
     */
    IClass<?> type();

    /**
     * Creates new wrapper object, which allows you to modify described property in specified object.
     *
     * @param that object
     * @return wrapper
     */
    BeanPropertyBinding<Object> bind(Object that);

    /**
     * Creates new wrapper object, which allows you to modify described property in specified object.
     *
     * Please note, that this version infers type of property in unsafe way.
     * It is responsibility of the caller, to store result in correct variable.
     *
     * @param that object
     * @param <T> inferred type of property
     * @return wrapper
     */
    <T> BeanPropertyBinding<T> $bind(Object that);

    /**
     * Changes property inside specified object. Is uses setter method.
     *
     * @param that object
     * @param value value
     * @throws UnsupportedOperationException for read-only properties
     */
    void set(Object that, Object value);

    /**
     * Reads property from specified object. Is uses getter method.
     *
     * @param that object
     * @return value
     * @throws UnsupportedOperationException for write-only properties
     */
    Object get(Object that);

    /**
     * Reads property from specified object. Is uses getter method.
     *
     * Please note, that this version infers type of property in unsafe way.
     * It is responsibility of the caller, to store result in correct variable.
     *
     * @param that object
     * @param <T> inferred type
     * @return value
     * @throws UnsupportedOperationException for write-only properties
     */
    <T> T $get(Object that);

    /**
     * Changes property inside specified object. Is uses setter method.
     * Returns old value of property. It uses getter method.
     * If property is write-only, it returns null as previous value.
     *
     * @param that object
     * @param value value
     * @return previous value or null
     * @throws UnsupportedOperationException for read-only properties
     */
    Object replace(Object that, Object value);

    /**
     * Returns true if property is readable
     *
     * @return bool
     */
    boolean isReadable();

    /**
     * Returns true if property is writable
     *
     * @return bool
     */
    boolean isWritable();
}
