package cz.vutbr.feec.libraryClasses;

import java.util.LinkedList;
import java.util.Vector;

import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import cz.vutbr.feec.graph.Path;
import cz.vutbr.feec.graph.Router;
import cz.vutbr.feec.gui.AccidentCanvas;
import cz.vutbr.feec.gui.ControllerInitializeGui;
import cz.vutbr.feec.gui.OtherCanvas;
import cz.vutbr.feec.gui.ReckCanvas;
import cz.vutbr.feec.project.Edit;
import cz.vutbr.feec.project.GlobalParameters;
import cz.vutbr.feec.stockElements.AbstractStockCell;
import cz.vutbr.feec.stockElements.AccidentCell;
import cz.vutbr.feec.stockElements.BorderCell;
import cz.vutbr.feec.stockElements.CoridorCell;
import cz.vutbr.feec.stockElements.RackCell;
import cz.vutbr.feec.stockElements.RouterCell;
import cz.vutbr.feec.stockElements.Stock;
import cz.vutbr.feec.stockElements.routeInStockSearching;
import cz.vutbr.feec.transportObjects.DrawnPathCrate;

public class GuiPainting {

	private static Stock stock = Stock.getInstance();
	public static int selectedRoute = -1;

	private GuiPainting() {
		// soukromy bezparametricky konstruktor
	}

	public static void createReckCanvas(Canvas canvas) {

		ReckCanvas rc = new ReckCanvas(canvas);
		GlobalParameters.reckCanvas = rc;
	}

	public static void createAccidentCanvas(Canvas canvas) {

		AccidentCanvas rc = new AccidentCanvas(canvas);
		GlobalParameters.accidentCanvas = rc;
	}

