var Selection = new Class({
	field: null,
	selected: [],
	
	initialize: function( field ) {
		this.field = field;
		
		for( var x = 0; x < this.field.size.x; x++ ) {
			this.selected[x] = [];
			for( var y = 0; y < this.field.size.y; y++ ) {
				this.selected[x][y] = 0;
			}
		}
	},
	
	_world2x: function( value ) {
		return Math.round( value * (this.field.size.x-1) );
	},

	_world2y: function( value ) {
		return Math.round( value * (this.field.size.y-1) );
	},

	
	// Copy the source selection to our own
	_copy: function( source ) {
		for( var x = 0; x < this.field.size.x; x++ ) {
			for( var y = 0; y < this.field.size.y; y++ ) {
				this.selected[x][y] = source[x][y];
			}
		}
	},


	// Main working function - calls an Effect for each selection in the grid
	each: function( callback, params, tick ) {
		for( var x = 0; x < this.field.size.x; x++ ) {
			for( var y = 0; y < this.field.size.y; y++ ) {
				if( this.selected[x][y] > 0 ) {
					callback( this.field.dots[x][y], tick, x, y, this.selected[x][y], params );
				}
			}
		}

		return this;
	},

	
	// All ----------------------------------------------------------------------------------------------
	all: function( amount ) {
		amount = $defined(amount) ? amount : 1;
		var result = new Selection( this.field );

		for( var x = 0; x < this.field.size.x; x++ ) {
			for( var y = 0; y < this.field.size.y; y++ ) {
				result.selected[x][y] = amount;
			}
		}
		return result;
	},


	// Rect ---------------------------------------------------------------------------------------------
	rect: function( left, top, right, bottom, amount ) {
		amount = $defined(amount) ? amount : 1;
		
		var result = new Selection( this.field );
		result._copy( this.selected );
		left = this._world2x( left );
		top = this._world2y( top );
		right = this._world2x( right );
		bottom = this._world2y( bottom );

		for( var x = left; x < right+1; x++ ) {
			result.selected[x][top] = amount;
			result.selected[x][bottom] = amount;
		}

		for( var y = top+1; y < bottom; y++ ) {
			result.selected[left][y] = amount;
			result.selected[right][y] = amount;
		}

		return result;
	},


	// Circle -------------------------------------------------------------------------------------------
	circle: function( cx, cy, r, amount ) {
		amount = $defined(amount) ? amount : 1;
		
		var result = new Selection( this.field );
		result._copy( this.selected );

		cx = this._world2x( cx );
		cy = this._world2y( cy );
		r = this._world2y( r );

		var x = 0;
		var y = r;
		var p = ( 5 - r * 4 )/4;

		result._circleSegment( Math.floor(cx), Math.floor(cy), Math.floor(x), Math.floor(y), amount );
		while( x < y ) {
			x++;
			if (p < 0) {
				p += 2 * x + 1;
			} else {
				y--;
				p += 2 * ( x-y ) + 1;
			}
			result._circleSegment( Math.floor(cx), Math.floor(cy), Math.floor(x), Math.floor(y), amount );
		}

		return result;
	},

	_circleSegment: function( cx, cy, x, y, amount ) {
		amount = $defined(amount) ? amount : 1;
		
		if( x == 0 ) {
			this.selected[cx][cy + y] = amount;
			this.selected[cx][cy - y] = amount;
			this.selected[cx + y][cy] = amount;
			this.selected[cx - y][cy] = amount;
		} else
		if( x == y ) {
			this.selected[cx + x][cy + y] = amount;
			this.selected[cx - x][cy + y] = amount;
			this.selected[cx + x][cy - y] = amount;
			this.selected[cx - x][cy - y] = amount;
		} else
		if( x < y ) {
			this.selected[cx + x][cy + y] = amount;
			this.selected[cx - x][cy + y] = amount;
			this.selected[cx + x][cy - y] = amount;
			this.selected[cx - x][cy - y] = amount;
			this.selected[cx + y][cy + x] = amount;
			this.selected[cx - y][cy + x] = amount;
			this.selected[cx + y][cy - x] = amount;
			this.selected[cx - y][cy - x] = amount;
		}
	},


	// Fill ---------------------------------------------------------------------------------------------
	fill: function( x, y, amount ) {
		amount = $defined(amount) ? amount : 1;
		
		var result = new Selection( this.field );
		result._copy( this.selected );

		if( amount <= 0 ) {
			return result;
		}

		x = this._world2x( x );
		y = this._world2y( y );

		var stack = [{x:x,y:y}];

		while( stack.length ) {
			var current = stack.pop();
			x = current.x;
			y = current.y;

			if( result.selected[x][y] == 0 ) {
				result.selected[x][y] = amount;

				if( y < this.field.size.y-1 )	stack.push( {x:x, y:y + 1} );
				if( y > 0 ) 					stack.push( {x:x, y:y - 1} );
				if( x < this.field.size.x-1 ) 	stack.push( {x:x + 1, y:y} );
				if( x > 0 ) 					stack.push( {x:x - 1, y:y} );
			}
		}

		return result;
	},


	// Ceil (unused?) -----------------------------------------------------------------------------------
	ceil: function() {

		var result = new Selection( this.field );

		for( var x = 0; x < this.field.size.x; x++ ) {
			for( var y = 0; y < this.field.size.y; y++ ) {
				result.selected[x][y] = this.selected[x][y] > 0 ? 1 : 0;
			}
		}

		return result;
	},


	// Glow (expand blur) -------------------------------------------------------------------------------
	glow: function( radius ) {

		var temp = new Selection( this.field );
		var result = new Selection( this.field );

		radius = this._world2y( radius );

		// horz
		for( var x = 0; x < this.field.size.x; x++ ) {
			for( var y = 0; y < this.field.size.y; y++ ) {
				var sum = 0;
				for( var kx = -radius; kx <= radius; kx++ ) {
					var tx = x + kx;
					if( tx < this.field.size.x -1 && tx > 0) {
						sum += this.selected[tx][y];
					}
				}
				var gh = sum / ( radius * 2 + 1 );
				temp.selected[x][y] = gh > this.selected[x][y] ? gh : this.selected[x][y];
			}
		}

		// vert
		for( x = 0; x < this.field.size.x; x++ ) {
			for( y = 0; y < this.field.size.y; y++ ) {
				sum = 0;
				for( var ky = -radius; ky <= radius; ky++ ) {
					var ty = y + ky;
					if( ty < this.field.size.y -1 && ty > 0) {
						sum += temp.selected[x][ty];
					}
				}
				var gv = sum / ( radius * 2 + 1 );
				result.selected[x][y] = gv > temp.selected[x][y] ? gv : temp.selected[x][y];
			}
		}

		return result;
	}
});

