package me.lpk.util;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FrameNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;

import me.lpk.log.Logger;

public class OpUtils implements org.objectweb.asm.Opcodes {
	private static Map<Integer, String> opcodes = new HashMap<Integer, String>(getCodes());
	private static Map<String, Integer> reopcodes = new HashMap<String, Integer>(getReCodes());

	private static Map<? extends Integer, ? extends String> getCodes() {
		HashMap<Integer, String> map = new HashMap<Integer, String>();
		map.put(-1, "INVALID OPCODE");
		map.put(ACC_PUBLIC, "ACC_PUBLIC");
		map.put(ACC_PRIVATE, "ACC_PRIVATE");
		map.put(ACC_PROTECTED, "ACC_PROTECTED");
		map.put(ACC_STATIC, "ACC_STATIC");
		map.put(ACC_FINAL, "ACC_FINAL");
		map.put(ACC_SUPER, "ACC_SUPER");
		map.put(ACC_SYNCHRONIZED, "ACC_SYNCHRONIZED");
		map.put(ACC_VOLATILE, "ACC_VOLATILE");
		map.put(ACC_BRIDGE, "ACC_BRIDGE");
		map.put(ACC_VARARGS, "ACC_VARARGS");
		map.put(ACC_TRANSIENT, "ACC_TRANSIENT");
		map.put(ACC_NATIVE, "ACC_NATIVE");
		map.put(ACC_INTERFACE, "ACC_INTERFACE");
		map.put(ACC_ABSTRACT, "ACC_ABSTRACT");
		map.put(ACC_STRICT, "ACC_STRICT");
		map.put(ACC_SYNTHETIC, "ACC_SYNTHETIC");
		map.put(ACC_ANNOTATION, "ACC_ANNOTATION");
		map.put(ACC_ENUM, "ACC_ENUM");
		map.put(ACC_MANDATED, "ACC_MANDATED");
		map.put(ACC_DEPRECATED, "ACC_DEPRECATED");
		map.put(T_BOOLEAN, "T_BOOLEAN");
		map.put(T_CHAR, "T_CHAR");
		map.put(T_FLOAT, "T_FLOAT");
		map.put(T_DOUBLE, "T_DOUBLE");
		map.put(T_BYTE, "T_BYTE");
		map.put(T_SHORT, "T_SHORT");
		map.put(T_INT, "T_INT");
		map.put(T_LONG, "T_LONG");
		map.put(H_GETFIELD, "H_GETFIELD");
		map.put(H_GETSTATIC, "H_GETSTATIC");
		map.put(H_PUTFIELD, "H_PUTFIELD");
		map.put(H_PUTSTATIC, "H_PUTSTATIC");
		map.put(H_INVOKEVIRTUAL, "H_INVOKEVIRTUAL");
		map.put(H_INVOKESTATIC, "H_INVOKESTATIC");
		map.put(H_INVOKESPECIAL, "H_INVOKESPECIAL");
		map.put(H_NEWINVOKESPECIAL, "H_NEWINVOKESPECIAL");
		map.put(H_INVOKEINTERFACE, "H_INVOKEINTERFACE");
		map.put(F_NEW, "F_NEW");
		map.put(F_FULL, "F_FULL");
		map.put(F_APPEND, "F_APPEND");
		map.put(F_CHOP, "F_CHOP");
		map.put(F_SAME, "F_SAME");
		map.put(F_SAME1, "F_SAME1");
		map.put(NOP, "NOP");
		map.put(ACONST_NULL, "ACONST_NULL");
		map.put(ICONST_M1, "ICONST_M1");
		map.put(ICONST_0, "ICONST_0");
		map.put(ICONST_1, "ICONST_1");
		map.put(ICONST_2, "ICONST_2");
		map.put(ICONST_3, "ICONST_3");
		map.put(ICONST_4, "ICONST_4");
		map.put(ICONST_5, "ICONST_5");
		map.put(LCONST_0, "LCONST_0");
		map.put(LCONST_1, "LCONST_1");
		map.put(FCONST_0, "FCONST_0");
		map.put(FCONST_1, "FCONST_1");
		map.put(FCONST_2, "FCONST_2");
		map.put(DCONST_0, "DCONST_0");
		map.put(DCONST_1, "DCONST_1");
		map.put(BIPUSH, "BIPUSH");
		map.put(SIPUSH, "SIPUSH");
		map.put(LDC, "LDC");
		map.put(ILOAD, "ILOAD");
		map.put(LLOAD, "LLOAD");
		map.put(FLOAD, "FLOAD");
		map.put(DLOAD, "DLOAD");
		map.put(ALOAD, "ALOAD");
		map.put(IALOAD, "IALOAD");
		map.put(LALOAD, "LALOAD");
		map.put(FALOAD, "FALOAD");
		map.put(DALOAD, "DALOAD");
		map.put(AALOAD, "AALOAD");
		map.put(BALOAD, "BALOAD");
		map.put(CALOAD, "CALOAD");
		map.put(SALOAD, "SALOAD");
		map.put(ISTORE, "ISTORE");
		map.put(LSTORE, "LSTORE");
		map.put(FSTORE, "FSTORE");
		map.put(DSTORE, "DSTORE");
		map.put(ASTORE, "ASTORE");
		map.put(IASTORE, "IASTORE");
		map.put(LASTORE, "LASTORE");
		map.put(FASTORE, "FASTORE");
		map.put(DASTORE, "DASTORE");
		map.put(AASTORE, "AASTORE");
		map.put(BASTORE, "BASTORE");
		map.put(CASTORE, "CASTORE");
		map.put(SASTORE, "SASTORE");
		map.put(POP, "POP");
		map.put(POP2, "POP2");
		map.put(DUP, "DUP");
		map.put(DUP_X1, "DUP_X1");
		map.put(DUP_X2, "DUP_X2");
		map.put(DUP2, "DUP2");
		map.put(DUP2_X1, "DUP2_X1");
		map.put(DUP2_X2, "DUP2_X2");
		map.put(SWAP, "SWAP");
		map.put(IADD, "IADD");
		map.put(LADD, "LADD");
		map.put(FADD, "FADD");
		map.put(DADD, "DADD");
		map.put(ISUB, "ISUB");
		map.put(LSUB, "LSUB");
		map.put(FSUB, "FSUB");
		map.put(DSUB, "DSUB");
		map.put(IMUL, "IMUL");
		map.put(LMUL, "LMUL");
		map.put(FMUL, "FMUL");
		map.put(DMUL, "DMUL");
		map.put(IDIV, "IDIV");
		map.put(LDIV, "LDIV");
		map.put(FDIV, "FDIV");
		map.put(DDIV, "DDIV");
		map.put(IREM, "IREM");
		map.put(LREM, "LREM");
		map.put(FREM, "FREM");
		map.put(DREM, "DREM");
		map.put(INEG, "INEG");
		map.put(LNEG, "LNEG");
		map.put(FNEG, "FNEG");
		map.put(DNEG, "DNEG");
		map.put(ISHL, "ISHL");
		map.put(LSHL, "LSHL");
		map.put(ISHR, "ISHR");
		map.put(LSHR, "LSHR");
		map.put(IUSHR, "IUSHR");
		map.put(LUSHR, "LUSHR");
		map.put(IAND, "IAND");
		map.put(LAND, "LAND");
		map.put(IOR, "IOR");
		map.put(LOR, "LOR");
		map.put(IXOR, "IXOR");
		map.put(LXOR, "LXOR");
		map.put(IINC, "IINC");
		map.put(I2L, "I2L");
		map.put(I2F, "I2F");
		map.put(I2D, "I2D");
		map.put(L2I, "L2I");
		map.put(L2F, "L2F");
		map.put(L2D, "L2D");
		map.put(F2I, "F2I");
		map.put(F2L, "F2L");
		map.put(F2D, "F2D");
		map.put(D2I, "D2I");
		map.put(D2L, "D2L");
		map.put(D2F, "D2F");
		map.put(I2B, "I2B");
		map.put(I2C, "I2C");
		map.put(I2S, "I2S");
		map.put(LCMP, "LCMP");
		map.put(FCMPL, "FCMPL");
		map.put(FCMPG, "FCMPG");
		map.put(DCMPL, "DCMPL");
		map.put(DCMPG, "DCMPG");
		map.put(IFEQ, "IFEQ");
		map.put(IFNE, "IFNE");
		map.put(IFLT, "IFLT");
		map.put(IFGE, "IFGE");
		map.put(IFGT, "IFGT");
		map.put(IFLE, "IFLE");
		map.put(IF_ICMPEQ, "IF_ICMPEQ");
		map.put(IF_ICMPNE, "IF_ICMPNE");
		map.put(IF_ICMPLT, "IF_ICMPLT");
		map.put(IF_ICMPGE, "IF_ICMPGE");
		map.put(IF_ICMPGT, "IF_ICMPGT");
		map.put(IF_ICMPLE, "IF_ICMPLE");
		map.put(IF_ACMPEQ, "IF_ACMPEQ");
		map.put(IF_ACMPNE, "IF_ACMPNE");
		map.put(GOTO, "GOTO");
		map.put(JSR, "JSR");
		map.put(RET, "RET");
		map.put(TABLESWITCH, "TABLESWITCH");
		map.put(LOOKUPSWITCH, "LOOKUPSWITCH");
		map.put(IRETURN, "IRETURN");
		map.put(LRETURN, "LRETURN");
		map.put(FRETURN, "FRETURN");
		map.put(DRETURN, "DRETURN");
		map.put(ARETURN, "ARETURN");
		map.put(RETURN, "RETURN");
		map.put(GETSTATIC, "GETSTATIC");
		map.put(PUTSTATIC, "PUTSTATIC");
		map.put(GETFIELD, "GETFIELD");
		map.put(PUTFIELD, "PUTFIELD");
		map.put(INVOKEVIRTUAL, "INVOKEVIRTUAL");
		map.put(INVOKESPECIAL, "INVOKESPECIAL");
		map.put(INVOKESTATIC, "INVOKESTATIC");
		map.put(INVOKEINTERFACE, "INVOKEINTERFACE");
		map.put(INVOKEDYNAMIC, "INVOKEDYNAMIC");
		map.put(NEW, "NEW");
		map.put(NEWARRAY, "NEWARRAY");
		map.put(ANEWARRAY, "ANEWARRAY");
		map.put(ARRAYLENGTH, "ARRAYLENGTH");
		map.put(ATHROW, "ATHROW");
		map.put(CHECKCAST, "CHECKCAST");
		map.put(INSTANCEOF, "INSTANCEOF");
		map.put(MONITORENTER, "MONITORENTER");
		map.put(MONITOREXIT, "MONITOREXIT");
		map.put(MULTIANEWARRAY, "MULTIANEWARRAY");
		map.put(IFNULL, "IFNULL");
		map.put(IFNONNULL, "IFNONNULL");
		return map;
	}