	public static void createZoomedCanvas() {
		Canvas canvas = GlobalParameters.mainCanvas;
		GraphicsContext gc = GlobalParameters.gc;
		// Color color = GlobalParameters.backgroundColor;
		float widthCurrent = (float) (stock.getLength() * cz.vutbr.feec.gui.ControllerInitializeGui
				.getZoomRatio());
		float heightCurrent = (float) (stock.getWidth() * cz.vutbr.feec.gui.ControllerInitializeGui
				.getZoomRatio());
		canvas.setWidth(widthCurrent);
		canvas.setHeight(heightCurrent);

		gc.clearRect(0, 0, widthCurrent, heightCurrent);
		/*
		 * gc.setFill(color); gc.fillRect(0, 0, widthCurrent, heightCurrent);
		 */

		// vyplnit regale farbou regalu

		AbstractStockCell[][] pole = stock.getField();
		int x = (int) ((stock.getLength() / stock.getDelimiter()));
		int y = (int) ((stock.getWidth() / stock.getDelimiter()));

		for (int i = 0; i < x; i++) {
			for (int j = 0; j < y; j++) {
				if (pole[i][j].getClass() == RackCell.class) {
					/*
					 * GuiPainting.drawInFieldCell(canvas, gc,
					 * GlobalParameters.reckColor,
					 * GuiMethods.getFieldFromIndexX(i),
					 * GuiMethods.getFieldFromIndexY(j));
					 */
					Image image;
					RackCell rc = (RackCell) pole[i][j];
					// zalezi ci bol vytvoreny ako rotated, tak musim zmenit
					// obrazok
					if (rc.isRotated()) {
						image = GlobalParameters.reckRotatedImage;
					} else {
						image = GlobalParameters.reckImage;
					}
					GuiPainting.drawImage(image,
							GuiMethods.getFieldFromIndexX(i),
							GuiMethods.getFieldFromIndexY(j));
				} else if (pole[i][j].getClass() == BorderCell.class) {
					// pokial je nastaveny nejaky obrazok tak ho vykreslim
					BorderCell bc = (BorderCell) pole[i][j];
					Image image;
					if (bc.isImage()) {
						image = bc.getImage();

						GuiPainting.drawImage(image,
								GuiMethods.getFieldFromIndexX(i),
								GuiMethods.getFieldFromIndexY(j));
					}
					// pozriet ci je zapnute pravitko
					if (GlobalParameters.meterButton.isSelected())
						createBorderCells(canvas, gc, i, j);

				}/* else if (pole[i][j].getClass() == AccidentCell.class) {
					/*
					 * GuiPainting.drawInFieldCell(canvas, gc,
					 * GlobalParameters.accidentColor,
					 * GuiMethods.getFieldFromIndexX(i),
					 * GuiMethods.getFieldFromIndexY(j));
					 
					GuiPainting.drawImage(GlobalParameters.accidentImage,
							GuiMethods.getFieldFromIndexX(i),
							GuiMethods.getFieldFromIndexY(j));
				} 
			*/
			else if (pole[i][j].getClass() == RouterCell.class) {
					// musim si pre tieto bunky spravit background
					if (stock.containsRamp((pole[i][j]))) {
						GuiPainting.drawImage(GlobalParameters.rampImage,
								GuiMethods.getFieldFromIndexX(i),
								GuiMethods.getFieldFromIndexY(j));
					} else {
						GuiPainting.drawImage(GlobalParameters.coridorImage,
								GuiMethods.getFieldFromIndexX(i),
								GuiMethods.getFieldFromIndexY(j));
					}
				} else if (pole[i][j].getClass() == CoridorCell.class) {
					/*
					 * GuiPainting.drawInFieldCell(canvas, gc,
					 * GlobalParameters.backGroundColor,
					 * GuiMethods.getFieldFromIndexX(i),
					 * GuiMethods.getFieldFromIndexY(j));
					 */
					// pokial je nastaveny obrazok vykreslujem
					CoridorCell c = (CoridorCell) pole[i][j];
					Image image;
					if (c.isImage()) {
						image = c.getImage();
					} else {
						image = GlobalParameters.coridorImage;
					}
					GuiPainting.drawImage(image,
							GuiMethods.getFieldFromIndexX(i),
							GuiMethods.getFieldFromIndexY(j));

				}
			}

		}
		// / toto MUSIM prerobit na dalsiu metodu
		// routre zobrazujem len na maintenance, na work tabe musia existovat,
		// ale nezobrazujem ich
		if (GlobalParameters.tabPane.getSelectionModel()
				.getSelectedItem() != GlobalParameters.workTab) {
			GuiPainting.showRouters(canvas, gc, GlobalParameters.routerImage);
			GuiPainting.showPaths(canvas, gc, GlobalParameters.routeImage);
			if (GlobalParameters.tabPane.getSelectionModel()
					.getSelectedItem() == GlobalParameters.creatingTab) {
				showRamps(canvas, gc, GlobalParameters.rampImage);

			}
		}
		if (selectedRoute >= 0) {
			showPathByNumber(selectedRoute, canvas, gc);
		}
		// vykreslovanie currentbunky

		GuiPainting.drawImage(GlobalParameters.currentImage,
				GuiMethods.getFieldFromIndexX(stock.getIsCurrent().getX()),
				GuiMethods.getFieldFromIndexY(stock.getIsCurrent().getY()));
		// vykreslenie accidentov uz mam hore / ale da sa aj takto
		//for (int i = 0; i < stock.getAccidents().size(); i++) {
			for (int i = 0; i < stock.getAccidentCells().size(); i++) {
			drawImage(
					GlobalParameters.accidentImage,
					GuiMethods.getFieldFromIndexX(stock.getAccidentCells().get(i)
							.getX()),
					GuiMethods.getFieldFromIndexY(stock.getAccidentCells().get(i)
							.getY()));
		}
		/*
		 * GuiPainting.drawInFieldCell( GlobalParameters.creatingCanvas,
		 * GlobalParameters.gc, GlobalParameters.accidentColor,
		 * GuiMethods.getFieldFromIndexX(stock.getAccidents().get(i)
		 * .getCell().getX()),
		 * GuiMethods.getFieldFromIndexY(stock.getAccidents().get(i)
		 * 
		 * .getCell().getY()));
		 * 
		 * }
		 */
		// vykreslenie mriezky
			if (GlobalParameters.netButton.isSelected())
			createLines(GlobalParameters.delimiterColor, gc, canvas);

		// pozeram ci je nieco vo fronte reda/unda a na zaklade toho je tlacitko
		// enable/disable
		setEditIcons();

	}

