package cz.vutbr.feec.libraryClasses;

import ij.ImagePlus;
import ij.process.BinaryProcessor;
import ij.process.ByteProcessor;

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

import javafx.geometry.Side;

import cz.vutbr.feec.graph.Dijkstra;
import cz.vutbr.feec.graph.Path;
import cz.vutbr.feec.graph.Router;
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.BFScellCrate;
import cz.vutbr.feec.transportObjects.DrawnPathCrate;
import cz.vutbr.feec.transportObjects.TransportRouterDistance;

public class SearchingMethods {
	final static int RECK = 255;
	final static int CORIDOR = 0;
	final static int ROUTER = 128;
	final static int PATH = 200;
	final static int BORDER = 70;
	private static Stock s = Stock.getInstance();
	private static boolean continueBFS = true;

	// metoda na prehladnie kazdej bunky chodby a
	// pridanie parametru s najblizsimi routrami a vzdialenostami
	public static void cellSorting() {
		GlobalParameters.clearCells();
		int x = (int) ((s.getLength() / s.getDelimiter()));
		int y = (int) ((s.getWidth() / s.getDelimiter()));
		// prehladam vsetky bunky a roztriedim do jednotlivych mnozin

		for (int i = 0; i < x; i++) {
			for (int j = 0; j < y; j++) {
				if (s.getFieldIndex(i, j).getClass() == CoridorCell.class) {
					GlobalParameters.allCoridorCells.add((CoridorCell) s
							.getFieldIndex(i, j));
				} else if (s.getFieldIndex(i, j).getClass() == RouterCell.class) {
					GlobalParameters.cellsInRouters.add((RouterCell) s
							.getFieldIndex(i, j));
				} else if (s.getFieldIndex(i, j).getClass() == RackCell.class) {
					GlobalParameters.cellsInRecks.add((RackCell) s
							.getFieldIndex(i, j));
				}
			}
		}
	}

	public static void findDistances() {
		// prevod mnoziny na pole
		HashSet<CoridorCell> cellsInPaths = GlobalParameters.cellsInPaths;
		// mnozina buniek ktore sa nachadzaju v ceste
		// aby som to potom neprehladaval dvakrat
		HashSet<CoridorCell> freeCells = GlobalParameters.cellsInCoridor;
		// potom budem pokracovat prehladavanie len s volnymi bunkami

		// musim vyhladat vzdialenosti pre vsetky ostatne bunky
		// vytvorim znova bitmap a rovno budem pridavat bunky cesty do bitmapy
		ByteProcessor bp = Skeletonization.stockToSkelet();

		CoridorCell[] cells = (CoridorCell[]) GlobalParameters.allCoridorCells
				.toArray(new CoridorCell[GlobalParameters.allCoridorCells
						.size()]);
		for (CoridorCell coridorCell : cells) {

			// dodatocne este roztriedim na cesty a na volne bunky
			// najskor najdem tie ktore su v cestach a priradim im router + ich
			// vzdialenosti
			// pre kazdu coridor bunku potrebujem ceknut ci sa nachadza v ceste

			for (int i = 0; i < s.getPaths().size(); i++) {
				// pre vsetky cesty musim ceknut ci sa tam nachadza bunka
				if (s.getPaths().get(i).contains(coridorCell)) {
					// nasiel som cestu kde lezi bunka, priradim routre
					if (!isAccidentInPath(coridorCell, i)) {
						// neprepocitavam cestu pokial tam je accident
						coridorCell.clearRouters();
						int cellIndex = GraphCreatingMethods
								.getCellIndexInPath(i, coridorCell.getX(),
										coridorCell.getY());
						coridorCell.addDistance(GraphCreatingMethods
								.getMetricToFirstRouter(cellIndex));
						coridorCell.addRouter(s.getPaths().get(i)
								.getFirstRouter());
						if (s.getPaths().get(i).getSecondRouter() != null) {
							coridorCell.addRouter(s.getPaths().get(i)
									.getSecondRouter());
							coridorCell.addDistance(GraphCreatingMethods
									.getMetricToSecondRouter(i, cellIndex));
						}
						// pridam vzdialenosti k routrom
						// pridam bunku do navstivenych stavov
						cellsInPaths.add(coridorCell);
						// nastavim bunku do bitmapy (nech nemusim znova cyklus
						// pustat)
						bp.set(coridorCell.getX(), coridorCell.getY(), PATH);
						break; // koncim cyklus pre tuto bunku
					} else {
						// tie bunky co su na ceste kde je accident, musim tiez
						// prekreslit do bp a pridat do cellsInPaths aby sa
						// nepremazavali
						cellsInPaths.add(coridorCell);
						bp.set(coridorCell.getX(), coridorCell.getY(), PATH);
					}

				}
			}
			// pokial sa bunka nenachadza v niektorej ceste, pridam do
			// freeBuniek
			if (!cellsInPaths.contains(coridorCell)) {
				coridorCell.clearRouters();
				freeCells.add(coridorCell);
			}
		}
		if (GlobalParameters.isSkeletonImage)
			new ImagePlus("Smerovace a cesty", bp.duplicate()).show();
		// pokracujem prehladavanim ostatnych buniek ktore nie su v cestach
		CoridorCell[] cellsNotAssigned = (CoridorCell[]) freeCells
				.toArray(new CoridorCell[freeCells.size()]);
		// musi vstupovat do funkcie bp duplicate
		for (CoridorCell coridorCell : cellsNotAssigned) {
			System.out.println("not assigned " + coridorCell.getX() + ","
					+ coridorCell.getY());
			// kazdej treba zmerat vzdialenosti do routrov pomocou bitmapy a bfs
			findDistance(coridorCell, bp);

		}

	}

	private static boolean isAccidentInPath(CoridorCell c, int pathNumber) {
	/*	for (int i = 0; i < s.getAccidents().size(); i++) {
			if (s.getPaths()
					.get(pathNumber)
					.contains(
							s.getAccidents().get(i).getCell().getPreviousCell())) {
				return true;
			}
		}*/
		return false;

	}

	public static void showInfo() {
		System.out.println("pocet routrov je " + s.getRouters().size());
		System.out.println("pocet ciest je " + s.getPaths().size());
		System.out.println(GlobalParameters.cellsInCoridor.size() + " free");
		System.out.println(GlobalParameters.cellsInRecks.size() + " in recks");
		System.out.println(GlobalParameters.cellsInRouters.size()
				+ " in routers");
		System.out.println(GlobalParameters.cellsInPaths.size() + " in paths");
		System.out.println(GlobalParameters.allCoridorCells.size()
				+ " all coridor");

	}

