package ui.controller;

import java.awt.Point;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ListIterator;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import classes.Category;
import classes.CpsEdge;
import classes.AbstractCpsObject;
import classes.HolonElement;
import classes.HolonObject;
import classes.HolonSwitch;
import classes.HolonTransformer;
import classes.IdCounter;
import ui.model.Model;

/**
 * Controller for Storage.
 * 
 * @author Gruppe14
 */
public class StoreController {

	private Model model;

	/**
	 * Constructor.
	 * 
	 * @param model
	 *            the Model
	 */
	public StoreController(Model model) {
		this.model = model;

	}

	/**
	 * Writes the current State of the Modelling into a JSON File which can be
	 * loaded.
	 * 
	 * @param path
	 *            the Path
	 * 
	 * @throws IOException
	 *             exception
	 */
	public void writeSaveFile(String path) throws IOException {

		JSONObject json = new JSONObject();

		json.put("MODE", "ALL");
		json.put("ID", IdCounter.getCounter());
		json.put("SIZEX", model.getCanvasX());
		json.put("SIZEY", model.getCanvasY());
		writeCategory(json);
		writeCategoryObjects(json);
		writeCanvasObjects(json);
		writeCategoryElements(json);
		writeCanvasElements(json);
		writeEdges(json);
		writeElementGraph(json);

		FileWriter writer = new FileWriter(path);
		writer.write(json.toJSONString());
		getClass();

		writer.flush();
		writer.close();
	}

	/**
	 * Write the Canvas File.
	 * 
	 * @param path
	 *            the Path
	 * @throws IOException
	 *             Exception
	 */
	public void writeCanvasFile(String path) throws IOException {

		JSONObject json = new JSONObject();

		json.put("MODE", "CANVAS");
		json.put("ID", IdCounter.getCounter());
		writeCanvasObjects(json);
		writeCanvasElements(json);
		writeEdges(json);
		writeElementGraph(json);

		FileWriter writer = new FileWriter(path);
		writer.write(json.toJSONString());
		getClass();

		writer.flush();
		writer.close();
	}

	/**
	 * Write the Category File.
	 * 
	 * @param path
	 *            the Path
	 * @throws IOException
	 *             exception
	 */
	public void writeCategoryFile(String path) throws IOException {

		JSONObject json = new JSONObject();

		json.put("MODE", "CATEGORY");
		// eventuell muss man ID auch Speichern
		writeCategory(json);
		writeCategoryObjects(json);
		writeCategoryElements(json);

		FileWriter writer = new FileWriter(path);
		writer.write(json.toJSONString());
		getClass();

		writer.flush();
		writer.close();
	}

	/**
	 * writes all Categories into a JSONObject.
	 * 
	 * @param json
	 *            JSON Object
	 * @throws IOException
	 *             exception
	 */
	public void writeCategory(JSONObject json) {
		JSONArray arr = new JSONArray();

		for (Category cat : model.getCategories())
			arr.add(cat.getName());

		json.put("CG", arr);
	}

	/**
	 * writes all Objects in Category into a JSONObject.
	 * 
	 * @param json
	 *            JSON Object
	 */
	public void writeCategoryObjects(JSONObject json) {

		JSONArray arr = new JSONArray();
		int i = 1;

		for (Category cats : model.getCategories())
			for (AbstractCpsObject cps : cats.getObjects()) {
				arr.add(getObjectType(cps));
				arr.add(cps.getSav());
				arr.add(cps.getObjName());
				arr.add(cps.getImage());
				json.put("CGO" + i++, arr);
				arr = new JSONArray();
			}
	}