	private static void setEditIcons() {
		Edit edit = GlobalParameters.edit;
		if (edit.undoIsEmpty()) {
			GuiMethods.iconSetDisable(GlobalParameters.undoIcon);
			GlobalParameters.undo.setDisable(true);
		} else
			GuiMethods.iconSetEnable(GlobalParameters.undoIcon);
		GlobalParameters.undo.setDisable(false);
		if (edit.redoIsEmpty()) {
			GuiMethods.iconSetDisable(GlobalParameters.redoIcon);
			GlobalParameters.redo.setDisable(true);
		} else
			GuiMethods.iconSetEnable(GlobalParameters.redoIcon);
		GlobalParameters.redo.setDisable(false);

	}

	private static void createBorderCells(Canvas canvas, GraphicsContext gc,
			int i, int j) {

		String text = "";
		// zistit cislo
		// potrebujem rozlisit ci sa robi vertikalna alebo horizontalna lajna
		if (i == 0) {
			// poslendy uz nerobit
			if (j != (stock.getWidth() / stock.getDelimiter()) - 1) {

				text = String.valueOf(j * stock.getDelimiter());
			}
		} else if (j == 0) {
			if (i != (stock.getLength() / stock.getDelimiter()) - 1) {
				text = String.valueOf(i * stock.getDelimiter());
			}
		}
		float maxSize = stock.getDelimiter()
				* cz.vutbr.feec.gui.ControllerInitializeGui.getZoomRatio();
		gc.setFill(Color.BLACK);
		gc.fillText(text, GuiMethods.getFieldFromIndexX(i),
				GuiMethods.getFieldFromIndexY(j + 1), maxSize);

	}

	public static void createLines(Color color, GraphicsContext gc,
			Canvas canvas) {
		float step = stock.getDelimiter()
				* cz.vutbr.feec.gui.ControllerInitializeGui.getZoomRatio();
		gc.setLineWidth(0.5);
		gc.setStroke(color);
		for (int x = 0; x < canvas.getWidth(); x += step) {
			double x1;
			x1 = x + 0.5;
			gc.strokeLine(x1, 0, x1, canvas.getHeight());
		}
		for (int y = 0; y < canvas.getHeight(); y += step) {
			double y1;
			y1 = y + 0.5;
			gc.strokeLine(0, y1, canvas.getWidth(), y1);
		}
	}

	public static String colorToString(Color color) {
		String string = null;
		if (color == Color.BLUE) {
			string = "BLUE";
		} else if (color == Color.RED) {
			string = "RED";
		} else if (color == Color.GREEN) {
			string = "GREEN";
		} else if (color == Color.WHITE) {
			string = "WHITE";
		} else if (color == Color.GRAY) {
			string = "GRAY";
		} else if (color == Color.BLACK) {
			string = "BLACK";
		}
		return string;

	}

	public static Color StringToColor(String string) {
		Color color = null;
		switch (string) {
		case "BLUE":
			color = Color.BLUE;
			break;
		case "WHITE":
			color = Color.WHITE;
			break;
		case "GREEN":
			color = Color.GREEN;
			break;
		case "RED":
			color = Color.RED;
			break;
		case "BLACK":
			color = Color.BLACK;
			break;
		case "GRAY":
			color = Color.GRAY;
			break;
		}
		return color;

	}

	public static void drawInFieldCell(Canvas canvas, GraphicsContext gc,
			Color color, int x, int y) {

		gc.setFill(color);
		/*
		 * gc.fillRect(x, y, (stock.getDelimiter() *
		 * cz.vutbr.feec.gui.ControllerInitializeGui.getZoomRatio()),
		 * (stock.getDelimiter() *
		 * cz.vutbr.feec.gui.ControllerInitializeGui.getZoomRatio()));
		 * createLines(GlobalParameters.delimiterColor, gc, canvas);
		 */
		gc.fillOval(
				x,
				y,
				stock.getDelimiter()
						* cz.vutbr.feec.gui.ControllerInitializeGui
								.getZoomRatio(),
				(stock.getDelimiter() * cz.vutbr.feec.gui.ControllerInitializeGui
						.getZoomRatio()));

	}