	public static void findDistance(CoridorCell c, ByteProcessor bp) {
		BinaryProcessor bpCopy = new BinaryProcessor(
				(ByteProcessor) bp.duplicate());

		// generovanie len moznych poli, bez navratu
		// BFS
		LinkedList<CoridorCell> open = new LinkedList<>();

		// potrebujem tu frontu pre 4 bunky ktore sa prave prezeraju
		LinkedList<AbstractStockCell> currentCells = new LinkedList<AbstractStockCell>();

		// pridaj vychozi bod do open
		open.add(c);
		int distance = s.getDelimiter() / GlobalParameters.meterPerSecond; // ak
																			// bude
																			// mat
																			// len
																			// jeden
																			// krok
																			// cyklus,
		// tak by sa vzdialenost
		// neinkrementovala a zostala by nula a blblo by to potom
		// potrebujem urcit kolko buniek sa pridalo do open pri jednom cykle
		// aby sa mi pri kazdom while !open.isEmpty nepripocitavala distance,
		// musi az po jednom cykle
		HashSet<CoridorCell> cellsInOneCycle = new HashSet<CoridorCell>();
		int x = 0;
		int y = 0;
		while (!open.isEmpty()) {
			// pokial ma kam ist ta cesta, tak pridavat prvky + inkrementovat
			// distance
			x = open.getFirst().getX();
			y = open.getFirst().getY();
			CoridorCell tmp = open.getFirst();
			open.remove(open.getFirst());

			// vygenerovat vsetky mozne stavy a pridat do open
			for (int i = -1; i < 2; i = i + 2) {
				// do fronty current si pridam len bunky ktore nie su regal, ani
				// border
				if ((bpCopy.get(x + i, y) != BORDER)
						&& (bpCopy.get(x + i, y) != RECK)) {
					// pridam konkretny typ bunky
					currentCells.add(s.getFieldIndex(x + i, y));
				}
				if ((bpCopy.get(x, y + i) != BORDER)
						&& (bpCopy.get(x, y + i) != RECK)) {
					// pridam konkretny typ bunky
					currentCells.add(s.getFieldIndex(x, y + i));
				}
			}
			// po skonceni vygenerovani vsetkych moznych stavov ceknem frontu a
			// rozhodnem co dalej v dalsej metode
			// processQueue metoda vracia boolean, ak uz je bunka vybavena, ma
			// nastavene
			// routre, vrati true a vtedy treba vyskocit z metody finDistance
			if (processQueue(c, currentCells, bpCopy, open, distance)) {
				return;
			}

			// musim vymazat frontu current buniek
			currentCells.removeAll(currentCells);
			// prekreslit vychadzajucu bunku na "closed"
			// mozem preklesit napriklad an farbu BORDER - je uplne jedno aka
			// farba ale ked je to BORDER, tak v podmienkach predtym sa zamedzi
			// najskor ako je mozne, nemusi sa osetrovat neskor
			bpCopy.set(x, y, BORDER);

			if (!cellsInOneCycle.contains(tmp)) {
				cellsInOneCycle.removeAll(cellsInOneCycle);
				cellsInOneCycle.addAll(open);
				distance = distance
						+ (s.getDelimiter() / GlobalParameters.meterPerSecond);
			}

		}

		// new ImagePlus("bunka"+x+","+y, bpCopy.duplicate()).show();
	}

