package cz.vutbr.feec.libraryClasses;

import cz.vutbr.feec.libraryClasses.GraphCreatingMethods;
import cz.vutbr.feec.graph.Router;
import cz.vutbr.feec.project.GlobalParameters;
import cz.vutbr.feec.stockElements.AbstractStockCell;
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 ij.ImagePlus;
import ij.process.BinaryProcessor;
import ij.process.ByteProcessor;

public class Skeletonization {

	static Stock s = Stock.getInstance();
	final static int RECK = 255;
	final static int CORIDOR = 0;
	final static int ROUTER = 128;
	final static int BORDER = 70;
	static int length;
	static int width;

	private Skeletonization() {

	}

	public static ByteProcessor stockToSkelet() {

		// pridavam jedno policko na zaciatok a nakoniec pri inicializaci
		length = (int) (s.getLength() / s.getDelimiter());
		width = (int) (s.getWidth() / s.getDelimiter());
		AbstractStockCell[][] field = s.getField();
		// vytvorim byteprocesor
		ByteProcessor bp = new ByteProcessor(length, width);

		for (int i = 0; i < length; i++) { //
			for (int j = 0; j < width; j++) {//
				if (field[i][j].getClass() == RackCell.class) {
					bp.set(i, j, RECK);//
				} else if (field[i][j].getClass() == BorderCell.class) {
					bp.set(i, j, BORDER);
				}
				// pokial su zadane aj routre tak vykreslim aj routre
				else if (field[i][j].getClass() == RouterCell.class) {
					bp.set(i, j, ROUTER);
				}
				// pokial su zadane aj cesty tak vykreslim aj tie z mnoziny
				// ciest

			}
		}
		// zobraz
		if(GlobalParameters.isSkeletonImage)
		new ImagePlus("Original (bez cest)", bp.duplicate()).show();
		return bp;
	}

	// pridanie chybajucich buniek v skeletonizaci
	private static BinaryProcessor optimalizeSkelet(BinaryProcessor bp) {
		// musim prehladat vsetky bunky chodby
		for (int x = 0; x < length; x++) {
			for (int y = 0; y < width; y++) {
				// po skeletonizaci je farba chodby biela a cesta cierna
				// prehladam len chodby, nie regale ani okreje (aspon sa vyhnem
				// outOfBorder exception)

				if (s.getFieldIndex(x, y).getClass() == CoridorCell.class
						&& bp.get(x, y) == RECK) {
					// v podmienke reck preto, lebo pri skeletonizaci sa
					// natiahne farba recku aj na chodbu
					// v skeletu zostane cierna a ostatne co boli chodby su
					// biele
					int counter = 0;
					// potrebujem vygenerovat vsetky susedne kolme bunky
					for (int i = -1; i < 2; i = i + 2) {
						if ((bp.get(x + i, y) == CORIDOR)) {
							// pokial tam je cesta tak inkrementujem counter
							counter++;
						}
						if ((bp.get(x, y + i) == CORIDOR)) {
							counter++;
						}
					}
					// po skonceni generovani susednych buniek musim pozret
					// counter
					if (counter > 2) {
						bp.set(x, y, CORIDOR);
					}
				}

			}
		}
		if(GlobalParameters.isSkeletonImage)
		new ImagePlus("Skeletonizace optimalizovana", new BinaryProcessor(
				(ByteProcessor) bp.duplicate())).show();
		return bp;

	}
	
	


	// rovno vytvaram aj graf
	


