code: package us.msu.cse.repair.core.util;
  
  import java.io.BufferedReader;
  import java.io.File;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.URI;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  
  import javax.tools.JavaFileObject;
  
  import jmetal.core.Solution;
  import jmetal.encodings.variable.ArrayInt;
  import jmetal.encodings.variable.Binary;
  
  import org.apache.commons.io.FileUtils;
  import org.eclipse.jdt.core.dom.Statement;
  
  import us.msu.cse.repair.core.compiler.JavaFileObjectImpl;
  import us.msu.cse.repair.core.parser.MethodInfo;
  import us.msu.cse.repair.core.parser.ModificationPoint;
  import us.msu.cse.repair.core.parser.SeedStatement;
  import us.msu.cse.repair.core.parser.SeedStatementInfo;
  
  public class IO {
  	public static void printSeedStatements(Map<SeedStatement, SeedStatementInfo> seedStatements, String filePath)
  			throws IOException {
  		File file = new File(filePath);
  		for (Map.Entry<SeedStatement, SeedStatementInfo> entry : seedStatements.entrySet()) {
  			String infoStr = entry.getValue().getSourceFilePaths().get(0) + "\t"
  					+ entry.getValue().getLCNodes().get(0).getLineNumber() + "\n";
  			infoStr += entry.getKey().getStatement().toString();
  			infoStr += "********************************************\n";
  			FileUtils.writeByteArrayToFile(file, infoStr.getBytes(), true);
  		}
  	}
  
  	public static void printModificationPoint(ModificationPoint mp, String filePath) throws IOException {
  		String infoStr = mp.getSourceFilePath() + "\t" + mp.getLCNode().getLineNumber() + "\t" + mp.getSuspValue()
  				+ "\n";
  		infoStr += mp.getStatement().toString();
  		infoStr += "********************************************\n\n";
  
  		infoStr += mp.getIngredients().size() + "\n";
  		for (Statement statement : mp.getIngredients()) {
  			infoStr += statement.toString();
  			infoStr += "********************************************\n";
  		}
  
  		FileUtils.writeByteArrayToFile(new File(filePath), infoStr.getBytes());
  	}
  
  	public static void printMethodsInEachModificationPoint(ModificationPoint mp) {
  		Map<String, MethodInfo> declaredMethods = mp.getDeclaredMethods();
  		System.out.println("*******************\n");
  		for (String key : declaredMethods.keySet())
  			System.out.println(key);
  		System.out.println("*******************\n");
  	}
  
  	public static void saveProgramVariant(Map<String, String> modifiedJavaSources,
  			Map<String, JavaFileObject> compiledClasses, String srcJavaDir, String binJavaDir,
  			String programVariantOutputDir, int globalID) throws IOException {
  		File srcFile = new File(srcJavaDir);
  		File destSrcFile = new File(programVariantOutputDir, "Variant_" + (globalID) + "/src");
  
  		File binFile = new File(binJavaDir);
  		File destBinFile = new File(programVariantOutputDir, "Variant_" + (globalID) + "/bin");
  
  		FileUtils.copyDirectory(srcFile, destSrcFile);
  		FileUtils.copyDirectory(binFile, destBinFile);
  
  		for (Map.Entry<String, String> entry : modifiedJavaSources.entrySet()) {
  			String sourceFilePath = entry.getKey();
  			URI uri1 = new File(sourceFilePath).toURI();
  			URI uri2 = srcFile.toURI();
  			URI uri3 = uri2.relativize(uri1);
  			File file = new File(destSrcFile, uri3.getPath());
  			FileUtils.writeByteArrayToFile(file, entry.getValue().getBytes());
  		}
  
  		for (Map.Entry<String, JavaFileObject> entry : compiledClasses.entrySet()) {
  			String fullClassName = entry.getKey();
  			String child = fullClassName.replace(".", File.separator) + ".class";
  
  			File file = new File(destBinFile, child);
  			byte[] bytes = ((JavaFileObjectImpl) entry.getValue()).getByteCode();
  			FileUtils.writeByteArrayToFile(file, bytes);
  		}
  	}
  
  	public static void savePatch(List<Integer> opList, List<Integer> locList, List<Integer> ingredList,
  			List<ModificationPoint> modificationPoints, List<List<String>> availableManipulations, String patchDir,
  			int globalID) throws IOException {
  		File file = new File(patchDir, "Patch_" + globalID + ".txt");
  		if (file.exists())
  			file.delete();
  
  		int opId = 0;
  		for (int i = 0; i < locList.size(); i++) {
  			int loc = locList.get(i);
  			int op = opList.get(i);
  			int ingred = ingredList.get(i);
  
  			ModificationPoint mp = modificationPoints.get(loc);
  			int lineNumber = mp.getLCNode().getLineNumber();
  			String sourceFilePath = mp.getSourceFilePath();
  
  			String manipulationName = availableManipulations.get(loc).get(op);
  
  			Statement faulty = mp.getStatement();
  
  			Statement seed = null;
  			if (mp.getIngredients() != null && !mp.getIngredients().isEmpty())
  				seed = mp.getIngredients().get(ingred);
  
  			String data = (++opId) + " " + manipulationName + " " + sourceFilePath + " " + lineNumber + "\n";
  
  			data += "Faulty:\n";
  			data += faulty.toString();
  			data += "Seed:\n";
  			data += (seed == null ? "NULL\n" : seed.toString());
  			data += "**************************************************\n";
  
  			FileUtils.writeByteArrayToFile(file, data.getBytes(), true);
  		}
  	}
  
  	public static void savePatch(List<Integer> opList, List<Integer> locList, List<Integer> ingredList,
  			List<ModificationPoint> modificationPoints, List<List<String>> availableManipulations, String patchDir,
  			int globalID, int evaluations, long estimatedTime) throws IOException {
  		File file = new File(patchDir, "Patch_" + globalID + ".txt");
  		if (file.exists())
  			file.delete();
  
  		int opId = 0;
  		for (int i = 0; i < locList.size(); i++) {
  			int loc = locList.get(i);
  			int op = opList.get(i);
  			int ingred = ingredList.get(i);
  
  			ModificationPoint mp = modificationPoints.get(loc);
  			int lineNumber = mp.getLCNode().getLineNumber();
  			String sourceFilePath = mp.getSourceFilePath();
  
  			String manipulationName = availableManipulations.get(loc).get(op);
  
  			Statement faulty = mp.getStatement();
  
  			Statement seed = null;
  			if (mp.getIngredients() != null && !mp.getIngredients().isEmpty())
  				seed = mp.getIngredients().get(ingred);
  
  			String data = (++opId) + " " + manipulationName + " " + sourceFilePath + " " + lineNumber + "\n";
  
  			data += "Faulty:\n";
  			data += faulty.toString();
  			data += "Seed:\n";
  			data += (seed == null ? "NULL\n" : seed.toString());
  			data += "**************************************************\n";
  
  			FileUtils.writeByteArrayToFile(file, data.getBytes(), true);
  		}
  		String evalInfo = "Evaluations: " + evaluations;
  		String timeInfo = "EstimatedTime: " + estimatedTime;
  		String info = evalInfo + "\n" + timeInfo + "\n";
  		FileUtils.writeByteArrayToFile(file, info.getBytes(), true);
  	}
  
  	public static void savePatch(Solution solution, List<ModificationPoint> modificationPoints,
  			List<List<String>> availableManipulations, List<Map.Entry<Integer, Double>> list, int numberOfEdits,
  			String patchDir, int globalID) throws IOException {
  		int[] var0 = ((ArrayInt) solution.getDecisionVariables()[0]).array_;
  
  		File file = new File(patchDir, "Patch_" + globalID + ".txt");
  		int opId = 0, size = var0.length / 2;
  
  		if (file.exists())
  			file.delete();
  
  		for (int i = 0; i < numberOfEdits; i++) {
  			int id = list.get(i).getKey();
  			ModificationPoint mp = modificationPoints.get(id);
  			int lineNumber = mp.getLCNode().getLineNumber();
  			String sourceFilePath = mp.getSourceFilePath();
  
  			String manipulationName = availableManipulations.get(id).get(var0[id]);
  
  			Statement faulty = mp.getStatement();
  
  			Statement seed = null;
  			if (mp.getIngredients() != null && !mp.getIngredients().isEmpty())
  				seed = mp.getIngredients().get(var0[id + size]);
  
  			String data = (++opId) + " " + manipulationName + " " + sourceFilePath + " " + lineNumber + "\n";
  
  			data += "Faulty:\n";
  			data += faulty.toString();
  			data += "Seed:\n";
  			data += (seed == null ? "NULL\n" : seed.toString());
  			data += "**************************************************\n";
  
  			FileUtils.writeByteArrayToFile(file, data.getBytes(), true);
  		}
  	}
  
  	public static void savePatch(Solution solution, List<ModificationPoint> modificationPoints,
  			String[] manipulationNames, String patchDir, int globalID) throws IOException {
  		int[] var0 = ((ArrayInt) solution.getDecisionVariables()[0]).array_;
  		Binary var1 = (Binary) solution.getDecisionVariables()[1];
  
  		File file = new File(patchDir, "Patch_" + globalID + ".txt");
  		int opId = 0, size = var1.getNumberOfBits();
  
  		if (file.exists())
  			file.delete();
  
  		for (int i = 0; i < size; i++) {
  			if (!var1.getIth(i))
  				continue;
  
  			ModificationPoint mp = modificationPoints.get(i);
  			int lineNumber = mp.getLCNode().getLineNumber();
  			String sourceFilePath = mp.getSourceFilePath();
  
  			String manipulationName = manipulationNames[var0[i]];
  
  			Statement faulty = mp.getStatement();
  
  			Statement seed = mp.getIngredients().get(var0[i + size]);
  
  			String data = (++opId) + " " + manipulationName + " " + sourceFilePath + " " + lineNumber + "\n";
  
  			data += "Faulty:\n";
  			data += faulty.toString();
  			data += "Seed:\n";
  			data += seed.toString();
  			data += "**************************************************\n";
  
  			FileUtils.writeByteArrayToFile(file, data.getBytes(), true);
  		}
  	}
  
  	public static void saveCompiledClasses(Map<String, JavaFileObject> compiledClasses, File binWorkingDirFile)
  			throws IOException {
  		for (Map.Entry<String, JavaFileObject> entry : compiledClasses.entrySet()) {
  			String fullClassName = entry.getKey();
  			String child = fullClassName.replace(".", File.separator) + ".class";
  
  			File file = new File(binWorkingDirFile, child);
  			byte[] bytes = ((JavaFileObjectImpl) entry.getValue()).getByteCode();
  			FileUtils.writeByteArrayToFile(file, bytes);
  		}
  	}
  	
  	
  	public static void savePatch(Map<String, String> modifiedJavaSources, String srcJavaDir,
  			String patchDir, int globalID) throws IOException, InterruptedException {
  		File root = new File(patchDir, "Patch_" + globalID);
  		List<String> diffs = new ArrayList<>();
  		
  		for (Map.Entry<String, String> entry : modifiedJavaSources.entrySet()) {
  			String orgFilePath = entry.getKey();
  			File patched = new File(root, "patched");
  			
  			String relative = new File(srcJavaDir).toURI().relativize(new File(orgFilePath).toURI()).getPath();
  			File revisedFile = new File(patched, relative);
  			FileUtils.writeByteArrayToFile(revisedFile, entry.getValue().getBytes());
  			
  			List<String> diff = getDiff(orgFilePath, revisedFile.getAbsolutePath());
  			diffs.addAll(diff);
  			diffs.add("\n");
  		}
  		
  		FileUtils.writeLines(new File(root, "diff"), diffs);
  	}
  	static List<String> getDiff(String orgFilePath, String revisedFilePath) throws IOException, InterruptedException {
  		List<String> params = new ArrayList<String>();
  		params.add("diff");
  		params.add("-u");
  		params.add(orgFilePath);
  		params.add(revisedFilePath);
  		
  		ProcessBuilder builder = new ProcessBuilder(params);
  		builder.redirectOutput();
  		builder.redirectErrorStream(true);
  		builder.directory();
  
  		Process process = builder.start();
  		
  		BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
  		String line;
  		List<String> lines = new ArrayList<>();
  		while ((line = in.readLine()) != null) {
  		   lines.add(line);
  		}
  		process.waitFor();
  
  		in.close();
  		
  		return lines;
  	}
  
  }
  