package me.coley.recaf.mapping;

import org.apache.commons.io.FileUtils;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.commons.ClassRemapper;
import org.objectweb.asm.commons.SimpleRemapper;

import java.io.File;
import java.io.IOException;
import java.util.Map;

/**
 * Base for mapppings.
 *
 * @author Matt
 */
public abstract class Mappings {
	/**
	 * ASM formatted mappings.
	 */
	private Map<String, String> mappings;

	/**
	 * @param file
	 * 		Text file containing mappings.
	 *
	 * @throws IOException
	 * 		Thrown if the file could not be read.
	 */
	public Mappings(File file) throws IOException {
		read(file);
	}

	/**
	 * @param file
	 * 		Text file containing mappings.
	 *
	 * @throws IOException
	 * 		Thrown if the file could not be read.
	 */
	private void read(File file) throws IOException {
		String text = FileUtils.readFileToString(file, "UTF-8");
		mappings = parse(text);
	}

	/**
	 * See the
	 * {@link org.objectweb.asm.commons.SimpleRemapper#SimpleRemapper(Map)} docs for more
	 * information.
	 *
	 * @return ASM formatted mappings.
	 */
	public Map<String, String> getMappings() {
		return mappings;
	}

	/**
	 * Parses the mappings into the standard ASM format. See the
	 * {@link org.objectweb.asm.commons.SimpleRemapper#SimpleRemapper(Map)} docs for more
	 * information.
	 *
	 * @param text
	 * 		Text of the mappings.
	 *
	 * @return ASM formatted mappings.
	 */
	protected abstract Map<String, String> parse(String text);

	/**
	 * @param clazz
	 * 		Class bytecode.
	 */
	public byte[] accept(byte[] clazz) {
		SimpleRecordingRemapper mapper = new SimpleRecordingRemapper(getMappings());
		ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
		ClassRemapper adapter = new ClassRemapper(cw, mapper);
		new ClassReader(clazz).accept(adapter, ClassReader.SKIP_FRAMES);
		// Only return the modified class if any references to the mappings were found.
		if (mapper.isDirty())
			return cw.toByteArray();
		return clazz;
	}
}

@@ -26,16 +26,62 @@
 pping;%0A%0A
+import me.coley.recaf.workspace.JavaResource;%0A
 import o
@@ -112,16 +112,16 @@
 eUtils;%0A
-
 import o
@@ -239,57 +239,8 @@
 per;
-%0Aimport org.objectweb.asm.commons.SimpleRemapper;
 %0A%0Aim
@@ -286,16 +286,42 @@
 eption;%0A
+import java.util.HashMap;%0A
 import j
@@ -1531,21 +1531,972 @@
 text);%0A%0A
-
 %09/**%0A
+%09 * Applies mappings to all classes in the given resource. Return value is the map of updated%0A%09 * classes.%0A%09 *%0A%09 * @param resource%0A%09 * %09%09Resource containing classes.%0A%09 *%0A%09 * @return Map of updated classes. Keys of the old names, values of the updated code.%0A%09 */%0A%09public Map%3CString, byte%5B%5D%3E accept(JavaResource resource) %7B%0A%09%09// Collect: %3COldName, NewBytecode%3E%0A%09%09Map%3CString, byte%5B%5D%3E updated = new HashMap%3C%3E();%0A%09%09for(Map.Entry%3CString, byte%5B%5D%3E e : resource.getClasses().entrySet()) %7B%0A%09%09%09byte%5B%5D old = e.getValue();%0A%09%09%09byte%5B%5D mapped = accept(old);%0A%09%09%09if(old == mapped)%0A%09%09%09%09continue;%0A%09%09%09updated.put(e.getKey(), mapped);%0A%09%09%7D%0A%09%09// Update the resource's classes map%0A%09%09for(Map.Entry%3CString, byte%5B%5D%3E e : updated.entrySet()) %7B%0A%09%09%09String newKey = new ClassReader(e.getValue()).getClassName();%0A%09%09%09resource.getClasses().remove(e.getKey());%0A%09%09%09resource.getClasses().put(newKey, e.getValue());%0A%09%09%7D%0A%09%09return updated;%0A%09%7D%0A%09/**%0A%09 * Applies mappings to the given class.%0A%09 *%0A
 %09 * @par

Add additional mapping 'accept'