	private static boolean processQueue(CoridorCell c,
			LinkedList<AbstractStockCell> currentCells, BinaryProcessor bp,
			LinkedList<CoridorCell> open, int distance) {
		Vector<RouterCell> countOfRouters = new Vector<RouterCell>();
		Vector<CoridorCell> countOfPaths = new Vector<CoridorCell>();
		Vector<CoridorCell> countOfFree = new Vector<CoridorCell>();

		// potrebujem roztriedit bunky a zistit akeho su typu a co potom s nimi
		// dalej
		for (int i = 0; i < currentCells.size(); i++) {
			if (currentCells.get(i).getClass() == AccidentCell.class) {
				// ak narazi na accident, tak vymazem frontu
				c.clearRouters();
				// vratim ze je proces hotovy
				return true;
			} else if (currentCells.get(i).getClass() == RouterCell.class) {
				// ak je dana bunka router pridam do routra
				countOfRouters.add((RouterCell) currentCells.get(i));
			} else if (currentCells.get(i).getClass() == CoridorCell.class) {
				// mali by byt iba coridorCelly pokial tam nie je nejaky router
				// - ten sa ale sprocesuje v cykle hore
				// zistit ci sa jedna o cestu, alebo len chodbu
				if (bp.get(currentCells.get(i).getX(), currentCells.get(i)
						.getY()) == PATH) {
					countOfPaths.add((CoridorCell) currentCells.get(i));
				} else {
					countOfFree.add((CoridorCell) currentCells.get(i));
				}
			}
		}
		// dva routre by pri jednej bunke nemali nikdy nestat - v takom pripade
		// to je uz rovno cesta
		// moze sa nachadzat len router a chodby bez cesty
		if (countOfRouters.size() == 1 && countOfPaths.size() == 0) {
			System.out.println("iba jeden router");
			// bunka je priamo nad routrom a nepatri do ziadnej cesty
			// bude mat iba jeden router a jednu vzdialenost a konci cely cyklus
			// pre bunku
			c.addRouter(countOfRouters.get(0).getRouter());
			c.addDistance(distance);
			return true;
		}
		// moze sa nachadzat jeden router a jedna cesta
		else if (countOfRouters.size() == 1 && countOfPaths.size() == 1) {
			System.out.println("jeden router a jedna cesta");
			// asi by nemalo nastat casto, pri zlej skeletonizaci mozno
			// treba zobrat first a second router bunky pre danu cestu a
			// porovnat
			// s routrom najdenym v bfs = ten ktory sa rovna tak pridam so
			// vzdialenostou z BFS
			// ten ktory sa nerovna pridam tiez + vzdialenost BFS + vzdialenost
			// k routru
			// treba osetrit pripad so slepou ulickou t.j jeden router
			// tak pridam len ten jeden a koncim cely cyklus pre danu bunku

			// musim odpocitat vzdialenosti, co su naikrementovane
			// kvoli ostatnym open bunkam, ktorymi preslo BFS
			// distance = distance - (open.size() * s.getDelimiter());

			for (int j = 0; j < countOfPaths.get(0).getClosestRouters().size(); j++) {
				if (countOfPaths.get(0).getClosestRouters().get(j) == countOfRouters
						.get(0).getRouter()) {
					// pokial sa rovnaju tie routre tak pridam router a
					// vzdialenost z BFS
					c.addRouter(countOfRouters.get(0).getRouter());
					c.addDistance(distance);
				} else {
					// ak to nie je ten isty tak pridam druhy
					c.addRouter(countOfPaths.get(0).getClosestRouters().get(j));
					c.addDistance(distance
							+ countOfPaths.get(0).getClosestDistances().get(j));
				}
			}
			// osetrenie na slepu ulicku je uz v tom cyklu, bud ma len jeden
			// router a ten
			// by sa mal rovnat s tym co naslo BFS

			return true;
		}
		// mohol by sa pri zlej skeletonizaci nachadzat jeden router a dve cesty
		// v tom pripade pripad rovnaky ako keby je len jeden router a ostatne
		// chodby
		else if (countOfRouters.size() == 1 && countOfPaths.size() == 2) {
			System.out.println("jeden router a dve cesty");
			// distance = distance - (open.size() * s.getDelimiter());
			c.addRouter(countOfRouters.get(0).getRouter());
			c.addDistance(distance);
			return true;
		}
		// ak sa nachadza len jedna cesta a ziadny router
		else if (countOfPaths.size() == 1 && countOfRouters.size() == 0) {
			System.out.println("jedna cesta a ziadny router");
			// treba osetrit pripad so slepou ulickou t.j jeden router
			// tak pridam len ten jeden a koncim cely cyklus pre danu bunku
			for (int j = 0; j < countOfPaths.get(0).getClosestRouters().size(); j++) {
				// pre vsetky routre ktore su na danej bunke pre danu cestu -
				// osetrujem rovno pripad slepej ulicky
				c.addRouter(countOfPaths.get(0).getClosestRouters().get(j));
				// pridam len tolko routrov kolko ich je v skutocnosti a ich
				// vzdialenosti
				c.addDistance(distance
						+ countOfPaths.get(0).getClosestDistances().get(j));

			}
			return true;
		}
		// ak sa nachadzaju dve cesty a ziadny router - najhorsi pripad
		else if (countOfPaths.size() == 2 && countOfRouters.size() == 0) {
			System.out.println("dve cesty a ziadny router");
			// moze sa jednat o tu istu cestu
			Router first1;
			Router second1;
			Router first2;
			Router second2;
			// distance = distance - (open.size() * s.getDelimiter());
			// najdem routre konkretnej bunky
			first1 = countOfPaths.get(0).getClosestRouters().get(0);
			if (countOfPaths.get(0).getClosestRouters().size() == 1) {
				// pokial je len jeden router
				second1 = null;
			} else {
				second1 = countOfPaths.get(0).getClosestRouters().get(1);

			}
			first2 = countOfPaths.get(1).getClosestRouters().get(0);
			if (countOfPaths.get(1).getClosestRouters().size() == 1) {
				// pokial je len jeden router
				second2 = null;
			} else {
				second2 = countOfPaths.get(1).getClosestRouters().get(1);

			}
			// musim zistit cisla ciest a porovnat ich
			if (s.getPathNumber(first1, second1) == s.getPathNumber(first2,
					second2)) {
				// pokial je to ta ista cesta, zoberem kratsiu vzdialenost k
				// jednotlivym routrom
				// kedze su aj routre ktore maju viac ciest medzi sebou, tu sa
				// to pekne spocita spravne
				// kvoli podmienke v getPathNumber
				for (int j = 0; j < countOfPaths.get(0).getClosestRouters()
						.size(); j++) {
					// je jedno ktoru bunku z cesty pouzijem - obidve bunky
					// musia mat rovnaky pocet routrov
					if (countOfPaths.get(0).getClosestDistances().get(j) < countOfPaths
							.get(1).getClosestDistances().get(j)) {
						// ak je vzdialenost od prvej bunky mensia k danemu
						// routru pouzijem tu
						c.addRouter(countOfPaths.get(0).getClosestRouters()
								.get(j));
						c.addDistance(distance
								+ countOfPaths.get(0).getClosestDistances()
										.get(j));
					} else {
						// inak pouzijem druhu bunku s jej vzdialenostou
						c.addRouter(countOfPaths.get(1).getClosestRouters()
								.get(j));
						c.addDistance(distance
								+ countOfPaths.get(1).getClosestDistances()
										.get(j));
					}
				}
				return true;

			} else {
				// ak to nie je ta ista cesta pravdepodobne bude router
				// na uhlopriecke vtedy ho treba pridat iba ako jeden,
				// dosiahnutelny urcite je kedze su okolo cesty
				// najskor treba skusit ci bunka nepatri do nejakej cesty -
				// skujsit vygenerovat z bunky dalsie mozne bunky a z nich este
				// dalsie a ak
				// narazia na tu istu cestu, tak viem ze patria do tej cesty

				// ak ani to nejde tak metoda na zistenie spolocneho routra z
				// dvoch ciest
				TransportRouterDistance crate = getCommonCoordinates(
						countOfPaths.get(0), countOfPaths.get(1));
				// moze sa stat ze sa spolocny router nenasiel a to teda neviem
				// ci je vobec mozne
				if (crate.router != null) {
					c.addRouter(crate.router);
					c.addDistance(crate.distance + distance);
					System.out.println("nastavujem parametre z prepravky");
				} else {
					System.out
							.println("chyba pri dvoch cestach a ziadnom routri");
				}
				return true;
			}

			// treba naprogramovat v niektorych pripadoch moze vratit true,
			// niekedy false
		} else if (countOfPaths.size() == 0 && countOfRouters.size() == 0) {
			System.out.println("iba open");
			// ak su tam iba chodby tak vsetky pridam do OPEN
			open.addAll(countOfFree);
			for (CoridorCell coridorCell : countOfFree) {
				bp.set(coridorCell.getX(), coridorCell.getY(), BORDER);
			}

			return false;

		} else {
			// tu uz neviem co by mohlo nastat
			System.out.println("NEOCAKAVANY STAV!!!!");
			return true; // keby bolo false, tak sa asi zacykli
		}

	}

	private static TransportRouterDistance getCommonCoordinates(CoridorCell c1,
			CoridorCell c2) {
		TransportRouterDistance crate = new TransportRouterDistance();
		// moze sa stat, ze dva routre maju dve rozne cesty a tym padom
		// tento algoritmus najde obidva
		Router router1 = null;
		Router router2 = null;
		int distance1 = 0;
		int distance2 = 0;
		if (c1.getClosestRouters().get(0).getxInField() == c2
				.getClosestRouters().get(0).getxInField()
				&& c1.getClosestRouters().get(0).getyInField() == c2
						.getClosestRouters().get(0).getyInField()) {
			// mam spolocny router
			router1 = c1.getClosestRouters().get(0);
			distance1 = c1.getClosestDistances().get(0);
			// prvy krok moze byt jedine jeden router
		}
		if (c2.getClosestRouters().size() == 2) {
			if (c1.getClosestRouters().get(0).getxInField() == c2
					.getClosestRouters().get(1).getxInField()
					&& c1.getClosestRouters().get(0).getyInField() == c2
							.getClosestRouters().get(1).getyInField()) {
				// tento prvy router sa moze rovnat len s jednym alebo druhym
				// routrom z druhej cesty
				// preto netreba podmienku ci uz je prvy router nastaveny alebo
				// null
				router1 = c1.getClosestRouters().get(0);
				distance1 = c1.getClosestDistances().get(0);
			}
		}

		if (c1.getClosestRouters().size() == 2) {
			if (c1.getClosestRouters().get(1).getxInField() == c2
					.getClosestRouters().get(0).getxInField()
					&& c1.getClosestRouters().get(1).getyInField() == c2
							.getClosestRouters().get(0).getyInField()) {
				// tu uz tu podmienku treba ci je prvy router nastaveny, alebo
				// null
				if (router1 == null) {
					router1 = c1.getClosestRouters().get(1);
					distance1 = c1.getClosestDistances().get(1);
				} else {
					router2 = c1.getClosestRouters().get(1);
					distance2 = c1.getClosestDistances().get(1);
				}
			}
			if (c2.getClosestRouters().size() == 2) {
				if (c1.getClosestRouters().get(1).getxInField() == c2
						.getClosestRouters().get(1).getxInField()
						&& c1.getClosestRouters().get(1).getyInField() == c2
								.getClosestRouters().get(1).getyInField()) {
					if (router1 == null) {
						router1 = c1.getClosestRouters().get(1);
						distance1 = c1.getClosestDistances().get(1);
					} else {
						router2 = c1.getClosestRouters().get(1);
						distance2 = c1.getClosestDistances().get(1);
					}
				}

			}

		}
		if (router1 == null) {
			System.out.println("mega chyba");
			return crate;
		}
		// pokial je nastaveny aj second router, musim zistit ktory router je
		// ten spravny
		if (router2 == null) {
			crate.router = router1;
			crate.distance = distance1;

		} else {
			// vzdialenost od obidvoch buniek cesty by mala byt rovnaka k tomu
			// spolocnemu routru
			// v pripade ze su dva spolocne routre t.j. dve rozne cesty do nich,
			// musi byt vzdy jedna cesta kratsia a to je zrovna do toho routru
			// ktory hladam
			if (distance1 < distance2) {
				crate.router = router1;
				crate.distance = distance1;
			} else {
				crate.router = router2;
				crate.distance = distance2;
			}
		}

		return crate;

		// toto by malo nastat len v pripade krizovatky- to znamena
		// ze router je cez uhlopriecku a vzdialenosti z obidvoch ciest
		// su rovnake

	}

