package com.artemis.meta;


import static com.artemis.Weaver.PACKED_ANNOTATION;
import static com.artemis.Weaver.POOLED_ANNOTATION;
import static com.artemis.Weaver.PROFILER_ANNOTATION;
import static com.artemis.Weaver.WOVEN_ANNOTATION;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import com.artemis.Weaver;
import com.artemis.meta.ClassMetadata.OptimizationType;
import com.artemis.meta.ClassMetadata.WeaverType;

public class MetaScanner extends ClassVisitor implements Opcodes {
	
	private static final class AnnotationReader extends AnnotationVisitor {
		
		private ClassMetadata info;

		private AnnotationReader(AnnotationVisitor av, ClassMetadata meta) {
			super(ASM4, av);
			this.info = meta;
		}

		@Override
		public void visit(String name, Object value) {
			if ("forceWeaving".equals(name)) {
				info.forcePooledWeaving = (Boolean)value;
			}
			super.visit(name, value);
		}
	}

	private ClassMetadata info;

	public MetaScanner(ClassMetadata metadata) {
		super(ASM4);
		info = metadata;
	}

	@Override
	public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
		info.superClass = superName;
		if (superName.equals("com/artemis/systems/EntityProcessingSystem"))
			info.sysetemOptimizable =  OptimizationType.FULL;
		
		super.visit(version, access, name, signature, superName, interfaces);
	}
	
	@Override
	public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
		AnnotationVisitor av = super.visitAnnotation(desc, visible);
		
		if (PACKED_ANNOTATION.equals(desc)) {
			info.annotation = WeaverType.PACKED;
		} else if (POOLED_ANNOTATION.equals(desc)) {
			info.annotation = WeaverType.POOLED;
			av = new AnnotationReader(av, info);
		} else if (PROFILER_ANNOTATION.equals(desc)) {
			return new ProfileAnnotationReader(desc, info);
		} else if (WOVEN_ANNOTATION.equals(desc)) {
			info.isPreviouslyProcessed = true;
		} else if (info.sysetemOptimizable == OptimizationType.FULL
				&& Weaver.PRESERVE_VISIBILITY_ANNOTATION.equals(desc)) {
			
			info.sysetemOptimizable = OptimizationType.SAFE;
		}
		
		return av;
	}
	
	@Override
	public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
		info.fields.add(new FieldDescriptor(access, name, desc, signature, value));
		return super.visitField(access, name, desc, signature, value);
	}
	
	@Override
	public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
		if ("reset".equals(name) && "()V".equals(desc))
			info.foundReset = true;
		else if ("forEntity".equals(name) && desc.startsWith("(Lcom/artemis/Entity;)"))
			info.foundEntityFor = true;
		else if ("begin".equals(name) && "()V".equals(desc))
			info.foundBegin = true;
		else if ("end".equals(name) && desc.equals("()V"))
			info.foundEnd = true;
		else if ("initialize".equals(name) && "()V".equals(desc))
			info.foundInitialize = true;
		else if ("<clinit>".equals(name) && "()V".equals(desc))
			info.foundStaticInitializer = true;
		
		info.methods.add(new MethodDescriptor(access, name, desc, signature, exceptions));
		
		return super.visitMethod(access, name, desc, signature, exceptions);
	}
}
@@ -2788,28 +2788,9 @@
 h(%22(
-Lcom/artemis/Entity;
+I
 )%22))

Fix metascanner.