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

import java.io.Serializable;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.Map;
import net.ranides.assira.collection.maps.ArrayMap;
import net.ranides.assira.collection.maps.OpenMap;
import net.ranides.assira.collection.maps.MapUtils;
import net.ranides.assira.reflection.IClass;

/**
 * IContext implementation which stores explicitly generic params used by "derived" class
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public class GContext extends AContext implements Serializable {

    private static final long serialVersionUID = 1L;
    
    private final Class<?> derived;
    private final Map<String, IClass<?>> params;

    GContext(Class<?> type, IClass<?>[] params) {
        this.derived = type;
        this.params = new ArrayMap<>(names(type.getTypeParameters()), params);
    }

    @Override
    public boolean derived(Type type) {
        return derived.equals(type);
    }
    
    private static String[] names(TypeVariable<?>[] types) {
        return Arrays.stream(types).map(a -> a.getName()).toArray(String[]::new);
    }

    @Override
    protected IClass<?> resolveNS(String type) {
        IClass<?> ic = params.get(type);
        return ic!=null ? ic : super.typeinfo(type);
    }

    @Override
    protected IClass<?> resolveTV(TypeVariable type) {
        IClass<?> ic = params.get(type.getName());
        return ic!=null ? ic : super.typeinfo(type);
    }

    @Override
    public Map<String, Type> map() {
        OpenMap<String, Type> map = new OpenMap<>();
        map.putAll(MapUtils.valueAdapter(params, c -> c.reflective()));
        map.putAll(super.map());
        return map;
    }

}
