// Path: annotations/src/main/java/org/leandreck/endpoints/processor/model/typefactories/TypeNodeUtils.java
// public class TypeNodeUtils {
// 
//     static final String NO_TEMPLATE = "NO_TEMPLATE";
//     static final String UNDEFINED_TYPE_NAME = "UNDEFINED";
//     static final String JAVA_LANG_OBJECT = "java.lang.Object";
//     static TypeMirror objectMirror;
// 
//     public static <A extends Annotation> A getAnnotationForClass(final TypeMirror typeMirror, final Class<A> annotation, final Types typeUtils) {
//         final TypeKind kind = typeMirror.getKind();
//         final TypeMirror realMirror;
//         if (TypeKind.ARRAY.equals(kind)) {
//             realMirror = ((ArrayType) typeMirror).getComponentType();
//         } else {
//             realMirror = typeMirror;
//         }
// 
//         final Element definingElement = typeUtils.asElement(realMirror);
//         return (definingElement != null) ? definingElement.getAnnotation(annotation) : null;
//     }
// 
//     static String defineTemplate(final String typeNodeTemplate,
//                                  final TypeScriptType typeScriptTypeAnnotation,
//                                  final Element element) {
// 
//         if (typeNodeTemplate == null || typeNodeTemplate.isEmpty()) {
//             throw new MissingConfigurationTemplateException("TemplateConfiguration is null while processing Element", element);
//         }
// 
//         final String template;
//         if (typeScriptTypeAnnotation == null || typeScriptTypeAnnotation.template().isEmpty()) {
//             template = typeNodeTemplate;
//         } else {
//             template = typeScriptTypeAnnotation.template();
//         }
// 
//         return template;
//     }
// 
//     static String defineName(final TypeMirror typeMirror, final TypeScriptType typeScriptTypeAnnotation, final Function<TypeMirror, String> nameFunction) {
//         //check if has a annotation and a type
//         final String typeFromAnnotation = TypeNodeUtils.defineTypeFromAnnotation(typeScriptTypeAnnotation);
//         if (!UNDEFINED_TYPE_NAME.equals(typeFromAnnotation)) {
//             return typeFromAnnotation;
//         }
//         //forward to furter determination
//         return nameFunction.apply(typeMirror);
//     }
// 
//     static TypeMirror getObjectMirror(final Elements elementUtils) {
//         if (objectMirror == null) {
//             objectMirror = elementUtils.getTypeElement(JAVA_LANG_OBJECT).asType();
//         }
//         return objectMirror;
//     }
// 
//     private static String defineTypeFromAnnotation(final TypeScriptType annotation) {
//         if (annotation != null && !annotation.value().isEmpty()) {
//             return annotation.value();
//         }
//         return UNDEFINED_TYPE_NAME;
//     }
// 
//     /**
//      * No Instances of this utility class.
//      */
//     private TypeNodeUtils() {
//     }
// }
// 
// Path: annotations/src/main/java/org/leandreck/endpoints/processor/model/TypeNode.java
// protected static final String EMPTY_JAVA_DOC = "";