	public static void showRouters(Canvas canvas, GraphicsContext gc,
			Image image) {
		// Vector<Router> r = new Vector<>();
		Vector<Router> r = stock.getRouters();
		for (int i = 0; i < r.size(); i++) {

			int x = r.get(i).getxInField();
			int y = r.get(i).getyInField();
			x = GuiMethods.getFieldFromIndexX(x);
			y = GuiMethods.getFieldFromIndexY(y);
			drawImage(image, x, y);
			/*
			 * gc.setFill(color); gc.fillRect( x, y, (stock.getDelimiter() *
			 * cz.vutbr.feec.gui.ControllerInitializeGui .getZoomRatio()),
			 * (stock.getDelimiter() * cz.vutbr.feec.gui.ControllerInitializeGui
			 * .getZoomRatio())); // createLines(s.getDelimiterColor(), gc,
			 * canvas);
			 */

		}
	}

	public static void showPaths(Canvas canvas, GraphicsContext gc, Image image) {
		Vector<Path> paths = stock.getPaths();
		for (int i = 0; i < paths.size(); i++) {

			Vector<AbstractStockCell> cell = paths.get(i).getPath();

			for (int j = 0; j < cell.size(); j++) {

				int x = cell.get(j).getX();
				int y = cell.get(j).getY();
				x = GuiMethods.getFieldFromIndexX(x);
				y = GuiMethods.getFieldFromIndexY(y);
				drawImage(image, x, y);
			}
		}
	}

	public static void addPathBetweenRouters(Router start, Router dst,
			DrawnPathCrate drawnPath) {
		Vector<Path> paths = stock.getPaths();
		// musim najst najlepsiu cestu medzi dvoma routrami - moze byt viac
		// ciest medzi dvoma
		LinkedList<Path> multiplePaths = new LinkedList<>();
		Path tmp;

		for (int i = 0; i < paths.size(); i++) {
			tmp = paths.get(i);
			// pokial je iba jeden router na ceste

			// first router ak sa rovna
			if ((tmp.getFirstRouter() == start)
					&& (tmp.getSecondRouter() == dst)) {
				multiplePaths.add(tmp);
	//			System.out.println("Pridavam do multiple number " + i);
			}
			// routre mozu byt prehodene
			else if ((tmp.getFirstRouter() == dst)
					&& (tmp.getSecondRouter() == start)) {

				// musim vytvorit novu cestu a nakopirovat bunky v opacnom
				// poradi
				Path p = new Path(stock.getGraph());
				p.setCost(tmp.getCost());
				for (int j = tmp.getPath().size() - 1; j > -1; j--) {
					p.getPath().add(tmp.getPath().get(j));
				}
				multiplePaths.add(p);
//				System.out.println("Pridavam do multiple number " + i);

			}

		}
		// tu mam zoznam ciest ktory vyhovuje routrom
		// potrebujem vybrat tu s lepsou metrikou
		if (multiplePaths.size() == 1) {
			// prekopirujem vsetky bunky z tejto cesty do drawnPath
			for (int i = 0; i < multiplePaths.get(0).getPath().size(); i++) {
				drawnPath.route.getCellsInPath().add(
						multiplePaths.get(0).getPath().get(i));
			}

		} else {
			tmp = multiplePaths.get(0);
			for (int i = 0; i < multiplePaths.size(); i++) {
				if (multiplePaths.get(i).getCost() > tmp.getCost()) {
					tmp = multiplePaths.get(i);
				}
			}
			for (int i = 0; i < tmp.getPath().size(); i++) {
				drawnPath.route.getCellsInPath().add(tmp.getPath().get(i));
			}
		}

	}

