
package de.javanarior.vo;

import static de.javanarior.vo.types.AbstractValue.assertNotNull;
import de.javanarior.utils.lang.reflect.Invoker;
import de.javanarior.vo.generator.TypeGenerator;
import de.javanarior.vo.types.DoubleWrapper;
import de.javanarior.vo.types.Value;

/**
 * Factory to create Double based Value Objects.
 */
public final class TypeDouble {

    @SuppressWarnings("rawtypes")
    private static final Class<DoubleWrapper> WRAPPER_CLASS = DoubleWrapper.class;
    private static final Class<Double> TECHNICAL_TYPE = Double.TYPE;

    private TypeDouble() {
        /* Factory Class */
    }

    /**
     * Create value object with {@code type} and {@code value}.
     *
     * @param <V>
     *            - the value type
     * @param type
     *            - object type
     * @param value
     *            - value for the object
     * @return value object
     */
    public static <V extends Value<V, Double>> V create(Class<V> type, Double value) {
        Class<V> generated = TypeGenerator.generate(type, TECHNICAL_TYPE, WRAPPER_CLASS);
        return invokeConstructor(generated, assertNotNull(value));
    }

    /**
     * Create value object with {@code type} and {@code value}.
     *
     * @param <V>
     *            - the value type
     * @param type
     *            - object type
     * @param value
     *            - value for the object
     * @return value object
     */
    public static <V extends Value<V, Double>> V create(Class<V> type, double value) {
        return create(type, Double.valueOf(value));
    }

    /**
     * Create value object with {@code type} and {@code value}.
     *
     * @param <V>
     *            - the value type
     * @param type
     *            - object type
     * @param value
     *            - value for the object
     * @return value object
     */
    public static <V extends Value<V, Double>> V create(Class<V> type, String value) {
        return create(type, Double.valueOf(assertNotNull(value)));
    }

    private static <V extends Value<V, Double>> V invokeConstructor(Class<V> objectClass, Double value) {
        return Invoker.invokeConstructor(objectClass, value);
    }

}