	private static Map<? extends String, ? extends Integer> getReCodes() {
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		map.put("INVALID OPCODE", -1);
		map.put("ACC_PUBLIC", ACC_PUBLIC);
		map.put("ACC_PRIVATE", ACC_PRIVATE);
		map.put("ACC_PROTECTED", ACC_PROTECTED);
		map.put("ACC_STATIC", ACC_STATIC);
		map.put("ACC_FINAL", ACC_FINAL);
		map.put("ACC_SUPER", ACC_SUPER);
		map.put("ACC_SYNCHRONIZED", ACC_SYNCHRONIZED);
		map.put("ACC_VOLATILE", ACC_VOLATILE);
		map.put("ACC_BRIDGE", ACC_BRIDGE);
		map.put("ACC_VARARGS", ACC_VARARGS);
		map.put("ACC_TRANSIENT", ACC_TRANSIENT);
		map.put("ACC_NATIVE", ACC_NATIVE);
		map.put("ACC_INTERFACE", ACC_INTERFACE);
		map.put("ACC_ABSTRACT", ACC_ABSTRACT);
		map.put("ACC_STRICT", ACC_STRICT);
		map.put("ACC_SYNTHETIC", ACC_SYNTHETIC);
		map.put("ACC_ANNOTATION", ACC_ANNOTATION);
		map.put("ACC_ENUM", ACC_ENUM);
		map.put("ACC_MANDATED", ACC_MANDATED);
		map.put("ACC_DEPRECATED", ACC_DEPRECATED);
		map.put("T_BOOLEAN", T_BOOLEAN);
		map.put("T_CHAR", T_CHAR);
		map.put("T_FLOAT", T_FLOAT);
		map.put("T_DOUBLE", T_DOUBLE);
		map.put("T_BYTE", T_BYTE);
		map.put("T_SHORT", T_SHORT);
		map.put("T_INT", T_INT);
		map.put("T_LONG", T_LONG);
		map.put("H_GETFIELD", H_GETFIELD);
		map.put("H_GETSTATIC", H_GETSTATIC);
		map.put("H_PUTFIELD", H_PUTFIELD);
		map.put("H_PUTSTATIC", H_PUTSTATIC);
		map.put("H_INVOKEVIRTUAL", H_INVOKEVIRTUAL);
		map.put("H_INVOKESTATIC", H_INVOKESTATIC);
		map.put("H_INVOKESPECIAL", H_INVOKESPECIAL);
		map.put("H_NEWINVOKESPECIAL", H_NEWINVOKESPECIAL);
		map.put("H_INVOKEINTERFACE", H_INVOKEINTERFACE);
		map.put("F_NEW", F_NEW);
		map.put("F_FULL", F_FULL);
		map.put("F_APPEND", F_APPEND);
		map.put("F_CHOP", F_CHOP);
		map.put("F_SAME", F_SAME);
		map.put("F_SAME1", F_SAME1);
		map.put("NOP", NOP);
		map.put("ACONST_NULL", ACONST_NULL);
		map.put("ICONST_M1", ICONST_M1);
		map.put("ICONST_0", ICONST_0);
		map.put("ICONST_1", ICONST_1);
		map.put("ICONST_2", ICONST_2);
		map.put("ICONST_3", ICONST_3);
		map.put("ICONST_4", ICONST_4);
		map.put("ICONST_5", ICONST_5);
		map.put("LCONST_0", LCONST_0);
		map.put("LCONST_1", LCONST_1);
		map.put("FCONST_0", FCONST_0);
		map.put("FCONST_1", FCONST_1);
		map.put("FCONST_2", FCONST_2);
		map.put("DCONST_0", DCONST_0);
		map.put("DCONST_1", DCONST_1);
		map.put("BIPUSH", BIPUSH);
		map.put("SIPUSH", SIPUSH);
		map.put("LDC", LDC);
		map.put("ILOAD", ILOAD);
		map.put("LLOAD", LLOAD);
		map.put("FLOAD", FLOAD);
		map.put("DLOAD", DLOAD);
		map.put("ALOAD", ALOAD);
		map.put("IALOAD", IALOAD);
		map.put("LALOAD", LALOAD);
		map.put("FALOAD", FALOAD);
		map.put("DALOAD", DALOAD);
		map.put("AALOAD", AALOAD);
		map.put("BALOAD", BALOAD);
		map.put("CALOAD", CALOAD);
		map.put("SALOAD", SALOAD);
		map.put("ISTORE", ISTORE);
		map.put("LSTORE", LSTORE);
		map.put("FSTORE", FSTORE);
		map.put("DSTORE", DSTORE);
		map.put("ASTORE", ASTORE);
		map.put("IASTORE", IASTORE);
		map.put("LASTORE", LASTORE);
		map.put("FASTORE", FASTORE);
		map.put("DASTORE", DASTORE);
		map.put("AASTORE", AASTORE);
		map.put("BASTORE", BASTORE);
		map.put("CASTORE", CASTORE);
		map.put("SASTORE", SASTORE);
		map.put("POP", POP);
		map.put("POP2", POP2);
		map.put("DUP", DUP);
		map.put("DUP_X1", DUP_X1);
		map.put("DUP_X2", DUP_X2);
		map.put("DUP2", DUP2);
		map.put("DUP2_X1", DUP2_X1);
		map.put("DUP2_X2", DUP2_X2);
		map.put("SWAP", SWAP);
		map.put("IADD", IADD);
		map.put("LADD", LADD);
		map.put("FADD", FADD);
		map.put("DADD", DADD);
		map.put("ISUB", ISUB);
		map.put("LSUB", LSUB);
		map.put("FSUB", FSUB);
		map.put("DSUB", DSUB);
		map.put("IMUL", IMUL);
		map.put("LMUL", LMUL);
		map.put("FMUL", FMUL);
		map.put("DMUL", DMUL);
		map.put("IDIV", IDIV);
		map.put("LDIV", LDIV);
		map.put("FDIV", FDIV);
		map.put("DDIV", DDIV);
		map.put("IREM", IREM);
		map.put("LREM", LREM);
		map.put("FREM", FREM);
		map.put("DREM", DREM);
		map.put("INEG", INEG);
		map.put("LNEG", LNEG);
		map.put("FNEG", FNEG);
		map.put("DNEG", DNEG);
		map.put("ISHL", ISHL);
		map.put("LSHL", LSHL);
		map.put("ISHR", ISHR);
		map.put("LSHR", LSHR);
		map.put("IUSHR", IUSHR);
		map.put("LUSHR", LUSHR);
		map.put("IAND", IAND);
		map.put("LAND", LAND);
		map.put("IOR", IOR);
		map.put("LOR", LOR);
		map.put("IXOR", IXOR);
		map.put("LXOR", LXOR);
		map.put("IINC", IINC);
		map.put("I2L", I2L);
		map.put("I2F", I2F);
		map.put("I2D", I2D);
		map.put("L2I", L2I);
		map.put("L2F", L2F);
		map.put("L2D", L2D);
		map.put("F2I", F2I);
		map.put("F2L", F2L);
		map.put("F2D", F2D);
		map.put("D2I", D2I);
		map.put("D2L", D2L);
		map.put("D2F", D2F);
		map.put("I2B", I2B);
		map.put("I2C", I2C);
		map.put("I2S", I2S);
		map.put("LCMP", LCMP);
		map.put("FCMPL", FCMPL);
		map.put("FCMPG", FCMPG);
		map.put("DCMPL", DCMPL);
		map.put("DCMPG", DCMPG);
		map.put("IFEQ", IFEQ);
		map.put("IFNE", IFNE);
		map.put("IFLT", IFLT);
		map.put("IFGE", IFGE);
		map.put("IFGT", IFGT);
		map.put("IFLE", IFLE);
		map.put("IF_ICMPEQ", IF_ICMPEQ);
		map.put("IF_ICMPNE", IF_ICMPNE);
		map.put("IF_ICMPLT", IF_ICMPLT);
		map.put("IF_ICMPGE", IF_ICMPGE);
		map.put("IF_ICMPGT", IF_ICMPGT);
		map.put("IF_ICMPLE", IF_ICMPLE);
		map.put("IF_ACMPEQ", IF_ACMPEQ);
		map.put("IF_ACMPNE", IF_ACMPNE);
		map.put("GOTO", GOTO);
		map.put("JSR", JSR);
		map.put("RET", RET);
		map.put("TABLESWITCH", TABLESWITCH);
		map.put("LOOKUPSWITCH", LOOKUPSWITCH);
		map.put("IRETURN", IRETURN);
		map.put("LRETURN", LRETURN);
		map.put("FRETURN", FRETURN);
		map.put("DRETURN", DRETURN);
		map.put("ARETURN", ARETURN);
		map.put("RETURN", RETURN);
		map.put("GETSTATIC", GETSTATIC);
		map.put("PUTSTATIC", PUTSTATIC);
		map.put("GETFIELD", GETFIELD);
		map.put("PUTFIELD", PUTFIELD);
		map.put("INVOKEVIRTUAL", INVOKEVIRTUAL);
		map.put("INVOKESPECIAL", INVOKESPECIAL);
		map.put("INVOKESTATIC", INVOKESTATIC);
		map.put("INVOKEINTERFACE", INVOKEINTERFACE);
		map.put("INVOKEDYNAMIC", INVOKEDYNAMIC);
		map.put("NEW", NEW);
		map.put("NEWARRAY", NEWARRAY);
		map.put("ANEWARRAY", ANEWARRAY);
		map.put("ARRAYLENGTH", ARRAYLENGTH);
		map.put("ATHROW", ATHROW);
		map.put("CHECKCAST", CHECKCAST);
		map.put("INSTANCEOF", INSTANCEOF);
		map.put("MONITORENTER", MONITORENTER);
		map.put("MONITOREXIT", MONITOREXIT);
		map.put("MULTIANEWARRAY", MULTIANEWARRAY);
		map.put("IFNULL", IFNULL);
		map.put("IFNONNULL", IFNONNULL);
		return map;
	}