	private static TransportRouterDistance getCommonRouter(CoridorCell c1,
			CoridorCell c2) {
		TransportRouterDistance crate = new TransportRouterDistance();
		// moze sa stat, ze dva routre maju dve rozne cesty a tym padom
		// tento algoritmus najde obidva
		Router router1 = null;
		Router router2 = null;
		int distance1 = 0;
		int distance2 = 0;
		if (c1.getClosestRouters().get(0) == c2.getClosestRouters().get(0)) {
			// mam spolocny router
			router1 = c1.getClosestRouters().get(0);
			distance1 = c1.getClosestDistances().get(0);
			// prvy krok moze byt jedine jeden router
		}
		if (c2.getClosestRouters().size() == 2) {
			if (c1.getClosestRouters().get(0) == c2.getClosestRouters().get(1)) {
				// tento prvy router sa moze rovnat len s jednym alebo druhym
				// routrom z druhej cesty
				// preto netreba podmienku ci uz je prvy router nastaveny alebo
				// null
				router1 = c1.getClosestRouters().get(0);
				distance1 = c1.getClosestDistances().get(0);
			}
		}

		if (c1.getClosestRouters().size() == 2) {
			if (c1.getClosestRouters().get(1) == c2.getClosestRouters().get(0)) {
				// tu uz tu podmienku treba ci je prvy router nastaveny, alebo
				// null
				if (router1 == null) {
					router1 = c1.getClosestRouters().get(1);
					distance1 = c1.getClosestDistances().get(1);
				} else {
					router2 = c1.getClosestRouters().get(1);
					distance2 = c1.getClosestDistances().get(1);
				}
			}
			if (c2.getClosestRouters().size() == 2) {
				if (c1.getClosestRouters().get(1) == c2.getClosestRouters()
						.get(1)) {
					if (router1 == null) {
						router1 = c1.getClosestRouters().get(1);
						distance1 = c1.getClosestDistances().get(1);
					} else {
						router2 = c1.getClosestRouters().get(1);
						distance2 = c1.getClosestDistances().get(1);
					}
				}

			}

		}
		if (router1 == null) {
			System.out.println("mega chyba");
			return crate;
		}
		// pokial je nastaveny aj second router, musim zistit ktory router je
		// ten spravny
		if (router2 == null) {
			crate.router = router1;
			crate.distance = distance1;

		} else {
			// vzdialenost od obidvoch buniek cesty by mala byt rovnaka k tomu
			// spolocnemu routru
			// v pripade ze su dva spolocne routre t.j. dve rozne cesty do nich,
			// musi byt vzdy jedna cesta kratsia a to je zrovna do toho routru
			// ktory hladam
			if (distance1 < distance2) {
				crate.router = router1;
				crate.distance = distance1;
			} else {
				crate.router = router2;
				crate.distance = distance2;
			}
		}

		return crate;

		// toto by malo nastat len v pripade krizovatky- to znamena
		// ze router je cez uhlopriecku a vzdialenosti z obidvoch ciest
		// su rovnake

	}

	private static Path getPathBetweenRouters(Router r1, Router r2) {
		// Search for paths
		/*
		 * Dijkstra d = s.getDijkstra(); System.out.println(d); LinkedList<Path>
		 * p = d.getPaths(r1, r2, GlobalParameters.factor);
		 * System.out.println("Nejkratsi cesta dikstra " + p + "...");
		 * System.out.println("prva cesta p.get(0) " + p.get(0));
		 * System.out.println("idem vykreslit");
		 */
		try {

			LinkedList<Path> p = s.getRoutingTable().getPaths(r1, r2);
			// vraciam najlepsiu cestu, neni problem vratit viacej tych ciest
			// System.out.println("cesta pomocou routing table " + p);
			System.out.println("medzi routrami "+p.get(0));
			return p.get(0);

		} catch (Exception e) {
			System.out.println("chyba v RT, ceste pomocou Dijkstru");
			Dijkstra d = s.getDijkstra();
			LinkedList<Path> p = d.getPaths(r1, r2, GlobalParameters.factor);
			return p.get(0);
		}

	}

	private static Path getPathFromStartRouter(Router start,
			AbstractStockCell cell, DrawnPathCrate drawnPath) {
		// nutne odlisit ak su na rovnakej ceste
		for (int i = 0; i < cell.getClosestRouters().size(); i++) {
			// System.out.println("for cyklus");
			if (cell.getClosestRouters().get(i) == start) {
				// System.out.println("podmienka");
				RouterCell rc = (RouterCell) s.getFieldIndex(
						start.getxInField(), start.getyInField());
				GuiPainting.addPathToCellFromRouter(cell, rc, drawnPath);
				drawnPath.route.getCellsInPath().remove(0);
				// GuiPainting.drawFoundPath(drawnPath);
				return null;
			}
		}
		Path path;
		Path tmp = null;
		int tmpDistance = 10000000; // nejake velke cislo na zaciatku
		// musim skusit kombinace a vratit najkratsiu vzdialenost
		// neviem kolko routrov ma dana bunka, radsej to vyriesim cyklom
		for (int i = 0; i < cell.getClosestRouters().size(); i++) {
			path = getPathBetweenRouters(start, cell.getClosestRouters().get(i));
			int currentDistance = path.getCost()
					+ cell.getClosestDistances().get(i);
			if (tmpDistance > currentDistance) {
				tmpDistance = currentDistance;
				tmp = path;
			}
		}
		return tmp;

	}