	public static BinaryProcessor skeletonize(ByteProcessor bp){
		// Skeletonizace
				BinaryProcessor binp = new BinaryProcessor(
						(ByteProcessor) bp.duplicate());
				binp.skeletonize();
				if(GlobalParameters.isSkeletonImage)
				new ImagePlus("Po skeletonizaci", new BinaryProcessor(
						(ByteProcessor) binp.duplicate())).show();
				//tu pridavam metodu na pridanie buniek do nespravne vyhodnotenej skeletonizace
				Skeletonization.optimalizeSkelet(binp);
				//tu ukladam do GlobalParamterov kvoli save/load a kvoli accident
						
				findRouters(binp);
				
				//malo by tu byt este vykreslenie
				
		return binp;
		
		
	}
	public static BinaryProcessor findRouters(ByteProcessor bp) {
		BinaryProcessor binp = new BinaryProcessor((ByteProcessor) bp.duplicate());
		s.getRouters().removeAllElements();
		s.getPaths().removeAllElements();
		// vyhladanie miest kde maju byt smerovace
		for (int x = 0; x < length; x++) {
			for (int y = 0; y < width; y++) {
				if (binp.get(x, y) == CORIDOR) {
					// pre vsetky pixely (bunky) ktore su na ceste (kostre)
					
					try {
						// pri vytvarani noveho routra x-1 a y-1 ak sa pridavaju
						// extra riadky
						// vyhladanie kolmeho suseda
						if ((binp.get(x - 1, y) == CORIDOR)
								&& ((binp.get(x, y - 1) == CORIDOR) || binp
										.get(x, y + 1) == CORIDOR)) {
							// tu je smerovac
							if(!Skeletonization.isRouterAround(binp, x, y)){
							binp.set(x, y, ROUTER);
							Router router = new Router(x, y);// -1 -1
							s.addRouter(router);
							// pridavam routerCell do pola
							RouterCell rc = new RouterCell(x, y);
							// nastavim vazbu na router
							rc.setRouter(router);
							s.setFieldIndex(rc, x, y);
							// break;		
							}
						} else if ((binp.get(x + 1, y) == CORIDOR)
								&& ((binp.get(x, y - 1) == CORIDOR) || binp
										.get(x, y + 1) == CORIDOR)) {
							// tu je smerovac
							if(!Skeletonization.isRouterAround(binp, x, y)){
							binp.set(x, y, ROUTER);
							Router router = new Router(x, y);
							s.addRouter(router);
							// pridavam routerCell do pola
							RouterCell rc = new RouterCell(x, y);
							rc.setRouter(router);
							s.setFieldIndex(rc, x, y);
							// break;
							}
						} else if ((binp.get(x, y - 1) == CORIDOR)
								&& ((binp.get(x + 1, y) == CORIDOR) || binp
										.get(x - 1, y) == CORIDOR)) {
							// tu je smerovac
							if(!Skeletonization.isRouterAround(binp, x, y)){
							binp.set(x, y, ROUTER);
							Router router = new Router(x, y);
							s.addRouter(router);
							// pridavam routerCell do pola
							RouterCell rc = new RouterCell(x, y);
							rc.setRouter(router);
							s.setFieldIndex(rc, x, y);
							// break;
							}
						} else if ((binp.get(x, y + 1) == CORIDOR)
								&& ((binp.get(x + 1, y) == CORIDOR) || binp
										.get(x - 1, y) == CORIDOR)) {
							// tu je smerovac
							if(!Skeletonization.isRouterAround(binp, x, y)){
							binp.set(x, y, ROUTER);
							Router router = new Router(x, y);
							s.addRouter(router);
							// pridavam routerCell do pola
							RouterCell rc = new RouterCell(x, y);
							rc.setRouter(router);
							s.setFieldIndex(rc, x, y);
							// break;
							}
						}

					} catch (Exception e) {
						System.out.println("exception");
					}

				}
			}
		}
		findPaths(binp);
		GraphCreatingMethods.optimalizePaths();
		return binp;

	}

	public static void findPaths(BinaryProcessor binp) {
		// zacnem cyklom pre kazdy router
		int numberOfRouters = s.getRouters().size();
		System.out.println(s.getRouters().size());
		for (int a = 0; a < numberOfRouters; a++) {
			int x = s.getRouters().get(a).getxInField();
			int y = s.getRouters().get(a).getyInField();

			// router z ktoreho vychadzam - tzv first router
			Router r = s.getRouters().get(a);
			System.out.println("poloha routra: " + x + " " + y);

			// pre jeden router musim ceknut vsetky smery

			for (int i = x - 1; i < x + 2; i++) {
				for (int j = y - 1; j < y + 2; j++) {
					if ((binp.get(i, j) == CORIDOR) && !s.isCellInPath(i, j)) {
						
						GraphCreatingMethods.createPath(binp, r, i, j);
					}
				}
			}
			System.out.println("pocet ciest" + s.getPaths().size());
			System.out.println("pocdt routrov " + s.getRouters().size());
		}

	}
	private static boolean isRouterAround(BinaryProcessor binp, int x, int y){
		for (int i = x - 1; i < x + 2; i++) {
			for (int j = y - 1; j < y + 2; j++) {
				if (binp.get(i, j) == ROUTER) {
					return true;
				}
			}
		}
		return false;
	}
}