	/**
	 * Given an opcode (as text), returns the opcode as an index.
	 * 
	 * @param opcode
	 * @return
	 */
	public static int getOpcodeIndex(String opcode) {
		return reopcodes.get(opcode.toUpperCase());
	}

	/**
	 * Given an opcode (index), returns the opcode as text.
	 * 
	 * @param opcode
	 * @return
	 */
	public static String getOpcodeText(int opcode) {
		return opcodes.get(opcode);
	}

	/**
	 * Returns a set of all the opcodes as strings.
	 * 
	 * @return
	 */
	public static Set<String> getOpcodes() {
		return reopcodes.keySet();
	}

	/**
	 * Get the integer value of a InsnNode.
	 * 
	 * @param ain
	 * @return
	 */
	public static int getIntValue(AbstractInsnNode ain) {
		int opcode = ain.getOpcode();
		if (opcode >= Opcodes.ICONST_M1 && opcode <= Opcodes.ICONST_5) {
			return getIntValue(opcode);
		} else {
			return ((IntInsnNode) ain).operand;
		}
	}

	/**
	 * Gets the integer value of a given opcode.
	 * 
	 * @param opcode
	 * @return
	 */
	public static int getIntValue(int opcode) {
		if (opcode == Opcodes.ICONST_0) {
			return 0;
		} else if (opcode == Opcodes.ICONST_1) {
			return 1;
		} else if (opcode == Opcodes.ICONST_2) {
			return 2;
		} else if (opcode == Opcodes.ICONST_3) {
			return 3;
		} else if (opcode == Opcodes.ICONST_4) {
			return 4;
		} else if (opcode == Opcodes.ICONST_5) {
			return 5;
		} else {
			return -1;
		}
	}