	private static Path getPathFromDstRouter(AbstractStockCell cell,
			Router dst, DrawnPathCrate drawnPath) {

		// nutne odlisit ak su na rovnakej ceste
		for (int i = 0; i < cell.getClosestRouters().size(); i++) {
			if (cell.getClosestRouters().get(i) == dst) {
				RouterCell rc = (RouterCell) s.getFieldIndex(dst.getxInField(),
						dst.getyInField());
				GuiPainting.addPathToRouterFromCell(cell, rc, drawnPath);
				drawnPath.route.getCellsInPath().remove(
						drawnPath.route.getCellsInPath().size() - 1);
				// GuiPainting.drawFoundPath(drawnPath);
				return null;
			}
		}
		Path path;
		Path tmp = null;
		int tmpDistance = 10000000; // nejake velke cislo na zaciatku
		// musim skusit kombinace a vratit najkratsiu vzdialenost
		// neviem kolko routrov ma dana bunka, radsej to vyriesim cyklom
		for (int i = 0; i < cell.getClosestRouters().size(); i++) {
			path = getPathBetweenRouters(cell.getClosestRouters().get(i), dst);
			int currentDistance = path.getCost()
					+ cell.getClosestDistances().get(i);
			if (tmpDistance > currentDistance) {
				tmpDistance = currentDistance;
				tmp = path;
			}
		}
		return tmp;

	}

	private static DrawnPathCrate getDrawnPathOnSamePath(AbstractStockCell c1,
			AbstractStockCell c2, DrawnPathCrate drawnPath) {
		// mam pathNumber z prvej bunky
		int pathNumber = GraphCreatingMethods.getPathNumberByClick(c1.getX(),
				c1.getY());
		// ak to nahodou nie je rovnaka cesta / viacnasobne hrany /
		// dve slepe ulicky so spolocnym routrom
		int index1 = GraphCreatingMethods.getCellIndexInPath(pathNumber,
				c1.getX(), c1.getY());
		int index2 = GraphCreatingMethods.getCellIndexInPath(pathNumber,
				c2.getX(), c2.getY());

		if (index2 == -1) {
			// nenachadzaju sa na rovnakej ceste
			// System.out.println("identifikovana spravne nerovnaka cesta");
			// ak to bola slepa ulicka
			if (c1.getClosestRouters().size() == 1) {
				getDrawnPathByOneSameRouter(c1.getClosestRouters().get(0), c1,
						c2, drawnPath);
				/*
				 * getDistanceByOneSameRouter(c1.getClosestDistances().get(0),
				 * c2, c1.getClosestRouters().get(0), c1, drawnPath);
				 */

			}
			return getDrawnPathMoreSamePaths(c1, c2, drawnPath);
		}
		if (index1 < index2) {
			for (int i = index1; i < index2; i++) {
				if (i != index1) {
					drawnPath.route.getCellsInPath().add(
							s.getPaths().get(pathNumber).getPath().get(i));
				}
			}
		} else {
			for (int i = index1; i > index2; i--) {
				if (i != index1) {
					drawnPath.route.getCellsInPath().add(
							s.getPaths().get(pathNumber).getPath().get(i));
				}
			}
		}
		return drawnPath;
		// GuiPainting.drawFoundPath(drawnPath);

	}

	private static int getDistanceOnSamePath(AbstractStockCell c1,
			AbstractStockCell c2, DrawnPathCrate drawnPath) {
		// zoberem vzdy prvy rotuer, pretoze sem mozu vstupovat bunky bud s
		// jednym alebo dvoma routrami
		// mozu byt ale prehodene tie routre ak su dva
		int distance1 = c1.getClosestDistances().get(0);
		int distance2;
		if (c1.getClosestRouters().get(0) == c2.getClosestRouters().get(0)) {
			distance2 = c2.getClosestDistances().get(0);
		} else {
			distance2 = c2.getClosestDistances().get(1);
		}

		int index1 = distance1 / s.getDelimiter()
				* GlobalParameters.meterPerSecond;
		int index2 = distance2 / s.getDelimiter()
				* GlobalParameters.meterPerSecond;
		int pathNumber = GraphCreatingMethods.getPathNumberByClick(c1.getX(),
				c1.getY());
		if (index1 < index2) {
			for (int i = index1; i < index2 - 1; i++) {

				drawnPath.route.getCellsInPath().add(
						s.getPaths().get(pathNumber).getPath().get(i));

			}

		} else {
			for (int i = index1 - 2; i > index2 - 1; i--) {

				drawnPath.route.getCellsInPath().add(
						s.getPaths().get(pathNumber).getPath().get(i));

			}
		}
		// vykresli cestu
		GuiPainting.drawFoundPath(drawnPath);
		System.out.println("vzdialenost z vyslednej cesty= "
				+ drawnPath.route.getCellsInPath().size() * s.getDelimiter()
				/ GlobalParameters.meterPerSecond);

		// vrat absolutnu hodnotu rozdielu ich vzdialenosti k spolocnemu routru
		// (je jedno ku ktoremu)
		return Math.abs(distance1 - distance2);

	}

	private static Path getPathBetweenTwoCells(AbstractStockCell c1,
			AbstractStockCell c2) {

		Path path;
		Path tmp = null;
		int tmpDistance = 10000000; // nejake velke cislo na zaciatku
		for (int i = 0; i < c1.getClosestRouters().size(); i++) {
			for (int j = 0; j < c2.getClosestRouters().size(); j++) {
				path = getPathBetweenRouters(c1.getClosestRouters().get(i), c2
						.getClosestRouters().get(j));
				int currentDistance = path.getCost()
						+ c1.getClosestDistances().get(i)
						+ c2.getClosestDistances().get(j);
				System.out.println("medzi bunkami "+path);
				if (tmpDistance > currentDistance) {
					tmpDistance = currentDistance;
					tmp = path;
				}
			}
		}
		return tmp;

	}

	private static DrawnPathCrate getDrawnPathMoreSamePaths(
			AbstractStockCell c1, AbstractStockCell c2, DrawnPathCrate drawnPath) {
		// potrebujem zistit ktora kombinacia je najlepsia cez ktory smerovac
		Router router;
		Router tmp = null;
		int tmpDistance = 10000000; // nejake velke cislo na zaciatku
		for (int i = 0; i < c1.getClosestRouters().size(); i++) {
			for (int j = 0; j < c2.getClosestRouters().size(); j++) {
				Router r = c1.getClosestRouters().get(j);
				int currentDistance = c1.getClosestDistances().get(i)
						+ c2.getClosestDistances().get(j);
				if (tmpDistance > currentDistance) {
					tmpDistance = currentDistance;
					tmp = r;
				}
			}
		}
		return getDrawnPathByOneSameRouter(tmp, c1, c2, drawnPath);

	}

