import java.util.Iterator;

import lejos.geom.Rectangle;

public class ProbabilityMatriz implements Iterable<DiscretePoint> {
	public class MatrizIterator implements Iterator<DiscretePoint> {
		private final ProbabilityMatriz m;
		public long count = 0;
		public long end = totalsize;

		public MatrizIterator(ProbabilityMatriz m) {
			this.m = m;
		}

		public void set (long start, long end) {
			this.end = end;
			this.count = start;
		}

		@Override
		public boolean hasNext() {
			return count < end;
		}

		@Override
		public DiscretePoint next() {
			int b = matriz[0].length;
			int c = matriz[0][0].length;
			
			int x = (int) (count/(b*c));
			int y = (int) (count%(c*b)/c);
			int z = (int) (count%c);
			DiscretePoint tmp = new DiscretePoint(m, x, y, z);
			count++;
			return tmp;
		}
	}

	/*
	 * Recebe as bordas dos triangulos da matriz (bounds)
	 * ssize - squere size, tamanho do quadrado utilizado na discretizacao
	 * alphad - em quantas partes sera dividido os angulos
	 */
	Rectangle bounds;
	double[][][] matriz;
	double ssize;
	int alphad;
	long totalsize;
	ProbabilityMatriz (Rectangle bounds, double ssize, int alphad) {
		this.bounds = bounds;
		this.ssize = ssize;
		this.alphad = alphad;
		int x = (int) Math.ceil(bounds.getWidth()/ssize);
		int y = (int) Math.ceil(bounds.getHeight()/ssize);
		matriz = new double[x][y][alphad];
		totalsize = matriz.length*matriz[0].length*matriz[0][0].length;
		setAll(1);
		normalize();
	}
	

	/*
	 * Retorna a probabilidade maxima
	 */
	double max () {
		double max = 0;
		for (DiscretePoint p: this)
			max = Math.max(max, p.get());
		return max;
	}
	
	/*
	 * adiciona a todos
	 */
	void setAll (double v) {
		for (DiscretePoint p: this)
			p.set(v);
	}

	/*
	 * Retorna a soma de todos o pontos
	 */
	double sum () {
		double x = 0;
		for (DiscretePoint p: this)
			x += p.get();
		return x;
	}
	
	/*
	 * Faz a soma ser 1
	 */
	void normalize () {
		double s = sum();
		for (DiscretePoint p: this)
			p.set(p.get()/s);
	}

	@Override
	public Iterator<DiscretePoint> iterator() {
		ProbabilityMatriz m = this;
		return new MatrizIterator(m);
	}

	public void set(double v, int x, int y, int z) {
		matriz[x][y][z] = v;
	}

	public double get(int x, int y, int z) {
		return matriz[x][y][z];
	}


	public Iterator<DiscretePoint> iteratorSet(long start, long end) {
		ProbabilityMatriz m = this;
		MatrizIterator it = new MatrizIterator(m);
		it.set(start, end);
		return new MatrizIterator(m);
	}
}