import org.leandreck.endpoints.annotations.TypeScriptIgnore;
import org.leandreck.endpoints.processor.config.TemplateConfiguration;
import org.leandreck.endpoints.processor.model.typefactories.ConcreteTypeNodeFactory;
import org.leandreck.endpoints.processor.model.typefactories.TypeNodeKind;
import org.leandreck.endpoints.processor.model.typefactories.TypeNodeUtils;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import static java.util.stream.Collectors.toList;
import static org.leandreck.endpoints.processor.model.TypeNode.EMPTY_JAVA_DOC;
import static org.leandreck.endpoints.processor.model.typefactories.TypeNodeKind.OPTIONAL;
        final Map<TypeNodeKind, ConcreteTypeNodeFactory> tmpFactories = new EnumMap<>(TypeNodeKind.class);
        Arrays.stream(TypeNodeKind.values()).forEach(it -> {
            try {
                tmpFactories.put(it, it.getTypeNodeFactory().newConfiguredInstance(this, this.configuration, this.typeUtils, this.elementUtils));
            } catch (final Exception e) {
                throw new InitTypeNodeFactoriesException(e);
            }
        });
        return tmpFactories;
    }

    /**
     * Factory Method to create new Root-TypeNodes like Returnvalues of Methods.
     *
     * @param typeMirror {@link TypeMirror} of Returnvalue or Parameter.
     * @return created {@link TypeNode} from given typeMirror
     */
    public TypeNode createTypeNode(final TypeMirror typeMirror) {
        return createTypeNode(typeMirror, null);
    }

    /**
     * Factory Method to create new Root-TypeNodes like Generics.
     *
     * @param typeMirror {@link TypeMirror} of TypeVariable.
     * @param containingType {@link TypeMirror} of the Type containing this {@link TypeNode}
     * @return created {@link TypeNode} from given typeMirror
     */
    public TypeNode createTypeNode(final TypeMirror typeMirror, final DeclaredType containingType) {
        final String fieldName = "TYPE-ROOT";
// Path: annotations/src/main/java/org/leandreck/endpoints/processor/model/typefactories/TypeNodeUtils.java
// public class TypeNodeUtils {
// 
//     static final String NO_TEMPLATE = "NO_TEMPLATE";
//     static final String UNDEFINED_TYPE_NAME = "UNDEFINED";
//     static final String JAVA_LANG_OBJECT = "java.lang.Object";
//     static TypeMirror objectMirror;
// 
//     public static <A extends Annotation> A getAnnotationForClass(final TypeMirror typeMirror, final Class<A> annotation, final Types typeUtils) {
//         final TypeKind kind = typeMirror.getKind();
//         final TypeMirror realMirror;
//         if (TypeKind.ARRAY.equals(kind)) {
//             realMirror = ((ArrayType) typeMirror).getComponentType();
//         } else {
//             realMirror = typeMirror;
//         }
// 
//         final Element definingElement = typeUtils.asElement(realMirror);
//         return (definingElement != null) ? definingElement.getAnnotation(annotation) : null;
//     }
// 
//     static String defineTemplate(final String typeNodeTemplate,
//                                  final TypeScriptType typeScriptTypeAnnotation,
//                                  final Element element) {
// 
//         if (typeNodeTemplate == null || typeNodeTemplate.isEmpty()) {
//             throw new MissingConfigurationTemplateException("TemplateConfiguration is null while processing Element", element);
//         }
// 
//         final String template;
//         if (typeScriptTypeAnnotation == null || typeScriptTypeAnnotation.template().isEmpty()) {
//             template = typeNodeTemplate;
//         } else {
//             template = typeScriptTypeAnnotation.template();
//         }
// 
//         return template;
//     }
// 
//     static String defineName(final TypeMirror typeMirror, final TypeScriptType typeScriptTypeAnnotation, final Function<TypeMirror, String> nameFunction) {
//         //check if has a annotation and a type
//         final String typeFromAnnotation = TypeNodeUtils.defineTypeFromAnnotation(typeScriptTypeAnnotation);
//         if (!UNDEFINED_TYPE_NAME.equals(typeFromAnnotation)) {
//             return typeFromAnnotation;
//         }
//         //forward to furter determination
//         return nameFunction.apply(typeMirror);
//     }
// 
//     static TypeMirror getObjectMirror(final Elements elementUtils) {
//         if (objectMirror == null) {
//             objectMirror = elementUtils.getTypeElement(JAVA_LANG_OBJECT).asType();
//         }
//         return objectMirror;
//     }
// 
//     private static String defineTypeFromAnnotation(final TypeScriptType annotation) {
//         if (annotation != null && !annotation.value().isEmpty()) {
//             return annotation.value();
//         }
//         return UNDEFINED_TYPE_NAME;
//     }
// 
//     /**
//      * No Instances of this utility class.
//      */
//     private TypeNodeUtils() {
//     }
// }
// 
// Path: annotations/src/main/java/org/leandreck/endpoints/processor/model/TypeNode.java
// protected static final String EMPTY_JAVA_DOC = "";


// Path: annotations/src/main/java/org/leandreck/endpoints/processor/model/TypeNodeFactory.java
import org.leandreck.endpoints.annotations.TypeScriptIgnore;
import org.leandreck.endpoints.processor.config.TemplateConfiguration;
import org.leandreck.endpoints.processor.model.typefactories.ConcreteTypeNodeFactory;
import org.leandreck.endpoints.processor.model.typefactories.TypeNodeKind;
import org.leandreck.endpoints.processor.model.typefactories.TypeNodeUtils;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import static java.util.stream.Collectors.toList;
import static org.leandreck.endpoints.processor.model.TypeNode.EMPTY_JAVA_DOC;
import static org.leandreck.endpoints.processor.model.typefactories.TypeNodeKind.OPTIONAL;

        final Map<TypeNodeKind, ConcreteTypeNodeFactory> tmpFactories = new EnumMap<>(TypeNodeKind.class);
        Arrays.stream(TypeNodeKind.values()).forEach(it -> {
            try {
                tmpFactories.put(it, it.getTypeNodeFactory().newConfiguredInstance(this, this.configuration, this.typeUtils, this.elementUtils));
            } catch (final Exception e) {
                throw new InitTypeNodeFactoriesException(e);
            }
        });
        return tmpFactories;
    }

    /**
     * Factory Method to create new Root-TypeNodes like Returnvalues of Methods.
     *
     * @param typeMirror {@link TypeMirror} of Returnvalue or Parameter.
     * @return created {@link TypeNode} from given typeMirror
     */
    public TypeNode createTypeNode(final TypeMirror typeMirror) {
        return createTypeNode(typeMirror, null);
    }

    /**
     * Factory Method to create new Root-TypeNodes like Generics.
     *
     * @param typeMirror {@link TypeMirror} of TypeVariable.
     * @param containingType {@link TypeMirror} of the Type containing this {@link TypeNode}
     * @return created {@link TypeNode} from given typeMirror
     */
    public TypeNode createTypeNode(final TypeMirror typeMirror, final DeclaredType containingType) {
        final String fieldName = "TYPE-ROOT";
        final String doc = EMPTY_JAVA_DOC + "FIXME: createTypeNode(final TypeMirror typeMirror, final DeclaredType containingType)";