	private static DrawnPathCrate getDrawnPathByOneSameRouter(
			Router sameRouter, AbstractStockCell startCell,
			AbstractStockCell dstCell, DrawnPathCrate drawnPath) {

		RouterCell rc = (RouterCell) s.getFieldIndex(sameRouter.getxInField(),
				sameRouter.getyInField());
		GuiPainting.addPathToRouterFromCell(startCell, rc, drawnPath);
		drawnPath.route.getCellsInPath().remove(
				drawnPath.route.getCellsInPath().size() - 1);
		GuiPainting.addPathToCellFromRouter(dstCell, rc, drawnPath);
		return drawnPath;
		/*
		 * int startSize = startCell.getClosestRouters().size(); int dstSize =
		 * dstCell.getClosestRouters().size(); if (startSize == 1) { // start ma
		 * jeden router //mozem rovno pridat bunky
		 * GuiPainting.addPathToRouterFromCell(startCell, rc, drawnPath); if
		 * (dstSize == 1) { // obidva maju len jeden router //pridam aj do dst
		 * GuiPainting.addPathToCellFromRouter(dstCell, rc, drawnPath); return
		 * drawnPath; } else { // dst ma dva routre if
		 * (dstCell.getClosestRouters().get(0) == sameRouter) {
		 * GuiPainting.addPathToRouterFromCell(startCell, rc, drawnPath);
		 * GuiPainting.addPathToCellFromRouter(dstCell, rc, drawnPath); return
		 * drawnPath; } else { distance =
		 * startCell.getClosestDistances().get(1);
		 * 
		 * } } } else { // start ma dva routre if (dstSize == 1) { // dst ma
		 * jeden router } else { // dst ma dva routre } }
		 * 
		 * if (startCell.getClosestRouters().get(0) == sameRouter) { distance =
		 * startCell.getClosestDistances().get(0); } else { distance =
		 * startCell.getClosestDistances().get(1);
		 * 
		 * } RouterCell rc = (RouterCell)
		 * s.getFieldIndex(sameRouter.getxInField(), sameRouter.getyInField());
		 * GuiPainting.addPathToRouterFromCell(startCell, rc, drawnPath);
		 * GuiPainting.addPathToCellFromRouter(dstCell, rc, drawnPath);
		 * 
		 * // vykresli cestu GuiPainting.drawFoundPath(drawnPath);
		 * System.out.println("vzdialenost z vyslednej cesty= " +
		 * drawnPath.route.getCellsInPath().size() * s.getDelimiter() /
		 * GlobalParameters.meterPerSecond); return distanceToRouter + distance;
		 */
	}

	private static int getDistanceByOneSameRouter(int distanceToRouter,
			AbstractStockCell dstCell, Router sameRouter,
			AbstractStockCell startCell, DrawnPathCrate drawnPath) {
		// vstupuje mi sem spolocny router a jedna jeho vzdialenost
		// staci dopocitat druhu vzdialenost k nemu a priratat k prvej
		int distance;
		if (startCell.getClosestRouters().get(0) == sameRouter) {
			distance = startCell.getClosestDistances().get(0);
		} else {
			distance = startCell.getClosestDistances().get(1);

		}
		RouterCell rc = (RouterCell) s.getFieldIndex(sameRouter.getxInField(),
				sameRouter.getyInField());
		GuiPainting.addPathToRouterFromCell(startCell, rc, drawnPath);
		GuiPainting.addPathToCellFromRouter(dstCell, rc, drawnPath);

		// vykresli cestu
		GuiPainting.drawFoundPath(drawnPath);
		System.out.println("vzdialenost z vyslednej cesty= "
				+ drawnPath.route.getCellsInPath().size() * s.getDelimiter()
				/ GlobalParameters.meterPerSecond);
		return distanceToRouter + distance;

	}

