package shadersmod.transform;

import static org.objectweb.asm.Opcodes.*;
import net.minecraft.launchwrapper.IClassTransformer;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import shadersmod.common.SMCLog;

/** transformer for VertexFormat */
public class STVertexFormat implements IClassTransformer {

	@Override
	public byte[] transform(String par1, String par2, byte[] par3) {
		SMCLog.fine("transforming %s %s",par1,par2);
		ClassReader cr = new ClassReader(par3);
		ClassWriter cw = new ClassWriter(cr, 0);
		CVTransform cv = new CVTransform(cw);
		cr.accept(cv,0);
		return cw.toByteArray();
	}

	private static class CVTransform extends ClassVisitor
	{
		String classname;
		boolean endFields = false;
		public CVTransform(ClassVisitor cv)
		{
			super(Opcodes.ASM4, cv);		
		}

		@Override
		public void visit(int version, int access, String name,
				String signature, String superName, String[] interfaces) {
			this.classname = name;
			//SMCLog.info(" class %s",name);
			super.visit(version, access, name, signature, superName, interfaces);
		}

		@Override
		public MethodVisitor visitMethod(int access, String name, String desc,
				String signature, String[] exceptions) 
		{
			if (!endFields) {
				endFields = true;
				FieldVisitor fv;
				fv = cv.visitField(ACC_PUBLIC, Names.vertexFormat_tangentElementOffset.name, Names.vertexFormat_tangentElementOffset.desc, null, null);
				fv.visitEnd();
				fv = cv.visitField(ACC_PUBLIC, Names.vertexFormat_entityElementOffset.name, Names.vertexFormat_entityElementOffset.desc, null, null);
				fv.visitEnd();
				fv = cv.visitField(ACC_PUBLIC, Names.vertexFormat_miduvElementOffset.name, Names.vertexFormat_miduvElementOffset.desc, null, null);
				fv.visitEnd();
			}
			//if (Names.vertexFormat_init_vertexFormat.equalsNameDesc(name, desc))
			//{
			//	SMCLog.finer("  patching method %s.%s%s",classname,name,desc);
			//	return new MVinitCopy(cv.visitMethod(access, name, desc, signature, exceptions));
			//}
			//else
			//if (Names.vertexFormat_getVertexSize.equalsNameDesc(name, desc))
			//{
			//	SMCLog.finer("  patching method %s.%s%s",classname,name,desc);
			//	return new MVgetVertexSize(cv.visitMethod(access, name, desc, signature, exceptions));
			//}
			if (Names.vertexFormat_addElement.equalsNameDesc(name, desc))
			{
				SMCLog.finer("  patching method %s.%s%s",classname,name,desc);
				return new MVaddElement(cv.visitMethod(access, name, desc, signature, exceptions));
			}
			
			return cv.visitMethod(access, name, desc, signature, exceptions);
		}

		@Override
		public void visitEnd() {
			// TODO Auto-generated method stub
			AccessorGenerator.generateFieldAccessor(cv, "offsets", Names.vertexFormat_offsets);
			AccessorGenerator.generateFieldAccessor(cv, "nextOffset", Names.vertexFormat_nextOffset);
			AccessorGenerator.generateFieldAccessor(cv, "colorElementOffset", Names.vertexFormat_colorElementOffset);
			AccessorGenerator.generateFieldAccessor(cv, "uvOffsets", Names.vertexFormat_uvOffsets);
			AccessorGenerator.generateFieldAccessor(cv, "normalElementOffset", Names.vertexFormat_normalElementOffset);
			super.visitEnd();
		}
		
	}

	
	private static class MVaddElement extends MethodVisitor
	{
		public MVaddElement(MethodVisitor mv) {
			super(Opcodes.ASM4, mv);
		}

		@Override
		public void visitCode() {
			mv.visitCode();
			mv.visitVarInsn(ALOAD, 0);
			mv.visitVarInsn(ALOAD, 1);
			mv.visitMethodInsn(INVOKESTATIC, Names.sVertexFormat_onAddElement.clasName, Names.sVertexFormat_onAddElement.name, Names.sVertexFormat_onAddElement.desc);
		}
		
	}
	
//	not needed
//	private static class MVinitCopy extends MethodVisitor
//	{
//		public MVinitCopy(MethodVisitor mv) {
//			super(Opcodes.ASM4, mv);
//		}
//
//		@Override
//		public void visitMethodInsn(int opcode, String owner, String name, String desc) {
//			if (Names.vertexFormat_getVertexSize.equals(owner,name,desc)) {
//				mv.visitFieldInsn(GETFIELD, Names.vertexFormat_nextOffset.clasName, Names.vertexFormat_nextOffset.name, Names.vertexFormat_nextOffset.desc);
//			} else {
//				super.visitMethodInsn(opcode, owner, name, desc);
//			}
//		}
//
//	}
//	not needed
//	private static class MVgetVertexSize extends MethodVisitor
//	{
//		public MVgetVertexSize(MethodVisitor mv) {
//			super(Opcodes.ASM4, mv);
//		}
//
//		@Override
//		public void visitFieldInsn(int opcode, String owner, String name, String desc) {
//			//if (opcode==GETFIELD && Names.vertexFormat_nextOffset.equals(owner, name, desc)) {
//			//	mv.visitIntInsn(BIPUSH, 14*4);
//			//} else {
//				super.visitFieldInsn(opcode, owner, name, desc);
//			//}
//		}
//
//	}

}
