package test;

import org.biojava.utils.bytecode.*;

import java.util.*;
import java.io.*;

public class MakeHelloWorld {
    public static void main(String[] args) throws Exception {
	CodeClass cl_Object = IntrospectedCodeClass.forClass("java.lang.Object");
	CodeClass cl_String = IntrospectedCodeClass.forClass("java.lang.String");
	CodeClass cl_System = IntrospectedCodeClass.forClass("java.lang.System");
	CodeClass cl_PrintStream = IntrospectedCodeClass.forClass("java.io.PrintStream");
	CodeClass cl_pVoid = IntrospectedCodeClass.forClass(Void.TYPE);
	CodeClass i_Runnable = IntrospectedCodeClass.forClass(Runnable.class);
        CodeClass[] aInterfaces = { i_Runnable };

	CodeField f_System_out = cl_System.getFieldByName("out");
	CodeMethod m_PrintStream_println_I = oneIntMethod(cl_PrintStream.getMethodsByName("println"));
	CodeMethod m_Object_init = new SimpleCodeMethod("<init>", cl_Object, cl_pVoid,
							 new ArrayList(), CodeUtils.ACC_PUBLIC);
	
        CodeClass[] aMethodArgs = {};
	GeneratedCodeClass cc = new GeneratedCodeClass("MyTestClass",
		       IntrospectedCodeClass.forClass("java.lang.Object"),
		       aInterfaces,
		       CodeUtils.ACC_PUBLIC | CodeUtils.ACC_SUPER);

	GeneratedCodeMethod init = cc.createMethod("<init>",
						   cl_pVoid,
						   aMethodArgs,
						   CodeUtils.ACC_PUBLIC);
	InstructionVector iv = new InstructionVector();
	iv.add(ByteCode.make_aload(init.getThis()));
	iv.add(ByteCode.make_invokespecial(m_Object_init));
	iv.add(ByteCode.make_return());
	cc.setCodeGenerator(init, iv);

	GeneratedCodeMethod run = cc.createMethod("run",
						   cl_pVoid,
						   aMethodArgs,
						   CodeUtils.ACC_PUBLIC);
	iv = new InstructionVector();
	Label loopTest = new Label();
	Label loopStart = new Label();
	Label loopEnd = new Label();
	iv.add(ByteCode.make_iconst(1));
	iv.add(ByteCode.make_goto(loopStart));
	iv.add(loopTest);
        iv.add(ByteCode.make_dup());
	iv.add(ByteCode.make_iconst(10));
	iv.add(ByteCode.make_if_icmpgt(loopEnd));
	iv.add(loopStart);
	iv.add(ByteCode.make_dup());
	iv.add(ByteCode.make_getstatic(f_System_out));
	iv.add(ByteCode.make_swap());
	iv.add(ByteCode.make_invokevirtual(m_PrintStream_println_I));
	iv.add(ByteCode.make_iconst(1));
	iv.add(ByteCode.make_iadd());
	iv.add(ByteCode.make_goto(loopTest));
	iv.add(loopEnd);
	iv.add(ByteCode.make_return());

	cc.setCodeGenerator(run, iv);

	FileOutputStream fos = new FileOutputStream("MyTestClass.class");
	cc.createCode(fos);
	fos.close();
    }

    static CodeMethod oneIntMethod(Set methods) {
	CodeClass cl_pInt = IntrospectedCodeClass.forClass(Integer.TYPE);
	for (Iterator i = methods.iterator(); i.hasNext(); ) {
	    CodeMethod cm = (CodeMethod) i.next();
	    if (cm.numParameters() != 1)
		continue;
	    if (cm.getParameterType(0) == cl_pInt)
		return cm;
	}

	return null;
    }
}
