package com.wizzardo.tools.evaluation;

import com.wizzardo.tools.collections.CollectionTools;
import com.wizzardo.tools.misc.Supplier;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by wizzardo on 22.12.15.
 */
public class Config extends HashMap<String, Object> implements CollectionTools.Closure<Object, ClosureExpression> {
    @Override
    public Object get(Object key) {
        Object value = super.get(key);
        if (value == null) {
            put((String) key, value = new Config());
        }
        return value;
    }

    @Override
    public Object execute(ClosureExpression it) {
        it.get(this);
        return this;
    }

    public Config config(String key) {
        return (Config) get(key);
    }

    public <T> T get(String key, T def) {
        Object value = super.get(key);
        if (value == null)
            return def;

        if (value instanceof Config && ((Config) value).isEmpty() && !(def instanceof Config))
            return def;

        return (T) value;
    }

    public <T> T get(String key, Supplier<T> def) {
        Object value = super.get(key);
        if (value == null)
            return def.supply();

        if (value instanceof Config && ((Config) value).isEmpty() && !(def instanceof Config))
            return def.supply();

        return (T) value;
    }

    public void merge(Map<String, Object> scr) {
        merge(this, scr);
    }

    private void merge(Map into, Map<?, ?> from) {
        for (Map.Entry<?, ?> entry : from.entrySet()) {
            if (entry.getValue() instanceof Map) {
                Object in = into.get(entry.getKey());
                if (in instanceof Map) {
                    merge(((Map) in), ((Map) entry.getValue()));
                } else {
                    into.put(entry.getKey(), entry.getValue());
                }
            } else {
                into.put(entry.getKey(), entry.getValue());
            }
        }
    }
}

@@ -128,16 +128,205 @@
 upplier;
+%0Aimport com.wizzardo.tools.misc.Unchecked;%0Aimport com.wizzardo.tools.reflection.FieldInfo;%0Aimport com.wizzardo.tools.reflection.FieldReflection;%0Aimport com.wizzardo.tools.reflection.Fields;
 %0A%0Aimport
@@ -2149,11 +2149,2564 @@
  %7D%0A    %7D
+%0A%0A    public %3CT%3E T bind(Class%3CT%3E clazz) %7B%0A        Fields%3CFieldInfo%3E fields = new Fields%3CFieldInfo%3E(clazz);%0A        T t = creteInstance(clazz);%0A        for (FieldInfo fieldInfo : fields) %7B%0A            FieldReflection reflection = fieldInfo.reflection;%0A            String name = fieldInfo.field.getName();%0A            switch (reflection.getType()) %7B%0A                case BOOLEAN:%0A                    reflection.setBoolean(t, get(name, Boolean.FALSE));%0A                    break;%0A                case BYTE:%0A                    reflection.setByte(t, get(name, (byte) 0));%0A                    break;%0A                case CHAR:%0A                    reflection.setChar(t, get(name, (char) 0));%0A                    break;%0A                case DOUBLE:%0A                    reflection.setDouble(t, get(name, 0.0));%0A                    break;%0A                case FLOAT:%0A                    reflection.setFloat(t, get(name, 0.0f));%0A                    break;%0A                case INTEGER:%0A                    reflection.setInteger(t, get(name, 0));%0A                    break;%0A                case LONG:%0A                    reflection.setLong(t, get(name, 0l));%0A                    break;%0A                case SHORT:%0A                    reflection.setShort(t, get(name, (short) 0));%0A                    break;%0A                case OBJECT: %7B%0A                    Object o = super.get(name);%0A                    if (o == null) %7B%0A                        reflection.setObject(t, null);%0A                        break;%0A                    %7D%0A%0A                    if (fieldInfo.generic.clazz.isAssignableFrom(o.getClass())) %7B%0A                        reflection.setObject(t, o);%0A                        break;%0A                    %7D%0A%0A                    try %7B%0A                        reflection.setObject(t, ((Config) o).bind(fieldInfo.generic.clazz));%0A                    %7D catch (ClassCastException e) %7B%0A                        throw new IllegalStateException(%22Cannot bind %22 + o.getClass() + %22 to %22 + fieldInfo.field);%0A                    %7D%0A                    break;%0A                %7D%0A                default:%0A                    throw new IllegalStateException(%22Unknown type of field %22 + fieldInfo.field);%0A            %7D%0A        %7D%0A        return t;%0A    %7D%0A%0A    protected %3CT%3E T creteInstance(Class%3CT%3E clazz) %7B%0A        T t;%0A        try %7B%0A            t = clazz.newInstance();%0A        %7D catch (InstantiationException e) %7B%0A            throw Unchecked.rethrow(e);%0A        %7D catch (IllegalAccessException e) %7B%0A            throw Unchecked.rethrow(e);%0A        %7D%0A        return t;%0A    %7D
 %0A%7D%0A

add simple binding