package io.highway.to.urhell.transformer;

import io.highway.to.urhell.domain.BreakerData;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.List;
import java.util.Map;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.LoaderClassPath;
import javassist.NotFoundException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GenericTransformer implements ClassFileTransformer {

	private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
	private Map<String, List<BreakerData>> mapToTransform = null;

	public GenericTransformer(Map<String, List<BreakerData>> mapTransform) {
		mapToTransform = mapTransform;
	}

	public byte[] transform(ClassLoader loader, String className,
			Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
			byte[] classfileBuffer) throws IllegalClassFormatException {

		String classNameToTransform = null;
		String methodNameToTransform = null;
		String signatureName = null;

		if (!mapToTransform.get(className).isEmpty()) {
			try {
				List<BreakerData> listbd = mapToTransform.get(className);
				ClassPool cp = ClassPool.getDefault();
				cp.appendClassPath(new LoaderClassPath(loader));
				addImportPackage(cp);
				classNameToTransform = listbd.get(0).getClassName();
				CtClass cc = cp.get(classNameToTransform);
				for (BreakerData bd : listbd) {
					classNameToTransform = bd.getClassName();
					methodNameToTransform = bd.getMethodName();
					signatureName = bd.getSignatureName();
					
					LOGGER.info(
							"Going to Transform {} with methodName {} and signature {} this class {}",
							classNameToTransform, methodNameToTransform,
							signatureName, this.getClass());

					CtMethod m = cc.getMethod(methodNameToTransform,
							signatureName);

					m.insertBefore(generateCmd(classNameToTransform,
							methodNameToTransform));
				}
				classfileBuffer = cc.toBytecode();
				cc.detach();
			} catch (NotFoundException ex) {
				LOGGER.error("not found ", ex);
			} catch (Exception ex) {
				LOGGER.error("Fail to Transform {} with {}",
						classNameToTransform, this.getClass(), ex);
			}

		}

		return classfileBuffer;
	}

	private String generateCmd(String className, String methodName) {
		return "GatherService.getInstance().gather(\"" + className + "."+ methodName + "\");";
	}

	private void addImportPackage(ClassPool cp) {
		cp.importPackage("io.highway.to.urhell");
		cp.importPackage("io.highway.to.urhell.domain");
		cp.importPackage("io.highway.to.urhell.service");
		cp.importPackage("io.highway.to.urhell.service.impl");
	}

}

@@ -277,16 +277,57 @@
 l.Map;%0A%0A
+import javassist.CannotCompileException;%0A
 import j
@@ -1032,17 +1032,16 @@
 ption %7B%0A
-%0A
 %09%09String
@@ -1074,79 +1074,8 @@
 ll;%0A
-%09%09String methodNameToTransform = null;%0A%09%09String signatureName = null;%0A%0A
 %09%09if
@@ -1462,503 +1462,24 @@
 %09%09%09%09
-classNameToTransform = bd.getClassName();%0A%09%09%09%09%09methodNameToTransform = bd.getMethodName();%0A%09%09%09%09%09signatureName = bd.getSignatureName();%0A%09%09%09%09%09%0A%09%09%09%09%09LOGGER.info(%0A%09%09%09%09%09%09%09%22Going to Transform %7B%7D with methodName %7B%7D and signature %7B%7D this class %7B%7D%22,%0A%09%09%09%09%09%09%09classNameToTransform, methodNameToTransform,%0A%09%09%09%09%09%09%09signatureName, this.getClass());%0A%0A%09%09%09%09%09CtMethod m = cc.getMethod(methodNameToTransform,%0A%09%09%09%09%09%09%09signatureName);%0A%0A%09%09%09%09%09m.insertBefore(generateCmd(classNameToTransform,%0A%09%09%09%09%09%09%09methodNameToTransform)
+insertCode(bd,cc
 );%0A%09
@@ -1747,14 +1747,12 @@
 %09%09%7D%0A
-%0A
 %09%09%7D%0A
-%0A
 %09%09re
@@ -1771,24 +1771,615 @@
 leBuffer;%0A%09%7D
+%0A%09%0A%09private void insertCode(BreakerData bd,CtClass cc)%7B%0A%09%09LOGGER.info(%0A%09%09%09%09%22Going to Transform %7B%7D with methodName %7B%7D and signature %7B%7D this class %7B%7D%22,%0A%09%09%09%09bd.getClassName(), bd.getMethodName(),%0A%09%09%09%09bd.getSignatureName(), this.getClass());%0A%0A%09%09CtMethod m;%0A%09%09try %7B%0A%09%09%09m = cc.getMethod(bd.getMethodName(),bd.getSignatureName());%0A%09%09%09m.insertBefore(generateCmd(bd.getClassName(),bd.getMethodName()));%0A%09%09%7D catch (NotFoundException %7C CannotCompileException e) %7B%0A%09%09%09LOGGER.error(%22Insert Code for className %7B%7D and methodName %7B%7D fails msg %7B%7D%22,bd.getClassName(),bd.getMethodName(),e.getMessage());%0A%09%09%7D%0A%09%7D
 %0A%0A%09private S

refactor GenericTransformer for add probe