package tests;

import java.awt.Point;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;

import org.junit.Before;
import org.junit.Test;
import classes.Category;
import classes.CpsEdge;

import classes.AbstractCpsObject;

import classes.HolonElement;
import classes.HolonObject;
import classes.HolonSwitch;
import classes.IdCounter;

import static org.junit.Assert.assertTrue;

import ui.controller.CanvasController;
import ui.controller.CategoryController;
import ui.controller.GlobalController;
import ui.controller.LoadController;
import ui.controller.MultiPurposeController;
import ui.controller.ObjectController;
import ui.controller.StoreController;
import ui.model.Model;
import ui.view.UnitGraph;

/**
 * Tests for LoadAndStoreController.
 * 
 * @author Gruppe14
 */
public class PraktikumHolonsTestLoadAndStoreController {

	protected PraktikumHolonsAdapter adapter;
	protected Model model;
	protected MultiPurposeController mp;
	protected CategoryController cg;
	protected CanvasController cvs;
	protected ObjectController obj;
	protected GlobalController global;
	protected StoreController storeController;
	protected LoadController loadController;
	protected IdCounter id;
	protected String path = System.getProperty("user.home") + "/HolonGUI/Test/";

	/**
	 * Setup for the Tests.
	 */
	@Before
	public void setUp() {
		adapter = new PraktikumHolonsAdapter();
		model = new Model();
		mp = new MultiPurposeController(model);
		cg = new CategoryController(model, mp);
		cvs = new CanvasController(model, mp);
		obj = new ObjectController(model, mp);
		storeController = new StoreController(model);
		loadController = new LoadController(model, cg, cvs, obj, global, mp);
		// cg.initCategories();
		// obj.initHolonElements();
		File file = new File(path);
		file.mkdirs();
	}

