import java.io.IOException;
import java.util.TreeMap;

/*import org.eclipse.markfactory.annotations.CheckAPI;
import org.eclipse.markfactory.annotations.ExamExercise;
import org.eclipse.markfactory.annotations.ExamTest;
*/
import calc.CellId;
import calc.MalformedFormulaException;
import calc.Sheet;
import calc.cell.Cell;
import calc.cell.FormulaCell;
import calc.cell.IntegerCell;

//@ExamTest
public class Main {

	private static int points = 0;

	//@ExamExercise
	public static void main(String[] args) throws IOException {

		System.out.println("A teszteles megkezdodott");

		Sheet emptySheet = testSheet();
		Cell dummyCell = testCell(emptySheet);
		testIntegerCell(emptySheet);
		testEvaluatable(emptySheet, dummyCell);
		testCellId();
		testSheetExtended();
		Sheet formulaSheet = testFormulaCell();
		testMalformedFormulaException(formulaSheet);
		testLoadFromFile();
		
		System.out.println("A publikus metodusok ellenorzese...");
		if (!testAPI()) {
			points -= 5;
		}

		System.out.println("A teszteles lezarult.");
		System.out.println("Pontszam: " + points + "/45");
		if (points <= 11)
			System.out.println("Jegy: 1 (elegtelen)");
		else if (points <= 20)
			System.out.println("Jegy: 2 (elegseges)");
		else if (points <= 28)
			System.out.println("Jegy: 3 (kozepes)");
		else if (points <= 35)
			System.out.println("Jegy: 4 (jo)");
		else
			System.out.println("Jegy: 5 (jeles)");
	}

	/*@CheckAPI(checkedClasses = { "calc.CellId", "calc.MalformedFormulaException",
			"calc.Sheet", "calc.cell.Cell", "calc.cell.IntegerCell",
			"calc.cell.FormulaCell", "calc.eval.Evaluatable" })*/
	private static boolean testAPI() {
		// this method will test the public methods and fields of the classes
		// created for the exam
		return true;
	}

	private static void errMsg(String msg) {
		System.err.println(msg);
		System.err.flush();
	}

	//@ExamExercise
	private static Sheet testSheet() {
		System.out.println("Sheet tesztelese");
		Sheet sheet = new Sheet(new TreeMap<CellId, Cell>());
		points += 1;
		System.out.println("... sikeres");
		return sheet;
	}

	//@ExamExercise
	private static Cell testCell(Sheet sheet) {
		System.out.println("Cell tesztelese");
		Cell dummy = new DummyCell(sheet);
		points += 3;
		System.out.println("... sikeres");
		return dummy;
	}

	//@ExamExercise
	private static void testIntegerCell(Sheet sheet) {
		System.out.println("IntegerCell tesztelese");
		Cell intCell = new IntegerCell(sheet);
		points += 1;
		String intCellWrongValMsg = "intCell.edit(\"%s\"); kiadasa utan "
				+ "az IntegerCell show fuggvenyenek eredmenye nem \"%s\"";
		String[] cellNumbers = { "42", "0", "-600" };
		for (String cellNum : cellNumbers) {
			intCell.edit(cellNum);
			if (!intCell.show().equals(cellNum)) {
				errMsg(String.format(intCellWrongValMsg, cellNum));
				return;
			}
		}
		points += 3;
		System.out.println("... sikeres");
	}

	//@ExamExercise
	private static void testEvaluatable(Sheet emptySheet, Cell dummyCell) {
		System.out.println("Evaluatable tesztelese");
		new DummyEvaluatable<Integer>();
		new DummyEvaluatable<Boolean>();
		points += 3;
		Integer dummyVal = dummyCell.eval();
		points += 1;
		Cell cell = new IntegerCell(emptySheet);
		cell.edit("36");
		if (!cell.eval().equals(36)) {
			errMsg("Cell.eval() nem a megfelelo eredmenyt adja");
			return;
		}
		points += 1;
		System.out.println("... sikeres");
	}

	//@ExamExercise
	private static void testCellId() {
		System.out.println("CellId tesztelese");
		CellId a1 = new CellId('A', 1);
		CellId a1_ = new CellId('A', 1);
		CellId a2 = new CellId('A', 2);
		CellId b1 = new CellId('B', 1);
		points += 1;
		testCellIdFromString();
		testCellIdEquals(a1, a1_, a2, b1);
		testCellIdHashCode(a1, a1_, a2, b1);
		testCellIdCompareTo(a1, a1_, a2, b1);
		System.out.println("... sikeres");
	}

