package hu.advancedweb.scott.runtime;

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

import org.junit.runner.Description;

import hu.advancedweb.scott.runtime.javasource.MethodSourceLoader;
import hu.advancedweb.scott.runtime.track.LocalVariableState;
import hu.advancedweb.scott.runtime.track.LocalVariableStateRegistry;

/**
 * Renders the pretty-printed report optimized for terminals.
 * 
 * @author David Csakvari
 */
public class FailureRenderer {

	public static String render(Description description, Throwable throwable) {
		// current test source resolving is based on maven conventions
		String testSourcePath = System.getProperty("user.dir") + "/../src/test/java/" + description.getTestClass().getCanonicalName().replace(".", File.separator) + ".java";
		String testMethodName = description.getMethodName();
		
		final ScottReport scottReport = new ScottReport();
		fillSource(scottReport, testSourcePath, testMethodName);
		fillTrackedData(scottReport);
		fillException(scottReport, description, throwable);

		return renderPlain(scottReport);
	}
	
	private static void fillSource(ScottReport scottReport, String testSourcePath, String testMethodName) {
		new MethodSourceLoader(testSourcePath, testMethodName).loadMethodSource(scottReport);
	}
	
	private static void fillTrackedData(ScottReport scottReport) {
		Map<Integer, String> trackedValue = new HashMap<>();
		
		for (LocalVariableState event : LocalVariableStateRegistry.getLocalVariableStates()) {
			String lastValue = trackedValue.get(event.var);
			if (!event.value.equals(lastValue)) {
				scottReport.addVariableSnapshot(event.lineNumber, LocalVariableStateRegistry.getLocalVariableName(event.var, event.lineNumber), event.value);
				trackedValue.put(event.var, event.value);
			}
		}
	}
	
	private static void fillException(ScottReport scottReport, Description description, Throwable throwable) {
		Integer lineNumber = scottReport.getBeginLineNumber();
		for (StackTraceElement stackTraceElement : throwable.getStackTrace()) {
			if (description.getClassName().equals(stackTraceElement.getClassName())) {
				lineNumber = stackTraceElement.getLineNumber();
				break;
			}
		}
		
		scottReport.setException(lineNumber, throwable.getClass().getSimpleName(), throwable.getMessage());
	}
	
	private static String renderPlain(ScottReport scottReport) {
		StringBuilder sb = new StringBuilder();
		sb.append("\n");
		for (Map.Entry<Integer, String> line : scottReport.getSourceLines().entrySet()) {
			int lineNumber = line.getKey();
			String lineText = line.getValue().replaceAll("\t", "    ");
			
			sb.append(String.format("%1$4s", lineNumber));
			if (scottReport.getExceptionLineNumber() == lineNumber) {
				sb.append("|* ");
			} else {
				sb.append("|  ");
			}
			
			sb.append(lineText);
			
			boolean isFirstCommentInThisLine = true;
			for (VariableSnapshot variableSnapshot : scottReport.getVariableSnapshots(lineNumber)) {
				if (!isFirstCommentInThisLine) {
					addBlankLine(sb, lineText);
				}
				
				sb.append("  // ");
				sb.append(variableSnapshot.name);
				sb.append("=");
				sb.append(variableSnapshot.value);
				isFirstCommentInThisLine = false;
			}
			
			if (scottReport.getExceptionLineNumber() == lineNumber) {
				if (!isFirstCommentInThisLine) {
					addBlankLine(sb, lineText);
				}
				sb.append("  // ");
				sb.append(scottReport.getExceptionClassName());
				if (scottReport.getExceptionMessage() != null) {
					sb.append(": ");
					sb.append(scottReport.getExceptionMessage());
				}
			}
			
			sb.append("\n");
		}
		return sb.toString();
	}

	private static void addBlankLine(StringBuilder sb, String lineText) {
		sb.append("\n");
		sb.append("    ");
		sb.append("|  ");
		sb.append(lineText.replaceAll(".", " "));
	}

}

@@ -3316,24 +3316,29 @@
 ext);%0A%09%09%09%09%7D%0A
+%09%09%09%09%0A
 %09%09%09%09sb.appen
@@ -3349,33 +3349,32 @@
  // %22);%0A%09%09%09%09
-sb.append
+%0A%09%09%09%09if 
 (scottReport
@@ -3390,29 +3390,43 @@
 tion
-ClassName());%0A%09%09%09%09if 
+Message() != null) %7B%0A%09%09%09%09%09sb.append
 (sco
@@ -3459,41 +3459,23 @@
 ge()
- != null) %7B%0A%09%09%09%09%09sb.append(%22: %22);
+);%0A%09%09%09%09%7D else %7B
 %0A%09%09%09
@@ -3502,38 +3502,40 @@
 ort.getException
-Messag
+ClassNam
 e());%0A%09%09%09%09%7D%0A%09%09%09%7D

modify exception class reporting