	public static void preparePathBetweenRouters(String path,
			DrawnPathCrate drawnPath) {
		String[] nodes = path.split(";");
		int numberOfnodes = nodes.length - 2;// aby sa nebrala cena ako router
		// a zaroven nevbehlo do metriky tym ze v cykle pracujem s +1
		int x1;
		int y1;
		int x2;
		int y2;
		// odstranenie prvej zatvorky
		nodes[0] = nodes[0].substring(1);

		RouterCell start = null;
		RouterCell dst = null;

		for (int i = 0; i < numberOfnodes; i++) {
			// ceknut kazdu cestu + vykreslit + pripocitat metriku
			// potrebujem najst cestu od uzlov one by one
			String s1[] = nodes[i].split(",");
			x1 = Integer.valueOf(s1[0]);
			y1 = Integer.valueOf(s1[1]);
			String s2[] = nodes[i + 1].split(",");
			x2 = Integer.valueOf(s2[0]);
			y2 = Integer.valueOf(s2[1]);
			// najdem start router
			if (start == null) {
		//		System.out.println("start router pridavam");
				start = (RouterCell) stock.getFieldIndex(x1, y1);
				// pridat bunky od start bunky do tohto routra
				addPathToRouterFromCell(drawnPath.start, start, drawnPath);

			}
			// najdem dst router
			if (i + 1 == numberOfnodes) {
		//		System.out.println("dst router pridavam");
				dst = (RouterCell) stock.getFieldIndex(x2, y2);
				// pridat bunky od tohto routra do dst bunky
				addPathToCellFromRouter(drawnPath.dst, dst, drawnPath);

			}

			RouterCell startCurrentCell = (RouterCell) stock.getFieldIndex(x1,
					y1);
			Router startCurrent = startCurrentCell.getRouter();
			RouterCell dstCurrentCell = (RouterCell) stock
					.getFieldIndex(x2, y2);
			Router dstCurrent = dstCurrentCell.getRouter();

			// pridam aj routre, tie sa nevykresluju pri ceste
			// ale iba tie co nie su start a dst
			if (start != startCurrentCell) {
				drawnPath.route.getCellsInPath().add(startCurrentCell);
			}
			// teraz treba pridat bunky cesty medzi routrami
			addPathBetweenRouters(startCurrent, dstCurrent, drawnPath);

		}
		//drawFoundPath(drawnPath);
	}

	public static void drawFoundPath(DrawnPathCrate drawnPath) {

		for (int i = 0; i < drawnPath.route.getCellsInPath().size(); i++) {
			int x = GuiMethods.getFieldFromIndexX(drawnPath.route
					.getCellsInPath().get(i).getX());
			int y = GuiMethods.getFieldFromIndexY(drawnPath.route
					.getCellsInPath().get(i).getY());
		/*	System.out.print("->"+GuiMethods.getClickedIndexOfFieldX(x) + ","
					+ GuiMethods.getClickedIndexOfFieldY(y));
					*/
			drawImage(GlobalParameters.routeSelectedImage, x, y);
		}
	}

	public static void showPathByNumber(int number, Canvas canvas,
			GraphicsContext gc) {

		Vector<AbstractStockCell> path = stock.getPaths().get(number).getPath();

		for (int i = 0; i < path.size(); i++) {

			int x = path.get(i).getX();
			int y = path.get(i).getY();
			x = GuiMethods.getFieldFromIndexX(x);
			y = GuiMethods.getFieldFromIndexY(y);
			drawImage(GlobalParameters.routeSelectedImage, x, y);
		}

		GlobalParameters.metricTextField
				.setText(String.valueOf(stock.getPaths().get(number).getCost()));

	}

