/**
 * Spirit hand.
 */
gui.SpiritHand = function () {
	
	this.fingers = [];
	this.lifted = [];
};

gui.SpiritHand.prototype = {
	
	/**
	 * Tracking active fingers.
	 * @type {Array<gui.SpiritFinger>}
	 */
	fingers : null,
	
	/**
	 * Tracking removed fingers. Fingers will stay 
	 * removed; adding them again counts as new.
	 * TODO: THIS IS NOT TRUE! SAFARI IPAD RECYCLES!
	 * @type {Array<gui.SpiritFinger>}
	 */
	lifted : null,
	
	/**
	 * Touch start. Return fingers added.
	 * @param {TouchList} touches
	 * @returns {Array<gui.SpiritFinger>}
	 */
	start : function ( touches ) {
		
		var result = [];
		Array.forEach ( touches, function ( touch ) {
			var id = gui.SpiritTouch.getID ( touch.identifier );
			if ( !this._has ( id )) {
				var finger = this._add ( id );
				this._props.forEach ( function ( prop ) {
					finger.start [ prop ] = touch [ prop ];
					finger.current [ prop ] = touch [ prop ];
					finger.relative [ prop ] = touch [ prop ];
				});
				result.push ( finger );
			};
		}, this );
		return result;
	},
	
	/**
	 * Touch move. Return fingers moved.
	 * @param {TouchList} touches
	 * @returns {Array<gui.SpiritFinger>}
	 */
	move : function ( touches ) {
		
		/*
		 * TODO: turning point tracking
		 */
		var result = [];
		Array.forEach ( touches, function ( touch ) {
			var finger = this._get (
				gui.SpiritTouch.getID ( touch.identifier )
			);
			var s = finger.start, c = finger.current;
			this._props.forEach ( function ( prop ) {
				c [ prop ] = touch [ prop ];
			});
			c.diffX = c.clientX - s.clientX;
			c.diffY = c.clientY - s.clientY;
			
			result.push ( finger );
		}, this );
		return result;
	},
	
	/**
	 * Touch end. Return fingers lifted.
	 * @param {TouchList} changed
	 * @returns {Array<gui.SpiritFinger>}
	 */
	end : function ( changed ) {
		
		var result = [];
		this.fingers.forEach ( function ( finger ) {
			Array.forEach ( changed, function ( touch ) {
				var id = gui.SpiritTouch.getID ( touch.identifier );
				if ( finger.id === id ) {
					gui.SpiritTouch.forgetID ( touch.identifier );
					this._remove ( finger.id );
					finger.end = finger.current;
					result.push ( finger );
				}
			}, this );
		}, this );
		return result;
	},
	
	/**
	 * Open question: Will this somehow release the objects from  
	 * memory faster that the garbage collector can go get them? 
	 * If yes, we should employ this strategy on a global scale.
	 */
	trash : function () {
		
		// nulling finger pointers...
		this.lifted.forEach ( function ( finger, index ) {
			this.lifted [ index ] = null;
		}, this );
		
		this.fingers = null;
		this.lifted = null;
	},
	
	
	// PRIVATE ........................................................
	
	/**
	 * SpiritTouchPoint properties mapping directly to DOM TouchEvent.
	 * @type {Array<String>}
	 */
	_props : [
		"clientX",
		"clientY",
		"screenX",
		"screenY",
		"pageX",
		"pageY"
	],
	
	/**
	 * Get finger for id.
	 * @type {String} id
	 * @returns {gui.SpiritFinger}
	 */
	_get : function ( id ) {
		
		var result = null;
		this.fingers.every ( function ( finger ) {
			if ( finger.id === id ) {
				result = finger;
			}
			return result === null;
		});
		return result;
	},
	
	/**
	 * Has finger indexed?
	 * @param {String} id
	 * @returns {boolean}
	 */
	_has : function ( id ) {
		
		return this._get ( id ) !== null;
	},
	
	/**
	 * Add finger for id.
	 * @param {String} id
	 * @returns {gui.SpiritFinger}
	 */
	_add : function ( id ) {
		
		var finger = new gui.SpiritFinger ( id );
		this.fingers.push ( finger );
		return finger;
	},
	
	/**
	 * Remove finger for id.
	 * @param {String} id
	 * @param {String} identifier
	 */
	_remove : function ( id, identifier ) {
		
		this.fingers.forEach ( function ( finger, index ) {
			if ( finger.id === id ) {
				this.fingers.remove ( index );
				this.lifted.push ( finger );
			}
		}, this );
	}
};