	//@ExamExercise
	private static void testCellIdFromString() {
		if (null == CellId.fromString("A4")
				|| null == CellId.fromString("Q1024")) {
			errMsg("CellId.fromString null-t ad helyes CellId-k eseten.");
			return;
		}
		points += 1;
		if (null != CellId.fromString("A") || null != CellId.fromString("42")) {
			errMsg("CellId.fromString nem ad null-t hibas CellId-k eseten.");
			return;
		}
		points += 1;
	}

	//@ExamExercise
	private static void testCellIdCompareTo(CellId a1, CellId a1_, CellId a2,
			CellId b1) {
		System.out.println("  CellId.compareTo tesztelese");
		if (a1.compareTo(a1) != 0 || a1.compareTo(a1_) != 0) {
			errMsg("CellId.compareTo nem ad 0-t azonos id-k eseten.");
			return;
		}
		if (Math.signum(a1.compareTo(a2)) != -Math.signum(a2.compareTo(a1))
				|| Math.signum(a1.compareTo(b1)) != -Math.signum(b1
						.compareTo(a1))) {
			errMsg("CellId.compareTo nem antiszimmetrikus.");
			return;
		}
		points += 2;
		System.out.println("  ... sikeres");
	}

	//@ExamExercise
	private static void testCellIdHashCode(CellId a1, CellId a1_, CellId a2,
			CellId b1) {
		System.out.println("  CellId.hashCode tesztelese");
		if (a1.hashCode() != a1_.hashCode()) {
			errMsg("CellId.hashCode() nem ad azonos hash kodot megegyezo CellId-k eseten.");
			return;
		}
		points += 1;
		if (a1.hashCode() == a2.hashCode() && a1.hashCode() == b1.hashCode()) {
			errMsg("CellId.hashCode() indokolatlanul ad azonos hash kodot eltero objektumok eseten.");
			return;
		}
		points += 1;
		System.out.println("  ... sikeres");
	}

	//@ExamExercise
	private static void testCellIdEquals(CellId a1, CellId a1_, CellId a2,
			CellId b1) {
		System.out.println("  CellId.equals tesztelese");
		if (!a1.equals(a1_) || !a1_.equals(a1) || !a1.equals(a1)
				|| !a1_.equals(a1_)) {
			errMsg("CellId.equals hamisat ad vissza azonos id-k eseten.");
		}
		if (a1.equals(a2) || a2.equals(a1) || b1.equals(a1) || a1.equals(b1)) {
			errMsg("CellId.equals igazat ad vissza eltero id-k eseten.");
		}
		points += 1;
		if (a1.equals(null)) {
			errMsg("CellId.equals igazat ad vissza null eseten.");
			return;
		}
		points += 1;
		if (a1.equals(new Object())) {
			errMsg("CellId.equals igazat ad vissza nem CellId parameter eseten.");
			return;
		}
		points += 1;
		System.out.println("  ... sikeres");
	}

	//@ExamExercise
	private static void testSheetExtended() {
		System.out.println("Sheet.getCell tesztelese");
		TreeMap<CellId, Cell> cells = new TreeMap<>();
		Sheet sheet = new Sheet(cells);
		IntegerCell cell1, cell2;
		cells.put(new CellId('A', 3), cell1 = new IntegerCell(sheet));
		cells.put(new CellId('B', 5), cell2 = new IntegerCell(sheet));
		if (!sheet.getCell(new CellId('A', 3)).equals(cell1)
				|| !sheet.getCell(new CellId('B', 5)).equals(cell2)) {
			errMsg("Sheet.getCell nem a megfelelo cellat adja vissza.");
			return;
		}
		points += 2;
		System.out.println("... sikeres");
	}