	public static DrawnPathCrate findPathFromCells(AbstractStockCell startCell,
			AbstractStockCell dstCell) {
		// kvoli vykresleniu pridavam cestu, ktora sa prenasa a pridavaju do nej
		// bunky

		DrawnPathCrate drawnPath = new DrawnPathCrate(startCell, dstCell);

		if (startCell == dstCell) {
			System.out.println("start a ciel je rovnaky");
			return drawnPath;
		}

		// vstupuje abstraktna bunka, pretoze sa moze vyhladavat z routra,
		// chodbz, pri chybe aj z regalu
		// osetrenie regalov a borders
		try {

			// najskor pozrem ci sa nevyhladava z routrov
			if (isRouterCell(startCell)) {
				if (isRouterCell(dstCell)) {
					// System.out.println("dva routre");
					// vrat cestu medzi dvoma routrami
					RouterCell start = (RouterCell) startCell;
					RouterCell dst = (RouterCell) dstCell;
					Path p = getPathBetweenRouters(start.getRouter(),

					dst.getRouter());
					GuiPainting.preparePathBetweenRouters(String.valueOf(p),
							drawnPath);
					return drawnPath;
				}
				// System.out.println("iba start je router a dst bunka");
				RouterCell start = (RouterCell) startCell;
				// kombinuj do dst z routra a vrat najkratsiu
				Path p = getPathFromStartRouter(start.getRouter(), dstCell,
						drawnPath);
				if (p != null) {
					GuiPainting.preparePathBetweenRouters(String.valueOf(p),
							drawnPath);
					return drawnPath;
				}
				return drawnPath;

			} else if (isRouterCell(dstCell)) {
				// System.out.println("iba dst je router a start bunka");
				RouterCell dst = (RouterCell) dstCell;
				Path p = getPathFromDstRouter(startCell, dst.getRouter(),
						drawnPath);
				if (p != null) {
					GuiPainting.preparePathBetweenRouters(String.valueOf(p),
							drawnPath);
					return drawnPath;
				}
				return drawnPath;
			}

			// ak to nie su routre, treba pozret ci nie su na spolocnom segmente
			// prva podmienka je rovnaky pocet routrov, ak by mali byt na
			// rovnakej
			// ceste
			if (startCell.getClosestRouters().size() == dstCell
					.getClosestRouters().size()) {
				int size = startCell.getClosestRouters().size();

				// mozu byt na spolocnej ceste
				// vytvorim mnozinu kde budem porovnavat routre
				HashSet<Router> sameRouters = new HashSet<Router>();
				for (int i = 0; i < size; i++) {

					sameRouters.add(startCell.getClosestRouters().get(i));
				}
				// mam naplnenu mnozinu routrami zo startu (nezaujima ma ci je
				// jeden
				// alebo dva)
				// potrebujem ich porovnat s routrami cielu
				if (sameRouters.contains(dstCell.getClosestRouters().get(0))) {
					// prvy router sa rovna, este treba pozret druhy router, ak
					// je
					if (size > 1) {
						if (sameRouters.contains(dstCell.getClosestRouters()
								.get(1))) {
							// routre su dva a rovnaju sa su na rovnakej ceste
							// metoda na odcitanie vzdialenosti medzi bunkami
							// moze
							// byt rovnaka pre
							// jeden router alebo dva routre, odcitavam k prvemu
							// routru vzdialenost
							// System.out.println("rovnaka cesta s dvoma routrami");
							// moze by problem s viacnasobnymi hranami
							drawnPath = getDrawnPathOnSamePath(startCell,
									dstCell, drawnPath);
							return drawnPath;
							// return getDistanceOnSamePath(startCell,
							// dstCell,drawnPath);

						} else {
							// velkost je dva a jeden z routrov sa rovna, jeden
							// nie
							// - nie su na rovnakej ceste
							// najrychlejsia cesta by mala byt prave cez ten
							// spolocny router
							// spolocny router je
							// dstCell.getClosestRouters().get(0)
							// System.out.println("jeden spolocny router");
							getDrawnPathByOneSameRouter(dstCell
									.getClosestRouters().get(0), startCell,
									dstCell, drawnPath);
							return drawnPath;
							/*
							 * return getDistanceByOneSameRouter(dstCell
							 * .getClosestDistances().get(0), dstCell, dstCell
							 * .getClosestRouters().get(0), startCell,
							 * drawnPath);
							 */
						}
					} else {
						// velkost bola len jedna a routre sa rovnaju, takze su
						// na
						// rovnakej ceste
						// System.out.println("rovnaka cesta - slepa ulicka");
						drawnPath = getDrawnPathOnSamePath(startCell, dstCell,
								drawnPath);
						return drawnPath;
						// return drawnPath.route.getCellsInPath().size();
						// return getDistanceOnSamePath(startCell, dstCell,
						// drawnPath);

					}
				} else {
					// staci ze sa jeden z routrov nerovna, tak nie su na tej
					// istej
					// ceste
					// este pozriem ci sa nerovna aspon jeden z tych routrov, co
					// sa
					// nepozrie v prvom cyklu
					// aby som ulahcil vypocet
					if (size == 1) {
						// System.out.println("nie su na rovnakej ceste");
						Path p = getPathBetweenTwoCells(startCell, dstCell);
						GuiPainting.preparePathBetweenRouters(
								String.valueOf(p), drawnPath);
						return drawnPath;
					}
					if (sameRouters
							.contains(dstCell.getClosestRouters().get(1))) {
						// rovna sa jeden z routrov
						// System.out.println("jeden router spolocny");
						getDrawnPathByOneSameRouter(dstCell.getClosestRouters()
								.get(1), startCell, dstCell, drawnPath);
						return drawnPath;
						/*
						 * return getDistanceByOneSameRouter(dstCell
						 * .getClosestDistances().get(1), dstCell, dstCell
						 * .getClosestRouters().get(1), startCell, drawnPath);
						 */
					}

					else {
						// nerovna sa ani jeden z routrov, ale neviem ci su dva
						// alebo jeden, ale maju rovnaku velkost
						// System.out.println("nie su na rovnakej ceste");
						Path p = getPathBetweenTwoCells(startCell, dstCell);
						GuiPainting.preparePathBetweenRouters(
								String.valueOf(p), drawnPath);
						return drawnPath;
					}
				}
				// /////////////////////////////////////////
			} else {
				// velkosti sa nerovnaju, jedna bunka ma jeden router a druha ma
				// dva
				// routre
				// nemozu byt na rovnakej ceste
				// mam na to uz metodu
				Path p;
				if (startCell.getClosestRouters().size() == 1) {
					// tu este moze byt spolocny router
					// System.out.println("jeden spolocny router");
					Router r = startCell.getClosestRouters().get(0);
					if (r == dstCell.getClosestRouters().get(0)
							|| r == dstCell.getClosestRouters().get(1)) {
						drawnPath = getDrawnPathByOneSameRouter(r, startCell,
								dstCell, drawnPath);
						return drawnPath;
					}

					// start ma jeden router
					// int d = startCell.getClosestDistances().get(0);
					p = getPathFromStartRouter(startCell.getClosestRouters()
							.get(0), dstCell, drawnPath);
					if (p != null) {
						GuiPainting.preparePathBetweenRouters(
								String.valueOf(p), drawnPath);
						return drawnPath;
					}
					return drawnPath;

				} else {
					// otocim vstup - dst ma jeden router
					// tu este moze byt spolocny router
					// System.out.println("jeden spolocny router");
					Router r = dstCell.getClosestRouters().get(0);
					if (r == startCell.getClosestRouters().get(0)
							|| r == startCell.getClosestRouters().get(1)) {
						drawnPath = getDrawnPathByOneSameRouter(r, startCell,
								dstCell, drawnPath);
						return drawnPath;
					}

					// int d = dstCell.getClosestDistances().get(0);
					p = getPathFromDstRouter(startCell, dstCell
							.getClosestRouters().get(0), drawnPath);
					if (p != null) {

						GuiPainting.preparePathBetweenRouters(
								String.valueOf(p), drawnPath);

						return drawnPath;
					}
					return drawnPath;

				}

			}
		} catch (Exception e) {
			// TODO: handle exception
			// ak to niekde spadne, prehladam bunky BFSkom
			System.out.println("Exception - BFS");
			Vector<AbstractStockCell> path = new Vector<AbstractStockCell>();
			Vector<AbstractStockCell> target = new Vector<AbstractStockCell>();
			path.add(startCell);
			target.add(dstCell);
			recalculatePath(path, target);
			path.remove(0);
			drawnPath.route.setCellsInPath(path);
		}
		return drawnPath;

	}

	public static Path findPathFromCoordinates(int startX, int startY,
			int dstX, int dstY) {
		findPathFromCells(
				s.getFieldIndex(startX / s.getDelimiter(),
						startY / s.getDelimiter()),
				s.getFieldIndex(dstX / s.getDelimiter(),
						dstY / s.getDelimiter()));
		return null;

	}

	public static DrawnPathCrate findPathFromFieldIndex(int startX, int startY,
			int dstX, int dstY) {

		return findPathFromCells(s.getFieldIndex(startX, startY),
				s.getFieldIndex(dstX, dstY));
	}

	private static boolean isRouterCell(AbstractStockCell c) {
		boolean isRouter = false;
		if (c.getClass() != RackCell.class && c.getClass() != BorderCell.class) {
			// je to router?
			if (c.getClass() == RouterCell.class) {
				isRouter = true;
			}
		} else {

			return false;
		}
		return isRouter;
	}

	public static void sortAndAccidentCheck(DrawnPathCrate drawnPath) {
		Vector<AbstractStockCell> path = new Vector<AbstractStockCell>();
		Vector<AbstractStockCell> target = new Vector<AbstractStockCell>();

		Vector<AbstractStockCell> oldPath = drawnPath.route.getCellsInPath();
		// pridam start
		path.add(drawnPath.start);
		target.add(drawnPath.dst);
		while (!oldPath.isEmpty()) {

			for (int i = 0; i < oldPath.size(); i++) {
				AbstractStockCell cell = oldPath.get(i);
				AbstractStockCell c = path.get(path.size() - 1);
				// hladaj pokracovanie cesty
				if ((cell.getX() == c.getX() - 1 && cell.getY() == c.getY())
						|| (cell.getX() == c.getX() + 1 && cell.getY() == c
								.getY())
						|| (cell.getX() == c.getX() && cell.getY() == c.getY() - 1)
						|| (cell.getX() == c.getX() && cell.getY() == c.getY() + 1)) {
					// tadialto pokracuje cesta
					// ak nie je nehoda pridam do cesty
					if (!s.containsAccident(cell)) {
						path.add(cell);

						// vymazem bunku zo starej cesty aby sa necyklilo a
						// break
						oldPath.remove(i);

						break;
					} else {
						// je tam nehoda, treba zoradit target
						
						sortTargetPath(target, oldPath);
						// prehladanie alternativnej cesty - BFS
						//removeVectorItemsAfter(path, i);
						path.removeAllElements();
						path.add(drawnPath.start);
						recalculatePath(path, target);
					}
				} else {
				
					oldPath.removeAll(oldPath);
					recalculatePath(path, target);

				}

			}

		}

		// System.out.println("size path = " + path.size());
		path.remove(0);
		checkReachable(drawnPath, path);
		drawnPath.route.setCellsInPath(path);
	}

