package org.pitest.mutationtest.mocksupport;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.function.Function;
import java.util.function.Predicate;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.pitest.bytecode.FrameOptions;

public class BendJavassistToMyWillTransformer implements ClassFileTransformer {

  private final Predicate<String> filter;
  private final Function<ClassWriter,ClassVisitor> transformation;

  public BendJavassistToMyWillTransformer(final Predicate<String> filter, Function<ClassWriter,ClassVisitor> transformation) {
    this.filter = filter;
    this.transformation = transformation;
  }

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

    if (shouldInclude(className)) {

      final ClassReader reader = new ClassReader(classfileBuffer);
      final ClassWriter writer = new ClassWriter(
          FrameOptions.pickFlags(classfileBuffer));

      reader.accept(this.transformation.apply(writer),
          ClassReader.EXPAND_FRAMES);
      return writer.toByteArray();
    } else {
      return null;
    }
  }

  private boolean shouldInclude(final String className) {
    return this.filter.test(className);
  }

}

@@ -185,16 +185,85 @@
 Domain;%0A
+import java.util.Map;%0Aimport java.util.concurrent.ConcurrentHashMap;%0A
 import j
@@ -286,24 +286,24 @@
 n.Function;%0A
-
 import java.
@@ -483,16 +483,120 @@
 Options;
+%0Aimport org.pitest.classinfo.ComputeClassWriter;%0Aimport org.pitest.classpath.ClassloaderByteArraySource;
 %0A%0Apublic
@@ -778,16 +778,94 @@
 rmation;
+%0A  private final Map%3CString, String%3E computeCache = new ConcurrentHashMap%3C%3E();
 %0A%0A  publ
@@ -1450,24 +1450,31 @@
 riter = new 
+Compute
 ClassWriter(
@@ -1474,16 +1474,93 @@
 Writer(%0A
+              new ClassloaderByteArraySource(loader), this.computeCache,%0A    
         
@@ -1604,16 +1604,17 @@
 fer));%0A%0A
+%0A
       re

Fix for #613: The BendJavassistToMyWillTransformer must use the ComputeClassWriter instead of ASM's default ClassWriter, since it will inevitably try to compute frames for javassist classes. If an application has already loaded a javassist class in a lower level class loader (e.g. not in the system boot classloader, where pit is), then this will cause a LinkageError for duplicate class loading.