	//@ExamExercise
	private static Sheet testFormulaCell() {
		System.out.println("FormulaCell tesztelese");
		TreeMap<CellId, Cell> cells = new TreeMap<>();
		Sheet sheet = new Sheet(cells);
		FormulaCell formulaCell = new FormulaCell(sheet);
		points += 1;
		formulaCell.edit("=A1+A2+A3");
		cells.put(new CellId('B', 1), formulaCell);
		IntegerCell intCell1, intCell2, intCell3;
		cells.put(new CellId('A', 1), intCell1 = new IntegerCell(sheet));
		cells.put(new CellId('A', 2), intCell2 = new IntegerCell(sheet));
		cells.put(new CellId('A', 3), intCell3 = new IntegerCell(sheet));
		intCell1.edit("1");
		intCell2.edit("2");
		intCell3.edit("3");
		if (!formulaCell.eval().equals(6)) {
			errMsg("A FormulaCell.eval nem a megfelelo eredmenyt adja.");
			return sheet;
		}
		points += 5;
		if (!formulaCell.show().equals("6")) {
			errMsg("A FormulaCell.show nem a megfelelo eredmenyt adja.");
			return sheet;
		}
		points += 1;
		System.out.println("... sikeres");
		return sheet;
	}

	//@ExamExercise
	private static void testMalformedFormulaException(Sheet sheet) {
		System.out.println("MalformedFormulaException tesztelese");
		MalformedFormulaException e = new MalformedFormulaException(
				"This is stupid", "=/%");
		IllegalArgumentException iae = e;
		points += 1;
		if (!e.getFormula().equals("=/%")
				|| !e.getProblem().equals("This is stupid")) {
			errMsg("A MalformedFormulaException getterei nem mukodnek megfeleloen.");
			return;
		}
		points += 1;
		if (!e.getMessage().equals("This is stupid, in formula: =/%")) {
			String msg = "A MalformedFormulaException getMessage fuggvenye nem a megfelelo formatumu: elvart: \"%s\", kapott: \"%s\".";
			errMsg(String
					.format(msg, "This is stupid, in: =/%", e.getMessage()));
			return;
		}

		points += 1;
		Cell formulaCell = sheet.getCell(new CellId('B', 1));
		try {
			formulaCell.edit("A1+A2+A3");
			errMsg("FormulaCell.edit: Nem szarmazott kivetel az egyenlosegjel nelkuli formula beirasabol");
			return;
		} catch (MalformedFormulaException mfe) {
			if (!mfe.getProblem().equals("Formula must start with a = sign")) {
				errMsg("FormulaCell.edit: Rossz hibauzenet az egyenlosegjel nelkuli formula beirasabol");
				return;
			} else {
				points += 1;
			}
		}

		try {
			formulaCell.edit("=1+A2+A3");
			errMsg("FormulaCell.edit: Nem szarmazott kivetel a hibas cellaazonosito beirasabol");
			return;
		} catch (MalformedFormulaException mfe) {
			if (!mfe.getProblem().equals("Invalid cell reference")) {
				errMsg("FormulaCell.edit: Rossz hibauzenet a hibas cellaazonosito beirasabol");
				return;
			} else {
				points += 2;
			}
		}
		System.out.println("... sikeres");
	}

	//@ExamExercise
	private static void testLoadFromFile() throws IOException {
		System.out.println("Sheet.loadFromFile tesztelese");
		Sheet sheet = Sheet.loadFromFile("proba.csv");
		if (sheet == null) {
			errMsg("Sheet.loadFromFile: Letezo fajl eseten is null az eredmeny.");
			return;
		}
		Cell intCell1 = sheet.getCell(new CellId('A', 1));
		Cell intCell2 = sheet.getCell(new CellId('A', 2));
		Cell intCell3 = sheet.getCell(new CellId('A', 3));
		Cell formCell1 = sheet.getCell(new CellId('B', 1));

		points += 2;
		//System.out.println(intCell1.show());
		//System.out.println(intCell2.show());
		//System.out.println(intCell3.show());
		//System.out.println(formCell1.show());
		if (!intCell1.show().equals("1") || !intCell2.show().equals("2")
				|| !intCell3.show().equals("3")) {
			errMsg("Sheet.loadFromFile: Az egesz erteku cellak nem jol toltodnek be.");
			return;
		}
		points += 2;
		if (!formCell1.show().equals("6")) {
			errMsg("Sheet.loadFromFile: A formula cellak nem jol toltodnek be.");
			return;
		}
		points += 2;
		if (null != Sheet.loadFromFile("nincsilyen.csv")) {
			errMsg("Sheet.loadFromFile: Nem letezo fajl eseten az eredmeny legyen null.");
			return;
		}
		points += 1;
		System.out.println("... sikeres");
	}

}
