package Segmentation;

public class Toggle {

	public static int[] toggle (double I[], int sigma, int iter, int nrows, int ncols, int level) {
	   
		int   i;

	    int[] E = new int[nrows * ncols];
	    int[] D = new int[nrows * ncols];
	    int[] T = new int[nrows * ncols];
	    int[] TMP = new int[nrows * ncols];
	    
	    copy_vector (I, TMP, nrows*ncols);
	    
	    for(i = 0; i < iter; i++){
	          SSerosion (TMP, E, nrows, ncols, sigma, level);
	          copy_vector (E, TMP, nrows*ncols);
	    }

	    copy_vector (I, TMP, nrows*ncols);
	    
	    for(i = 0; i < iter; i++){
	          SSdilation (TMP, D, nrows, ncols, sigma, level);
	          copy_vector (D, TMP, nrows*ncols);
	    }

	    ApplyToggle (I, D, E, T, nrows, ncols);
	    
	    return T;
	}
	
	public static void copy_vector (double[] source, int[] target, int size) {
		for (int i = 0; i < size; i++) {
			target[i] = (int)source[i];
		}
	}

	public static void copy_vector (int[] source, int[] target, int size) {
		for (int i = 0; i < size; i++) {
			target[i] = source[i];
		}
	}
	
	public static void ApplyToggle (double I[], int D[], int E[], int T[], int nrows, int ncols) {

		int x, y, p;
		int MAX_GREY_LEVEL = 255;

		for (x = 0; x < nrows; x++){
			for (y = 0; y < ncols; y++) {
				p = x*ncols + y;
				double DminusI = D[p] - I[p];
	            double IminusE = I[p] - E[p];
				if (DminusI <= IminusE) {
					T[p] = MAX_GREY_LEVEL;
				}
				else {
					T[p] = 0;
					
				}
			}
		}
	}
	
	public static void ApplyToggle2 (double I[], int D[], int E[], int T[], int nrows, int ncols) {

		int x, y, p;
		int MAX_GREY_LEVEL = 255;

		int contrast1 = 8;
		int contrast2 = 35;
		int percentage = 79;

		for (x = 0; x < nrows; x++){
			for (y = 0; y < ncols; y++) {
				p = x*ncols + y;
				if ( (D[p] - E[p]) < contrast1 ) {
					T[p] = MAX_GREY_LEVEL;
				}
				else if ( (D[p] - E[p]) < contrast2) {
					if ( (D[p] - I[p]) < percentage * (I[p] - E[p])/100.0 ) {
						T[p] = MAX_GREY_LEVEL;
					}
					else {
						T[p] = 0;
					}
				}
				else {
					if ( (D[p] - I[p]) < percentage * (I[p] - E[p])/100.0 ) {
						T[p] = 0;
					}
					else {
						T[p] = MAX_GREY_LEVEL;
					}
				}
			}
		}
	}
	
	public static void SSerosion (int I[], int O[], int nrows, int ncols, int sigma, int level) {

	    int MAX_GREY_LEVEL = 255;
	    int MASK_SIZE;
	    if (level < 3) {
	    	MASK_SIZE = 6;
	    }
	    else {
	    	MASK_SIZE = 3;
	    }
	    int x, y, p, dx, dy, min;
	    int hmask = MASK_SIZE/2;

	    for (x = 0; x < nrows; x++){
	        for (y = 0; y < ncols; y++) {
	            if (isEdge(nrows, ncols, x, y, hmask)) {
	                p = x * ncols + y;
	                O[p] = I[p];
	            }
	            else {
	                min = MAX_GREY_LEVEL;
	                for (dx = -hmask; dx <= hmask; dx++){
	                    for (dy = -hmask; dy <= hmask; dy++){
	                        p = (x + dx)*ncols + y + dy;
	                        if(dx == 0 && dy == 0){
	                            if (I[p] < min) {
	                                min = I[p];
	                            }
	                        }
	                        else{
	                            if (I[p]+sigma < min) {
	                                min = I[p]+sigma;
	                            }
	                        }
	                    }
	                }
	                p = x*ncols + y;
	                O[p] = min;
	            }
	        }
	    }
	}

	public static void SSdilation(int I[], int O[], int nrows, int ncols, int sigma, int level) {

	    int MASK_SIZE;
	    if (level < 3) {
	    	MASK_SIZE = 6;
	    }
	    else {
	    	MASK_SIZE = 3;
	    }
	    int x, y, p, dx, dy, max;
	    int hmask = MASK_SIZE/2;

	    for (x = 0; x < nrows; x++){
	        for (y = 0; y < ncols; y++) {
	            if (isEdge(nrows, ncols, x, y, hmask)) {
	                p = x * ncols + y;
	                O[p] = I[p];
	            }
	            else {
	                max = 0;
	                for (dx = -hmask; dx <= hmask; dx++){
	                    for (dy = -hmask; dy <= hmask; dy++){
	                        p = (x + dx)*ncols + y + dy;
	                        if(dx == 0 && dy == 0){
	                            if (I[p] > max) {
	                                max = I[p];
	                            }
	                        }
	                        else{
	                            if (I[p]-sigma > max) {
	                                max = I[p]-sigma;
	                            }
	                        }
	                    }
	                }
	                p = x*ncols + y;
	                O[p] = max;
	            }
	        }
	    }
	}
	
	static boolean isEdge (int nrows, int ncols, int x, int y, int hmask) {
		if ( ((x - hmask) <= 0) || ((y - hmask) <= 0) || 
			 ((x + hmask) >= (nrows-1)) || ((y + hmask) >= (ncols-1))) {
			return true;
		}
		else {
			return false;
		}
	}
}
