package estivate.core.ast.parser2;

import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import estivate.core.ClassUtils;
import estivate.core.MembersFinder;
import estivate.core.ast.EstivateAST;
import estivate.core.ast.ExpressionAST;
import estivate.core.ast.FieldExpressionAST;
import estivate.core.ast.ListValuesAST;
import estivate.core.ast.SimpleValueAST;
import estivate.core.impl.DefaultMembersFinder;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class EstivateParser2 {

    protected static List<ClassParser> classParsers = new ArrayList<ClassParser>();
    protected static List<MemberParser> memberParsers = new ArrayList<MemberParser>();
    protected static List<AnnotationParser> annotationParsers = new ArrayList<AnnotationParser>();
    protected static List<TypeParser> typeParsers = new ArrayList<TypeParser>();

    protected static MembersFinder membersFinder = new DefaultMembersFinder();

    public static EstivateAST parse(Class<?> clazz) {
        EstivateAST ast = new EstivateAST();

        for (ClassParser parser : classParsers) {
            parser.parseClass(ast, clazz);
        }

        log.debug("AST of '{}' is {}",clazz.toString(), ast);

        return ast;
    }

    public static ClassParser cParser = new ClassParser() {

        public void parseClass(EstivateAST ast, Class<?> clazz) {

            ast.setTargetType(clazz);
            ast.setTargetRawClass(ClassUtils.rawType(clazz));

            for (AnnotationParser parser : annotationParsers) {
                parser.parseMember(ast, clazz.getAnnotations());
            }
            
            List<AccessibleObject> list = membersFinder.list(clazz);
            for (AccessibleObject member : list) {
                for (MemberParser parser : memberParsers) {
                    parser.parseMember(ast, member);
                }
            }


        }
    };

    public static MemberParser fieldParser = new MemberParser() {

        public void parseMember(EstivateAST ast, AccessibleObject member) {
            if(member instanceof Field){
                Field field = (Field) member;
                
                FieldExpressionAST fieldAST = new FieldExpressionAST();
                
                for (AnnotationParser parser : annotationParsers) {
                    parser.parseMember(fieldAST, field.getAnnotations());
                }
                for (TypeParser parser : typeParsers) {
                    parser.parseType(fieldAST, field.getType());
                }
                
                ast.getExpressions().add(fieldAST);
            }
        }
        
    };
    
    public static TypeParser typeParser = new TypeParser() {

        public void parseType(ExpressionAST ast, Type... types) {
            
            ListValuesAST list = new ListValuesAST();
            
            for (Type type : types) {
                
                SimpleValueAST value = new SimpleValueAST();
                
                value.setType(type);
                value.setRawClass(ClassUtils.rawType(type));
                value.setValueList(value.getRawClass().equals(List.class));
                
                list.getValues().add(value);
                
            }
            
            ast.setValue(list);
            
        }
        
    };
    
    public interface ClassParser {
        public void parseClass(EstivateAST ast, Class<?> clazz);
    }

    public interface MemberParser {
        public void parseMember(EstivateAST ast, AccessibleObject member);
    }

    public interface AnnotationParser {
        public void parseMember(EstivateAST ast, Annotation[] annotations);
        
        public void parseMember(ExpressionAST ast, Annotation[] annotations);
    }
    
    public interface TypeParser {
        public void parseType(ExpressionAST ast, Type...types);
    }

}

@@ -149,16 +149,50 @@
 Field;%0D%0A
+import java.lang.reflect.Method;%0D%0A
 import j
@@ -504,24 +504,71 @@
 ValuesAST;%0D%0A
+import estivate.core.ast.MethodExpressionAST;%0D%0A
 import estiv
@@ -2480,32 +2480,75 @@
 pressionAST();%0D%0A
+                fieldAST.setField(field);%0D%0A
                 
@@ -2967,32 +2967,879 @@
 %0D%0A    %7D;%0D%0A    %0D%0A
+    public static MemberParser methodParser = new MemberParser() %7B%0D%0A        %0D%0A        public void parseMember(EstivateAST ast, AccessibleObject member) %7B%0D%0A            if(member instanceof Method)%7B%0D%0A                Method method = (Method) member;%0D%0A                %0D%0A                MethodExpressionAST methodAST = new MethodExpressionAST();%0D%0A                methodAST.setMethod(method);%0D%0A                %0D%0A                for (AnnotationParser parser : annotationParsers) %7B%0D%0A                    parser.parseMember(methodAST, method.getAnnotations());%0D%0A                %7D%0D%0A                for (TypeParser parser : typeParsers) %7B%0D%0A                    parser.parseType(methodAST, method.getTypeParameters());%0D%0A                %7D%0D%0A                %0D%0A                ast.getExpressions().add(methodAST);%0D%0A            %7D%0D%0A        %7D%0D%0A        %0D%0A    %7D;%0D%0A    %0D%0A
     public stati

add methodParser parser