package de.renew.formalism.function;

import java.lang.reflect.Field;

import de.renew.expression.Function;
import de.renew.unify.Impossible;
import de.renew.unify.Tuple;
import de.renew.util.Value;

/**
 * A function that writes a new value to a named field of an object.
 */
public class DynamicFieldWriteFunction implements Function {
    /**
     * The name of the field to be written to on the object.
     */
    private final String _field;

    /**
     * Creates an instance of this class describing a class field by its name that is supposed to be written to using this class.
     *
     * @param field the name of the class field
     */
    public DynamicFieldWriteFunction(String field) {
        this._field = field;
    }

    @Override
    public Object function(Object param) throws Impossible {
        try {
            // param must be a tuple consisting of the object
            // and the new value.
            Tuple tuple = (Tuple) param;
            Object obj = tuple.getComponent(0);
            Object val = tuple.getComponent(1);

            // Unlike in FieldFunction we need not deal with the special
            // field length for arrays, which cannot be assigned.
            Field theField = obj.getClass().getField(_field);

            // Possibly unwrap, then assign.
            theField.set(obj, Value.unvalueAndCast(val, theField.getType()));

            // Return the assigned value.
            return val;
        } catch (Exception e) {
            throw new Impossible("Exception occured during method call: " + e);
        }
    }
}