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

import java.io.Serializable;
import net.ranides.assira.reflection.IClass;

public interface Wrapper<T> {

    static <Q> Wrapper<Q> wrap(Q value) {
        class CWrapper<Q> implements Wrapper<Q>, Serializable {

            private static final long serialVersionUID = 3L;

            private Q value;

            public CWrapper(Q value) {
                this.value = value;
            }

            @Override
            public Q get() {
                return value;
            }

            @Override
            public void set(Q value) {
                this.value = value;
            }

            @Override
            public IClass<?> type() {
                return IClass.typefor(value);
            }

        }
        
        return new CWrapper<>(value);
    }

    T get();

    void set(T value);
    
    default T replace(T value) {
        T prv = get();
        set(value);
        return prv;
    }
    
    IClass<?> type();
    
    @SuppressWarnings("unchecked")
    default <R> Wrapper<R> cast(Class<R> type) {
        if( !type().isEquivalent(IClass.typeinfo(type))) {
            throw new ClassCastException(type() + " can not be cast to " + type);
        }
        return (Wrapper)this;
    }
    
    @SuppressWarnings("unchecked")
    default <R> Wrapper<R> cast(TypeToken<R> type) {
        if( !type().isEquivalent(type)) {
            throw new ClassCastException(type() + " can not be cast to " + type);
        }
        return (Wrapper)this;
    }

}
