package net.folab.fo.bytecode;

import java.util.ArrayList;
import java.util.List;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class ClassGenerator {

    private JavaVersion javaVersion = JavaVersion.V1_5;

    private AccessModifier accessModifier = AccessModifier.PUBLIC;

    private String name;

    private JavaType superClass = new JavaType("java/lang/Object");

    private JavaType[] interfaces = new JavaType[0];

    private List<MethodGenerator> methodGenerators = new ArrayList<MethodGenerator>();

    public byte[] generateBytecode() {

        ClassWriter cw = new ClassWriter(false);

        String[] interfaces = new String[this.interfaces.length];
        for (int i = 0; i < interfaces.length; i++) {
            interfaces[i] = this.interfaces[i].getName();
        }

        cw.visit(javaVersion.version, // version
                accessModifier.modifier, // access
                name, // name
                null, // signature
                superClass.getName(), // superName
                interfaces // interfaces
        );

        {
            MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V",
                    null, null);
            mv.visitCode();

            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>",
                    "()V");

            mv.visitInsn(Opcodes.RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }

        for (MethodGenerator mg : methodGenerators) {
            mg.generate(cw);
        }

        cw.visitEnd();

        return cw.toByteArray();

    }

    public JavaVersion getJavaVersion() {
        return javaVersion;
    }

    public ClassGenerator setJavaVersion(JavaVersion javaVersion) {
        this.javaVersion = javaVersion;
        return this;
    }

    public AccessModifier getAccessModifier() {
        return accessModifier;
    }

    public ClassGenerator setAccessModifier(AccessModifier accessModifier) {
        this.accessModifier = accessModifier;
        return this;
    }

    public String getName() {
        return name;
    }

    public ClassGenerator setName(String name) {
        this.name = name.replaceAll("\\.", "/");
        return this;
    }

    public JavaType getSuperClass() {
        return superClass;
    }

    public ClassGenerator setSuperClass(JavaType superClass) {
        this.superClass = superClass;
        return this;
    }

    public JavaType[] getInterfaces() {
        return interfaces;
    }

    public ClassGenerator setInterfaces(JavaType... interfaces) {
        this.interfaces = interfaces;
        return this;
    }

    public MethodGenerator addMethod() {
        MethodGenerator mg = new MethodGenerator(this);
        methodGenerators.add(mg);
        return mg;
    }

}

@@ -88,78 +88,119 @@
 ort 
-org.objectweb.asm.ClassWriter;%0Aimport org.objectweb.asm.MethodVisitor;
+net.folab.fo.ast.ConstructorInvocation;%0Aimport net.folab.fo.ast.LocalVariable;%0Aimport net.folab.fo.ast.Return;%0A
 %0Aimp
@@ -221,23 +221,27 @@
 web.asm.
-Opcodes
+ClassWriter
 ;%0A%0Apubli
@@ -1188,255 +1188,333 @@
     
-%7B%0A            MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, %22%3Cinit%3E%22, %22()V%22,%0A                    null, null);%0A            mv.visitCode();%0A%0A            mv.visitVarInsn(Opcodes.ALOAD, 0);%0A            mv.visitMethodInsn(Opcodes.INVOKESPECIAL,
+// TODO detect constructor of super class%0A        new MethodGenerator(this) //%0A                .setName(%22%3Cinit%3E%22) //%0A                .setParameterTypes() //%0A                .setReturnType(JavaType.VOID) //%0A                .addStatement( //%0A                        new ConstructorInvocation( //%0A                               
  %22ja
@@ -1534,18 +1534,22 @@
 t%22, 
-%22%3Cinit%3E%22,%0A
+//%0A           
     
@@ -1568,16 +1568,18 @@
     
+ 
 %22()V%22
-);%0A
+, //
 %0A   
@@ -1591,106 +1591,183 @@
     
-mv.visitInsn(Opcodes.RETURN);%0A            mv.visitMaxs(1, 1);%0A            mv.visitEnd();%0A        %7D
+                    new LocalVariable(%22this%22) //%0A                        ) //%0A                ) //%0A                .addStatement(Return.VOID) //%0A                .generate(cw);
 %0A%0A  

Replace default constructor generation code