	/**
	 * minimal tests for saving.
	 */
	@Test
	public void testStoreMinimal() {
		try {
			File sav = new File(path + "TestSavMinimal.json");
			storeController.writeSaveFile(sav.getAbsolutePath());
			assertTrue("Save File was not created", new File(path + "TestSavMinimal.json").exists());

			File cat = new File(path + "TestCategoryMinimal.json");
			storeController.writeCategoryFile(cat.getAbsolutePath());
			assertTrue("Category File was not created", new File(path + "TestCategoryMinimal.json").exists());

			File canvas = new File(path + "TestCanvasMinimal.json");
			storeController.writeCanvasFile(canvas.getAbsolutePath());
			assertTrue("Canvas File was not created", new File(path + "TestCanvasMinimal.json").exists());

			assertTrue("Non Existant File exist", !new File(path + "TestDummyMinimal.json").exists());

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * basic tests for saving.
	 */
	@Test
	public void testStoreBasic() {

		for (int i = 1; i <= 26; i++) {
			cg.addNewCategory(adapter.generate(i));
			assertTrue("Number of Categories does not match", model.getCategories().size() == i + 3);
			assertTrue("Category was not created", mp.searchCat(adapter.generate(i)) != null);
			for (int j = 1; j <= 10; j++) {
				cg.addNewHolonObject(mp.searchCat(adapter.generate(i)), adapter.generate(j),
						new ArrayList<HolonElement>(), "");
				assertTrue("Number of Objects does not match",
						mp.searchCat(adapter.generate(i)).getObjects().size() == j);
				assertTrue("Object was not created", mp.searchCat(adapter.generate(i)).getObjects().get(j - 1) != null);
			}
		}

		// here some Objects were dropped on the canvas
		for (int i = 1; i <= 10; i++) {
			cvs.addNewObject(new HolonObject(mp.searchCatObj(mp.searchCat("Building"), "House")));
			assertTrue("Size of Objects on Canvas does not match", model.getObjectsOnCanvas().size() == i);
			assertTrue("Object was not added", model.getObjectsOnCanvas().get(i - 1) != null
					&& model.getObjectsOnCanvas().get(i - 1).getObjName().equals("House"));
		}

		HolonSwitch sw = new HolonSwitch(mp.searchCatObj(mp.searchCat("Component"), "Switch"));
		sw.setPosition(77, 88);
		cvs.addNewObject(sw);

		try {
			File sav = new File(path + "TestSavBasic.json");
			storeController.writeSaveFile(sav.getAbsolutePath());
			assertTrue("Save File was not created", new File(path + "TestSavBasic.json").exists());

			File canvas = new File(path + "TestCanvasBasic.json");
			storeController.writeCanvasFile(canvas.getAbsolutePath());
			assertTrue("Canvas File was not created", new File(path + "TestCanvasBasic.json").exists());

			assertTrue("Non Existant File exist", !new File(path + "TestDummyMinimal.json").exists());

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * advanced tests for saving.
	 */
	@Test
	public void testStoreAdvanced() {

		setGraphPoints((HolonObject) mp.searchCatObj(mp.searchCat("Building"), "House"));

		int n = 0;
		for (int i = 0; i < 10; i++) {
			for (int j = 0; j < 10; j++) {
				HolonObject h = new HolonObject(mp.searchCatObj(mp.searchCat("Building"), "House"));
				h.setPosition(j * 50, i * 50);
				cvs.addNewObject(h);
				setGraphPoints(h);
				for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
					if (!cps.equals(h))
						cvs.addEdgeOnCanvas(new CpsEdge(h, cps));
				}

				// vollständiger Graph
				n = model.getObjectsOnCanvas().size();
				assertTrue("Number of Edges does not Match", model.getEdgesOnCanvas().size() == (n * (n - 1)) / 2);
			}
		}

		try {
			File sav = new File(path + "TestSavAdvanced.json");
			storeController.writeSaveFile(sav.getAbsolutePath());
			assertTrue("Save File was not created", new File(path + "TestSavAdvanced.json").exists());

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * minimal tests for loading a save file.
	 */
	@Test
	public void testLoadMinimal() {
		try {
			// Category Tests
			Category building = mp.searchCat("Building");
			assertTrue("Number of Categories does not match", model.getCategories().size() == 3);
			assertTrue("TestFile was not found", new File(path + "TestCategoryMinimal.json").exists());
			loadController.readJson(path + "TestCategoryMinimal.json");
			assertTrue("Number of Categories does not match", model.getCategories().size() == 3);
			// Tests if its same instance and if Name is the same
			assertTrue("Same instance of Category:Building", building != mp.searchCat("Building")
					&& building.getName().equals(mp.searchCat("Building").getName()));

			// Canvas Tests.. basically nothing happens because nothing is on
			// the Canvas
			assertTrue("Number of Objects on Canvas does not match", model.getObjectsOnCanvas().size() == 0);
			assertTrue("TestFile was not found", new File(path + "TestCanvasMinimal.json").exists());
			loadController.readJson(path + "TestCanvasMinimal.json");
			assertTrue("Number of Objects on Canvas does not match", model.getObjectsOnCanvas().size() == 0);

			// Save File tests basically both Test from Above Combined
			building = mp.searchCat("Building");
			assertTrue("Number of Objects in Energy does not Match", mp.searchCat("Energy").getObjects().size() == 1);
			assertTrue("TestFile was not found", new File(path + "TestSavMinimal.json").exists());
			loadController.readJson(path + "TestSavMinimal.json");
			assertTrue("Number of Objects in Energy does not Match", mp.searchCat("Energy").getObjects().size() == 1);
			assertTrue("Number of Objects on Canvas does not match", model.getObjectsOnCanvas().size() == 0);
			assertTrue("Same instance of Category:Building", building != mp.searchCat("Building")
					&& building.getName().equals(mp.searchCat("Building").getName()));

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * basic tests for loading a save file.
	 */
	@Test
	public void testLoadBasic() {
		assertTrue("Non-Existant Category Exists", mp.searchCat("J") == null);
		assertTrue("Non-Existant Category Exists", mp.searchCat("U") == null);
		assertTrue("Non-Existant Category Exists", mp.searchCat("L") == null);
		assertTrue("Non-Existant Category Exists", mp.searchCat("I") == null);
		assertTrue("Non-Existant Category Exists", mp.searchCat("A") == null);
		assertTrue("Non-Existant Category Exists", mp.searchCat("N") == null);

		try {
			assertTrue("Objects on Canvas is not 0", model.getObjectsOnCanvas().size() == 0);
			assertTrue("Canvas File was not found", new File(path + "TestCanvasBasic.json").exists());
			loadController.readJson(path + "TestCanvasBasic.json");

			assertTrue("NUmber of Objects on Canvas does not match", model.getObjectsOnCanvas().size() == 11);
			for (AbstractCpsObject obj : model.getObjectsOnCanvas()) {
				assertTrue("Not instance of HolonObject", obj instanceof HolonObject || obj instanceof HolonSwitch);

			}

			assertTrue("NUmber of Categories not match", model.getCategories().size() == 3);
			assertTrue("Canvas File was not found", new File(path + "TestSavBasic.json").exists());
			loadController.readJson(path + "TestSavBasic.json");
			assertTrue("NUmber of Categories not match", model.getCategories().size() == 29);
			assertTrue("Existant Category dont Exists", mp.searchCat("J") != null);
			assertTrue("Existant Category dont Exists", mp.searchCat("U") != null);
			assertTrue("Existant Category dont Exists", mp.searchCat("L") != null);
			assertTrue("Existant Category dont Exists", mp.searchCat("I") != null);
			assertTrue("Existant Category dont Exists", mp.searchCat("A") != null);
			assertTrue("Existant Category dont Exists", mp.searchCat("N") != null);
			assertTrue("Existant Object dont Exists", mp.searchCatObj(mp.searchCat("Z"), "A") != null);
			assertTrue("Existant Object dont Exists", mp.searchCatObj(mp.searchCat("Z"), "B") != null);
			assertTrue("Existant Object dont Exists", mp.searchCatObj(mp.searchCat("Z"), "C") != null);
			assertTrue("Existant Object dont Exists", mp.searchCatObj(mp.searchCat("Z"), "D") != null);
			assertTrue("Existant Object dont Exists", mp.searchCatObj(mp.searchCat("Z"), "E") != null);
			assertTrue("Existant Object dont Exists", mp.searchCatObj(mp.searchCat("Z"), "F") != null);

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * advanced tests for loading a save file.
	 */
	@Test
	public void testLoadAdvanced() {

		try {
			assertTrue("Objects on Canvas is not 0", model.getObjectsOnCanvas().size() == 0);
			assertTrue("Save File was not found", new File(path + "TestSavAdvanced.json").exists());
			loadController.readJson(path + "TestSavAdvanced.json");
			assertTrue("Objects on Canvas is not 100", model.getObjectsOnCanvas().size() == 100);

			int n = model.getObjectsOnCanvas().size();
			assertTrue("Number of Edges does not Match", model.getEdgesOnCanvas().size() == (n * (n - 1)) / 2);
			assertTrue("Element has no UnitGraph", !mp
					.searchEle((HolonObject) model.getObjectsOnCanvas().get(77), "Fridge").getGraphPoints().isEmpty());
			assertTrue("Points in UnitGraph does not Match",
					mp.searchEle((HolonObject) model.getObjectsOnCanvas().get(77), "Fridge").getGraphPoints()
							.size() == 3);

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Test for FileNotFound.
	 * 
	 * @throws IOException
	 *             FileNotFoundException
	 */
	@Test(expected = FileNotFoundException.class)
	public void testLoadException() throws IOException {
		assertTrue("Save File was not found", !new File(path + "TestSavDummy.json").exists());
		loadController.readJson(path + "TestSavDummy.json");
	}

	/**
	 * sets the graph points in all elements of an Object.
	 * 
	 * @param obj
	 *            the Object
	 */
	public void setGraphPoints(HolonObject obj) {
		LinkedList<Point> list = new LinkedList<>();
		list.add(new Point(0, 0));
		list.add(new Point(125, 50));
		list.add(new Point(249, 0));
		UnitGraph u = new UnitGraph(model, null);
		u.repaintWithNewElement(obj.getElements());
		u.fillArrayofValue();
		for (HolonElement ele : obj.getElements()) {
			ele.setGraphPoints(list);
		}

	}
}
