/**
@author bibby
The all seeing eye. An object that tracks elements and their locations
to detect and allow/prevent collisons.
**/

var Contact = {
	
	// id to element references
	elements:{},
	
	getObject:function(id)
	{
		return this.elements[id];
	},
	//
	register:function(elm)
	{
		this.elements[elm.id]=elm;
		this.update(elm);
	},
	
	map:{},
	
	update:function(elm)
	{
		var area = elm.area();
		this.map[elm.id]={
			x:Math.range(area.x[0], area.x[1]),
			y:Math.range(area.y[0], area.y[1])
		};
	},
	
	/**
	@param object : data
	{
		id : string : id of element in motion (to exclude from seeing what's around)
		area : object : space requesting to be occupied {x:[x1,x2],y:[y1,y2]}
		property : string : style rule to modify (top|left)
		distance : int : distance to travel
	}
	**/
	mayMove:function(data)
	{
		// make sure that the object is indeed an object, that that it is moveable
		if(!is(this.getObject(data.id),'object'))
			return false;
		
		if(this.getObject(data.id).moveable != true)
			return false;
		
		// innocent until proven guilty
		//inMotion = {}.extend(data),
		var may = true,
		obstructions = [],
		move={},
		request={
			x:Math.range(data.area.x[0], data.area.x[1]),
			y:Math.range(data.area.y[0], data.area.y[1])
		};
		
		// find and list any objects sitting in the requested space
		for(id in this.map)
		{
			if(id == data.id || !is(this.map[id],'object'))
				continue;
			
			if(this.getObject(id)['class']=='Char')
				continue;
			
			if(!this.shares(request.x , this.map[id].x))
				continue;
			
			if(!this.shares(request.y , this.map[id].y))
				continue;
			obstructions.push(id);
		}
		
		// if there are any, this movement is contingent on the obstructions ability to move
		for(var i=0;i<obstructions.length;i++)
		{
			if( this.getObject(obstructions[i]).pos[data.property]+data.distance < 0)
				return false;
			
			data.extend({
				'id':obstructions[i],
				area:this.getObject(obstructions[i]).area(data.property, this.getObject(obstructions[i]).pos[data.property]+data.distance),
			},true);
			
			//may the obstruction move?
			if(!this.mayMove(data))
			{
				may = false;
				break;
			}
			else
				eval('move.extend({'+obstructions[i]+':data})');
		}
		
		// if we have only moveable obstructions, return these
		if(may==true && obstructions.length>0)
			this.callMove(move);
		
		return may;
	},
	
	/**
	a quick array instersect. returns true on first match
	@param array of ints A
	@param array of ints B
	@return bool shares a common value
	**/
	shares:function(a,b)
	{
		for(var i=0; i<a.length; i++)
		{
			if(b.in(a[i])!==false)
				return true;
		}
		return false;
	},
	
	callMove:function(moves)
	{
		for(id in moves)
		{
			if(is(moves[id],'function'))
				continue;
			
			moves[id].extend({ok:true});
			this.getObject(id).move(moves[id]);
		}
	}
};

