package ru.ifmo.testlib;

import ru.ifmo.testlib.verifiers.*;
import ru.ifmo.testlib.io.*;
import static ru.ifmo.testlib.Outcome.Type.*;

import java.io.*;
import java.util.*;

/**
 * The checking framework. Provides possibility to test different solutions by
 * different testers simultaneously.
 */
public class CheckerFramework {
	private static final String USAGE = "Usage: <verifier_classname> <input_file> <output_file> <answer_file> [<result_file> [<test_system_args>]]";

	private static final String DEFAULT_RESULT_ADAPTER = "checker-type:ifmo";

	public static boolean PE_IF_OK_AND_NOT_EOF = true;
	private static HashMap<String, ResultAdapter> resultAdapters = new HashMap<String, ResultAdapter>();

	private static void registerResultAdapter(String id, ResultAdapter v) {
		resultAdapters.put(id, v);
	}

	static {
		registerResultAdapter("checker-type:ifmo", new IFMOResultAdapter());
		registerResultAdapter("checker-type:kitten", new KittenResultAdapter());
		registerResultAdapter("checker-type:ejudge", new EJudgeResultAdapter());
	}

	private static void misusage() {
		System.err.println(USAGE);
		System.exit(3);
	}

	private static void fatal(String message, Object... args) {
		System.err.println(String.format(message, args));
		System.exit(3);
	}

	public static void main(String[] args) {
		if (args.length < 4) {
			misusage();
		}
		// TODO fix verifier -> result adapter
		String verifierClassName = args[0];
		Checker checker = null;
		try {
			checker = (Checker) (Class.forName(verifierClassName).newInstance());
		} catch (InstantiationException e) {
			e.printStackTrace();
			fatal(e.getMessage());
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			fatal(e.getMessage());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			fatal(e.getMessage());
		}

		InputInStream input = new InputInStream(new File(args[1]));
		OutputInStream output = new OutputInStream(new File(args[2]));
		AnswerInStream answer = new AnswerInStream(new File(args[3]));

		PrintWriter result = new PrintWriter(System.out);

		String[] verifierArgs = new String[0];

		if (args.length > 4) {
			try {
				result = new PrintWriter(args[4]);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			verifierArgs = new String[args.length - 5];
			System.arraycopy(args, 5, verifierArgs, 0, verifierArgs.length);
		}

		String verifierType = System.getProperty("checker-type");
		if (verifierType == null) {
			verifierType = DEFAULT_RESULT_ADAPTER;
		}
		if (verifierType.indexOf(':') == -1) {
			verifierType = "checker-type:" + verifierType;
		}

		ResultAdapter resultAdapter = resultAdapters.get(verifierType);

		if (resultAdapter == null) {
			System.err
					.println("No result adapter found (property checker-type = \""
							+ verifierType + "\")");
			System.exit(1);
		}

		resultAdapter.initArgs(verifierArgs);

		Outcome outcome;
		try {
			outcome = checker.test(input, output, answer);
		} catch (Outcome outex) {
			outcome = outex;
		}
		if (outcome.getType() == OK && PE_IF_OK_AND_NOT_EOF
				&& !output.seekEoF()) {
			outcome = new Outcome(PE, "Extra information in output file");
		}
		resultAdapter.printMessage(outcome, result, args.length <= 4);

		result.close();
		input.close();
		output.close();
		answer.close();

		System.exit(resultAdapter.getExitCodeFor(outcome));
	}
}
