package cz.vutbr.feec.imageprocessing.op.segmentation.watershed;

import java.awt.Color;
import java.util.ArrayList;
import ij.ImagePlus;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;

public class ImageStructure {
	
	private ConnectivityModels connectivityModel;
	
	//fields
	private int width;
	private int height;
	private WPoint[][] points;
	private RgbToGSModel convertModel;

	
	//constructors
	public ImageStructure(ImagePlus inputImage, RgbToGSModel convertModel, ConnectivityModels connectivityModel) {
		this.connectivityModel = connectivityModel;
		
		this.width = inputImage.getWidth();
		this.height = inputImage.getHeight();
		this.convertModel = convertModel;
		this.points = new WPoint [width][height];
		
		ColorProcessor ip = (ColorProcessor) inputImage.getProcessor();
		// get data
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				points[x][y] = new WPoint(this, x, y, ip.getColor(x, y));
			}
		}
	}
	
	//methods
	public RgbToGSModel getConvertModel() {
		return this.convertModel;
	}
	
	public WPoint getPoint(int x, int y) {
		return points[x][y];
	}
	
	public ArrayList<WPoint> getNeighborsFor (int x, int y) {
		ArrayList<WPoint> neighbors = new ArrayList<WPoint> ();
		
		search: {
		if (0 < x && x < (width - 1) && 0 < y && y < (height - 1)) {
			neighbors.add(points[x-1][y]);
			neighbors.add(points[x+1][y]);
			neighbors.add(points[x][y-1]);
			neighbors.add(points[x][y+1]);
			if (ConnectivityModels.C8.equals(connectivityModel)) {
				neighbors.add(points[x-1][y-1]);
				neighbors.add(points[x-1][y+1]);
				neighbors.add(points[x+1][y-1]);
				neighbors.add(points[x+1][y+1]);
				}
			break search;
			}

		// edges
		//top edge
		if (0 < x && x < (width - 1) && y == 0) {
			neighbors.add(points[x-1][y]);
			neighbors.add(points[x+1][y]);
			neighbors.add(points[x][y+1]);
			if (ConnectivityModels.C8.equals(connectivityModel)) {
				neighbors.add(points[x-1][y+1]);
				neighbors.add(points[x+1][y+1]);
				}
			break search;
			}
		//bottom edge
		if (0 < x && x < (width - 1) && y == (height - 1)) {
			neighbors.add(points[x-1][y]);
			neighbors.add(points[x+1][y]);
			neighbors.add(points[x][y-1]);
			if (ConnectivityModels.C8.equals(connectivityModel)) {
				neighbors.add(points[x-1][y-1]);
				neighbors.add(points[x+1][y-1]);
				}
			break search;
			}
		//left edge
		if (x == 0 && 0 < y && y < (height - 1)) {
			neighbors.add(points[x+1][y]);
			neighbors.add(points[x][y-1]);
			neighbors.add(points[x][y+1]);
			if (ConnectivityModels.C8.equals(connectivityModel)) {
				neighbors.add(points[x+1][y-1]);
				neighbors.add(points[x+1][y+1]);
				}
			break search;
			}
		//right edge
		if (x == (width - 1) && 0 < y && y < (height - 1)) {
			neighbors.add(points[x-1][y]);
			neighbors.add(points[x][y-1]);
			neighbors.add(points[x][y+1]);
			if (ConnectivityModels.C8.equals(connectivityModel)) {
				neighbors.add(points[x-1][y-1]);
				neighbors.add(points[x-1][y+1]);
				}
			break search;
			}

		// corners
		//top left corner
		if (x == 0 && y == 0) {
			neighbors.add(points[x+1][y]);
			neighbors.add(points[x][y+1]);
			if (ConnectivityModels.C8.equals(connectivityModel))
				neighbors.add(points[x+1][y+1]);
			break search;
			}
		//top right corner
		if (x == (width - 1) && y == 0) {
			neighbors.add(points[x-1][y]);
			neighbors.add(points[x][y+1]);
			if (ConnectivityModels.C8.equals(connectivityModel))
				neighbors.add(points[x-1][y+1]);
			break search;
			}
		//bottom left corner
		if (x == 0 && y == (height - 1)) {
			neighbors.add(points[x+1][y]);
			neighbors.add(points[x][y-1]);
			if (ConnectivityModels.C8.equals(connectivityModel))
				neighbors.add(points[x+1][y-1]);
			break search;
			}
		//bottom right corner
		if (x == (width - 1) && y == (height - 1)) {
			neighbors.add(points[x-1][y]);
			neighbors.add(points[x][y-1]);
			if (ConnectivityModels.C8.equals(connectivityModel))
				neighbors.add(points[x-1][y-1]);
			break search;
			}
		}
		return neighbors;
	}
	
	
	public ImagePlus convertToResultingImage() {
		return deliverResultImage(null, false);
	}
	
	public ImagePlus deliverResultImage(Region[] regions, Boolean showWsheds) {
		//http://albert.rierol.net/imagej_programming_tutorials.html
		ImageProcessor ip = new ColorProcessor(width, height);
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				WPoint cp = this.getPoint(x, y);
				
				if (showWsheds && cp.wasWaterShad())
				{
					ip.set(y * width + x, Color.RED.getRGB());
					continue;
				}
				
				if (regions != null)
				{
					Region reg = regions[cp.getLabel()];
					ip.set(y * width + x, reg.getAvgColor().getRGB());
					continue;
				} 
					
				ip.set(y * width + x, this.getPoint(x,y).getColor().getRGB());
			}
		}
		ImagePlus img = new ImagePlus("obrazek", ip);
		return img;
	}

	

}