	private static void checkReachable(DrawnPathCrate path,
			Vector<AbstractStockCell> cells) {
		AbstractStockCell a;
		try {
			a = cells.get(cells.size() - 1);
		} catch (Exception e) {
			a = path.start;
		}
		if ((a.getX() == path.dst.getX() - 1 && a.getY() == path.dst.getY())
				|| (a.getX() == path.dst.getX() + 1 && a.getY() == path.dst
						.getY())
				|| (a.getX() == path.dst.getX() && a.getY() == path.dst.getY() - 1)
				|| (a.getX() == path.dst.getX() && a.getY() == path.dst.getY() + 1)) {
			// tadialto pokracuje cesta
			return;
		} else {
			Vector<AbstractStockCell> target = new Vector<AbstractStockCell>();
			target.add(path.dst);
			if (cells.size() == 0)
				cells.add(path.start);
			recalculatePath(cells, target);
		}

	}

	private static void sortTargetPath(Vector<AbstractStockCell> target,
			Vector<AbstractStockCell> oldPath) {

		while (!oldPath.isEmpty()) {

			for (int i = 0; i < oldPath.size(); i++) {
				AbstractStockCell cell = oldPath.get(i);
				AbstractStockCell c = target.get(target.size() - 1);
				// hladaj pokracovanie cesty
				if (cell.getX() == c.getX() - 1 && cell.getY() == c.getY()
						|| cell.getX() == c.getX() + 1
						&& cell.getY() == c.getY() || cell.getX() == c.getX()
						&& cell.getY() == c.getY() - 1
						|| cell.getX() == c.getX()
						&& cell.getY() == c.getY() + 1) {
					// tadialto pokracuje cesta
					// ak nie je nehoda pridam do cesty
					if (!s.containsAccident(cell)) {
						target.add(cell);

						// vymazem bunku zo starej cesty aby sa necyklilo a
						// break
						oldPath.remove(i);

						break;
					} else {
						// je tam nehoda, vymazat celu staru cestu
						oldPath.removeAll(oldPath);
						return;
					}
				} else {
					oldPath.removeAll(oldPath);

				}
			}
		}
	}

	private static void recalculatePath(Vector<AbstractStockCell> path,
			Vector<AbstractStockCell> target) {
		// bfs zacina od miesta najblizsie k nehode
		BFScellCrate root = new BFScellCrate(null, path.get(path.size() - 1));
		//BFScellCrate root = new BFScellCrate(null, path.get(0));
		//removeVectorItemsAfter(path, 0);
		// System.out.println("size path " + path.size());

		LinkedList<BFScellCrate> open = new LinkedList<>();
		HashSet<AbstractStockCell> closed = new HashSet<>();
		// pridaj vychozi bod do open
		continueBFS = true;
		open.add(root);
		int x;
		int y;
		while (!open.isEmpty() && continueBFS) {

			x = open.getFirst().cell.getX();
			y = open.getFirst().cell.getY();

			// pridat do navstivenych
			closed.add(open.getFirst().cell);
			// GuiPainting.drawImage(GlobalParameters.routeImage,
			// GuiMethods.getFieldFromIndexX(x),GuiMethods.getFieldFromIndexY(y));

			AbstractStockCell tmp;
			// pozret vsetky smery a pridat mozne do open
			tmp = s.getFieldIndex(x - 1, y);
			processBFStmp(open, closed, tmp, path, target);
			tmp = s.getFieldIndex(x + 1, y);
			processBFStmp(open, closed, tmp, path, target);
			tmp = s.getFieldIndex(x, y - 1);
			processBFStmp(open, closed, tmp, path, target);
			tmp = s.getFieldIndex(x, y + 1);
			processBFStmp(open, closed, tmp, path, target);
			// vymazat z open
			open.remove(open.getFirst());

		}
		
	}

	

	private static void processBFStmp(LinkedList<BFScellCrate> open,
			HashSet<AbstractStockCell> closed, AbstractStockCell tmp,
			Vector<AbstractStockCell> path, Vector<AbstractStockCell> target) {
		// pozriet ci nie je v closed
		if (closed.contains(tmp))
			return;
		// pozriet ci je v dst
		for (int i = 0; i < target.size(); i++) {
			if (tmp.getX() == target.get(i).getX()
					&& tmp.getY() == target.get(i).getY()) {

				// vymazat bunky do konca (smerom po nehodu)
				removeVectorItemsAfter(target, i);
				// pridat bunky do konecnej cesty
				completeRecalculatedPath(open.getFirst(), path, target);
				continueBFS = false;
			}
		}
		// ak to nie je regal alebo hranica, alebo nehoda pridat do open
		if (tmp.getClass() == CoridorCell.class
				|| tmp.getClass() == RouterCell.class) {
			if (!s.containsAccident(tmp)) {
				open.add(new BFScellCrate(open.getFirst(), tmp));
				// GuiPainting.drawImage(GlobalParameters.rampImage,
				// GuiMethods.getFieldFromIndexX(tmp.getX()),GuiMethods.getFieldFromIndexY(
				// tmp.getY()));
			}
		}
	}

	private static void completeRecalculatedPath(BFScellCrate cellCrate,
			Vector<AbstractStockCell> path, Vector<AbstractStockCell> target) {

		BFScellCrate bfsTmp = cellCrate;
		AbstractStockCell tmp = bfsTmp.cell;
		
		// narazil som uz na cestu?
		int flag = 0;
		while (flag == 0) {
			for (int i = 0; i < path.size(); i++) {
				if (tmp.getX() == path.get(i).getX()
						&& tmp.getY() == path.get(i).getY()) {
					// narazilo sa na cestu, koniec pridavania a vymazat zvysok
					// ku
					// nehode
					removeVectorItemsAfter(path, i);
					// pridat ostatne bunky z target do path
					addTargetCellsToPath(path, target);

					flag = 1;
					return;
				}
			}

			// pridat do target bunku od ktorej sa to naslo
			target.add(tmp);
			// tmp nastavit na parenta
			bfsTmp = bfsTmp.parentCell;
			tmp = bfsTmp.cell;
			/*
			 * GuiPainting.drawImage(GlobalParameters.rampImage,
			 * GuiMethods.getFieldFromIndexX
			 * (tmp.getX()),GuiMethods.getFieldFromIndexY( tmp.getY()));
			 */

		}
	}

	private static void removeVectorItemsAfter(Vector<AbstractStockCell> v,
			int i) {
		int size = v.size();
		i++;
		try {
			for (int j = i; j < size; j++) {
				v.remove(j);
				j--;
			}
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("out of range");
		}
	}

	private static void addTargetCellsToPath(Vector<AbstractStockCell> path,
			Vector<AbstractStockCell> target) {
		// opacne poradie

		int size = target.size() - 1;

		for (int i = 0; i < size; i++) {
			path.add(target.get(size - i));
		}
	}
}