	public static void addPathToRouterFromCell(AbstractStockCell sc,
			RouterCell start, DrawnPathCrate drawnPath) {

		int pathNumber = GraphCreatingMethods.getPathNumberByClick(sc.getX(),
				sc.getY());
		if (pathNumber == -1)
			return;// vyhladava sa z routra
		int counter = GraphCreatingMethods.getCellIndexInPath(pathNumber,
				sc.getX(), sc.getY());
		Path path = stock.getPaths().get(pathNumber);
		// ceknem ci ten router je prvy alebo druhy
		Router r = stock.getPaths().get(pathNumber).getFirstRouter();
		if (r == start.getRouter()) {

			// counter - kolkata bunka v zozname
			// kedze to je first router, takze budem odpocitavat bunky z cesty

			for (int i = counter; i > -1; i--) { // po nulovy index
				if (i != counter) {
	//				System.out.println("pridavam do bunky k first router");
					AbstractStockCell cell = path.getPath().get(i);
					drawnPath.route.getCellsInPath().add(cell);
				}
			}

		}
		// ak to nie je first router tak vykreslujem do second routra
		else {
//			System.out.println("else");
			for (int i = counter; i < path.getPath().size(); i++) {
				if (i != counter) {
//					System.out.println("pridavam do bunky k second router");
					AbstractStockCell cell = path.getPath().get(i);
					drawnPath.route.getCellsInPath().add(cell);
				}
			}

		}
		// este pridat router do cesty
		drawnPath.route.getCellsInPath().add(start);
	}

	public static void addPathToCellFromRouter(AbstractStockCell dst,
			RouterCell start, DrawnPathCrate drawnPath) {

		int pathNumber = GraphCreatingMethods.getPathNumberByClick(dst.getX(),
				dst.getY());
		if (pathNumber == -1)
			return;// vyhladava sa z routra
		int counter = GraphCreatingMethods.getCellIndexInPath(pathNumber,
				dst.getX(), dst.getY());
		// pridat router na do cesty
		drawnPath.route.getCellsInPath().add(start);

		Path path = stock.getPaths().get(pathNumber);
		// ceknem ci ten router je prvy alebo druhy
		Router r = stock.getPaths().get(pathNumber).getFirstRouter();
		if (r == start.getRouter()) {
			// counter - kolkata bunka v zozname
			// kedze to je first router, takze budem odpocitavat bunky z cesty a
			// vykreslovat ich

	//		System.out.println("som v cyklu");
			for (int i = 0; i < counter; i++) {
	//			System.out.println("pridavam do bunky od first router k bunke");
				AbstractStockCell cell = path.getPath().get(i);
				drawnPath.route.getCellsInPath().add(cell);
			}

		}
		// ak to nie je first router tak vykreslujem do second routra
		else {
	//		System.out.println("else");
			for (int i = path.getPath().size() - 1; i > counter; i--) {

	//			System.out.println("pridavam  bunky od second router");
				AbstractStockCell cell = path.getPath().get(i);
				drawnPath.route.getCellsInPath().add(cell);

			}
		}

	}

	public static void showPath(Path p, Image image) {
		Vector<AbstractStockCell> path = p.getPath();
		System.out.println("kreslim a size " + path.size());
		for (int i = 0; i < path.size(); i++) {
			System.out.println("ss");
			int x = path.get(i).getX();
			int y = path.get(i).getY();
			x = GuiMethods.getFieldFromIndexX(x);
			y = GuiMethods.getFieldFromIndexY(y);
			drawImage(image, x, y);
		}

	}

	public static void drawImage(Image img, int x, int y) {

		GlobalParameters.gc
				.drawImage(
						img,
						x,
						y,
						(stock.getDelimiter() * cz.vutbr.feec.gui.ControllerInitializeGui
								.getZoomRatio()),
						(stock.getDelimiter() * cz.vutbr.feec.gui.ControllerInitializeGui
								.getZoomRatio()));

	}

	public static void createOtherCanvas(Canvas otherCanvas) {
		OtherCanvas oc = new OtherCanvas(otherCanvas);
		GlobalParameters.otherCanvas = oc;

	}

	public static void showRamps(Canvas canvas, GraphicsContext gc, Image image) {
		// Vector<Router> r = new Vector<>();
		Vector<AbstractStockCell> a = stock.getRamps();
		for (int i = 0; i < a.size(); i++) {

			int x = a.get(i).getX();
			int y = a.get(i).getY();
			x = GuiMethods.getFieldFromIndexX(x);
			y = GuiMethods.getFieldFromIndexY(y);
			drawImage(image, x, y);
		}
	}

}