	/**
	 * Wrte Canvas Objects.
	 * 
	 * @param json
	 *            JSON Object
	 */
	public void writeCanvasObjects(JSONObject json) {

		JSONArray arr = new JSONArray();
		int i = 1;
		for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
			arr.add(getObjectType(cps));
			arr.add(cps.getObjName());
			arr.add(cps.getName());
			arr.add(cps.getID());
			arr.add(cps.getImage());
			arr.add(cps.getPosition().x);
			arr.add(cps.getPosition().y);
			json.put("CVSO" + i++, arr);
			arr = new JSONArray();
		}
	}

	/**
	 * writes all Elements in Objects in Category into a JSONObject.
	 * 
	 * @param json
	 *            JSON Object
	 */
	public void writeCategoryElements(JSONObject json) {

		JSONArray arr = new JSONArray();
		int i = 1;

		for (Category cats : model.getCategories())
			for (AbstractCpsObject cps : cats.getObjects())
				if (cps instanceof HolonObject)
					for (HolonElement ele : ((HolonObject) cps).getElements()) {
						arr.add(ele.getSav());
						arr.add(ele.getObj());
						arr.add(ele.getEleName());
						arr.add(ele.getAmount());
						arr.add(ele.getEnergy());
						json.put("CGE" + i++, arr);
						arr = new JSONArray();
					}

	}

	/**
	 * Write Canvas Elements.
	 * 
	 * @param json JSON Objects
	 */
	public void writeCanvasElements(JSONObject json) {

		JSONArray arr = new JSONArray();
		int i = 1;
		for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
			if (cps instanceof HolonObject)
				for (HolonElement ele : ((HolonObject) cps).getElements()) {
					arr.add(ele.getSav());
					arr.add(cps.getID());
					arr.add(ele.getEleName());
					arr.add(ele.getAmount());
					arr.add(ele.getEnergy());
					arr.add(Boolean.compare(ele.getActive(), true) + 1);
					json.put("CVSE" + i++, arr);
					arr = new JSONArray();
				}
		}
	}

	/**
	 * write all Edges into a JSONObject.
	 * 
	 * @param json JSON Object
	 */
	public void writeEdges(JSONObject json) {

		JSONArray arr = new JSONArray();
		int i = 1;

		for (CpsEdge edge : model.getEdgesOnCanvas()) {
			arr.add(edge.getA().getID());
			arr.add(edge.getB().getID());
			arr.add(edge.getCapacity());
			arr.add(edge.getFlow());
			json.put("EDGE" + i++, arr);
			arr = new JSONArray();
		}
	}

	/**
	 * writes the Graph from all Elements into a JSONObject.
	 * 
	 * @param json JSON Object
	 */
	public void writeElementGraph(JSONObject json) {

		ListIterator<Point> iterator;
		JSONArray arr = new JSONArray();
		int i = 1;

		for (Category cats : model.getCategories())
			for (AbstractCpsObject cps : cats.getObjects())
				if (cps instanceof HolonObject)
					for (HolonElement ele : ((HolonObject) cps).getElements())
						if (!ele.getGraphPoints().isEmpty()) {
							iterator = ele.getGraphPoints().listIterator();

							arr.add(ele.getSav());
							arr.add(ele.getObj());
							arr.add(ele.getEleName());

							while (iterator.hasNext()) {
								Point p = iterator.next();
								arr.add((int) p.getX());
								arr.add((int) p.getY());
							}
							json.put("CGGP" + i++, arr);
							arr = new JSONArray();
						}
		i = 1;
		for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
			if (cps instanceof HolonObject)
				for (HolonElement ele : ((HolonObject) cps).getElements())
					if (!ele.getGraphPoints().isEmpty()) {
						iterator = ele.getGraphPoints().listIterator();

						arr.add(ele.getSav());
						arr.add(cps.getID());
						arr.add(ele.getEleName());

						while (iterator.hasNext()) {
							Point p = iterator.next();
							arr.add((int) p.getX());
							arr.add((int) p.getY());
						}
						json.put("CVSGP" + i++, arr);
						arr = new JSONArray();
					}
		}
	}

	/**
	 * Return the Object Type.
	 * 
	 * @param cps AbstractCpsObject
	 * @return The Object Type
	 */
	public String getObjectType(AbstractCpsObject cps) {
		if (cps instanceof HolonObject)
			return "HolonObject";
		if (cps instanceof HolonTransformer)
			return "HolonTransformer";
		if (cps instanceof HolonSwitch)
			return "HolonSwitch";
		else
			return "CpsNode";
	}

}