package me.hfox.morphix;

import me.hfox.morphix.cache.EntityCache;
import me.hfox.morphix.cache.EntityCacheImpl;
import me.hfox.morphix.exception.MorphixException;
import me.hfox.morphix.helper.entity.DefaultEntityHelper;
import me.hfox.morphix.helper.entity.EntityHelper;
import me.hfox.morphix.helper.name.NameHelper;
import me.hfox.morphix.helper.polymorphism.DefaultPolymorhpismHelper;
import me.hfox.morphix.helper.polymorphism.PolymorhpismHelper;
import me.hfox.morphix.mapping.ObjectMapper;
import me.hfox.morphix.mapping.ObjectMapperImpl;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class Morphix {

    private MorphixOptions options;
    private ObjectMapper mapper;
    private Map<String, EntityCache> caches;

    private EntityHelper entityHelper;
    private Map<Class<? extends NameHelper>, NameHelper> nameHelpers;
    private PolymorhpismHelper polymorhpismHelper;

    public Morphix() {
        this(null, null);
    }

    public Morphix(MorphixOptions options) {
        this(options, null);
    }

    public Morphix(ObjectMapper mapper) {
        this(null, mapper);
    }

    public Morphix(MorphixOptions options, ObjectMapper mapper) {
        this.options = (options == null ? MorphixOptions.builder().build() : options);
        this.mapper = (mapper == null ? new ObjectMapperImpl() : mapper);
        this.caches = new HashMap<>();

        this.entityHelper = new DefaultEntityHelper(this);
        this.nameHelpers = new HashMap<>();
        getNameHelper(MorphixDefaults.DEFAULT_NAME_HELPER);

        this.polymorhpismHelper = new DefaultPolymorhpismHelper();
    }

    public MorphixOptions getOptions() {
        return options;
    }

    public ObjectMapper getMapper() {
        return mapper;
    }

    public Map<String, EntityCache> getCaches() {
        return caches;
    }

    public EntityCache getCache() {
        return getCache(MorphixDefaults.DEFAULT_CACHE_NAME);
    }

    public EntityCache getCache(String name) {
        EntityCache cache = caches.get(name);
        if (cache == null) {
            cache = new EntityCacheImpl(this);
            caches.put(name, cache);
        }

        return cache;
    }

    public boolean hasCache(String name) {
        return caches.get(name) != null;
    }

    public void setCache(String name, EntityCache cache) {
        caches.put(name, cache);
    }

    public EntityHelper getEntityHelper() {
        return entityHelper;
    }

    public void setEntityHelper(EntityHelper entityHelper) {
        this.entityHelper = entityHelper;
    }

    public Map<Class<? extends NameHelper>, NameHelper> getNameHelpers() {
        return nameHelpers;
    }

    public NameHelper getNameHelper(Class<? extends NameHelper> clazz) {
        NameHelper helper = nameHelpers.get(clazz);
        if (helper == null) {
            helper = createNameHelper(clazz);
            nameHelpers.put(clazz, helper);
        }

        return helper;
    }

    public NameHelper createNameHelper(Class<? extends NameHelper> clazz) {
        try {
            Constructor<? extends NameHelper> constructor = clazz.getConstructor(Morphix.class);
            return constructor.newInstance(this);
        } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ex) {
            throw new MorphixException(ex);
        }
    }

    public PolymorhpismHelper getPolymorhpismHelper() {
        return polymorhpismHelper;
    }

    public void setPolymorhpismHelper(PolymorhpismHelper polymorhpismHelper) {
        this.polymorhpismHelper = polymorhpismHelper;
    }

}

@@ -19,16 +19,64 @@
 rphix;%0A%0A
+import me.hfox.morphix.annotation.entity.Cache;%0A
 import m
@@ -588,16 +588,61 @@
 perImpl;
+%0Aimport me.hfox.morphix.util.AnnotationUtils;
 %0A%0Aimport
@@ -2109,32 +2109,349 @@
 E_NAME);%0A    %7D%0A%0A
+    public EntityCache getCache(Class%3C?%3E cls) %7B%0A        Cache cache = AnnotationUtils.getHierarchicalAnnotation(cls, Cache.class);%0A        if (cache == null) %7B%0A            return getCache();%0A        %7D%0A%0A        if (!cache.enabled()) %7B%0A            return null;%0A        %7D%0A%0A        return getCache(cache.value());%0A    %7D%0A%0A
     public Entit

Map the correct Cache to the Entity