	/**
	 * Gets the index of a AbstractInsnNode.
	 * 
	 * @param ain
	 * @return
	 */
	public static int getIndex(AbstractInsnNode ain) {
		int index = 0;
		while (ain.getPrevious() != null) {
			ain = ain.getPrevious();
			index += 1;
		}
		return index;
	}

	/**
	 * Given an integer, returns an InsnNode that will properly represent the
	 * int.
	 * 
	 * @param i
	 * @return
	 */
	public static AbstractInsnNode toInt(int i) {
		switch (i) {
		case -1:
			return new InsnNode(Opcodes.ICONST_M1);
		case 0:
			return new InsnNode(Opcodes.ICONST_0);
		case 1:
			return new InsnNode(Opcodes.ICONST_1);
		case 2:
			return new InsnNode(Opcodes.ICONST_2);
		case 3:
			return new InsnNode(Opcodes.ICONST_3);
		case 4:
			return new InsnNode(Opcodes.ICONST_4);
		case 5:
			return new InsnNode(Opcodes.ICONST_5);
		}
		if (i > -129 && i < 128) {
			return new IntInsnNode(Opcodes.BIPUSH, i);
		}
		return new LdcInsnNode(i);
	}

	public static String toString(AbstractInsnNode ain) {
		String s = getOpcodeText(ain.getOpcode());
		switch (ain.getType()) {
		case AbstractInsnNode.FIELD_INSN:
			FieldInsnNode fin = (FieldInsnNode) ain;
			return s + " " + fin.owner + "#" + fin.name + " " + fin.desc;
		case AbstractInsnNode.METHOD_INSN:
			MethodInsnNode min = (MethodInsnNode) ain;
			return s + " " + min.owner + "#" + min.name + min.desc;
		case AbstractInsnNode.VAR_INSN:
			VarInsnNode vin = (VarInsnNode) ain;
			return s + " " + vin.var;
		case AbstractInsnNode.TYPE_INSN:
			TypeInsnNode tin = (TypeInsnNode) ain;
			return s + " " + tin.desc;
		case AbstractInsnNode.JUMP_INSN:
			JumpInsnNode jin = (JumpInsnNode) ain;
			return s + " " + getIndex(jin.label);
		case AbstractInsnNode.LDC_INSN:
			LdcInsnNode ldc = (LdcInsnNode) ain;
			return s + " " + ldc.cst.toString();
		case AbstractInsnNode.INT_INSN:
			return s + " " + getIntValue(ain);
		case AbstractInsnNode.IINC_INSN:
			IincInsnNode iinc = (IincInsnNode) ain;
			return s + " " + iinc.var + " +" + iinc.incr;
		case AbstractInsnNode.FRAME:
			FrameNode fn = (FrameNode) ain;
			return s + " " + getOpcodeText(fn.type) + " " + fn.local.size() + " " + fn.stack.size();
		case AbstractInsnNode.LABEL:
			LabelNode ln = (LabelNode) ain;
			return s + " " + getIndex(ln);
		}
		return s;
	}

	public static void print(InsnList instructions) {
		for (AbstractInsnNode ain : instructions.toArray()) {
			Logger.logLow(toString(ain));
		}
	}
}