package com.gamepatriot.framework2d.implementation;

import java.util.ArrayList;

import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

import com.gamepatriot.androidframework.framework.AndroidInputter;
import com.gamepatriot.androidframework.framework.AndroidRenderer;
import com.gamepatriot.framework2d.implementation.Pool.PoolFactory;


/**
 * The Inputter class stores and retrieves all single-input actions that the application receives.
 * 
 * @see AndroidInputter
 * @author Pete Schmitz, May 9, 2013
 *
 */
public class Inputter implements AndroidInputter, OnTouchListener {
	
	/**
	 * The TouchEvent class stores information about an input.
	 * 
	 * @author Pete Schmitz, May 9, 2013
	 *
	 */
	public static class TouchEvent implements AndroidTouchEvent{
		
		/** Flag for type of input: Press. **/
		public static final int TOUCH_PRESS = 0;
		
		/** Flag for type of input: Release. **/
		public static final int TOUCH_RELEASE = 1;
		
		/** Flag for type of input: Movement. **/
		public static final int TOUCH_MOVE = 2;
		
		/** Flag for type of input: Back Pressed. **/
		public static final int TOUCH_BACK = 3;
		
		
		
		
		/** Type of input for this TouchEvent. See {@link #TOUCH_RELEASE} and {@link #TOUCH_PRESS}. **/
		public int type;
		
		/** Pixel-X position of this event. **/
		public int x;
		
		/** Pixel-Y position of this event. **/
		public int y;
	}
	
	
	//References
	
	private Renderer frameRenderer;
	
	
	//Containers
	
	/** Collection of input events **/
	private ArrayList<AndroidTouchEvent> events;
	
	/** Pool object for {@link AndroidTouchEvent} reusage. **/
	private Pool<AndroidTouchEvent> pool;
	
	
	/**
	 * Constructor.
	 * @param $frameRenderer - The application's {@link AndroidRenderer}; Used to assign a touch listener.
	 */
	public Inputter(AndroidRenderer $frameRenderer){
		
		//Assign renderer and apply listener
		frameRenderer = (Renderer) $frameRenderer;
		frameRenderer.setOnTouchListener(this);
		
		//Create a pool to reuse TouchEvents
		PoolFactory<AndroidTouchEvent> factory = new PoolFactory<AndroidTouchEvent>() {
			@Override
			public AndroidTouchEvent createObject() {
				return new TouchEvent();
			}
		};
		
		//Containers
		pool = new Pool<AndroidTouchEvent>(factory, 30);
		events = new ArrayList<AndroidTouchEvent>();
	}

	@Override
	public boolean onTouch(View $v, MotionEvent $e) {
		synchronized(events){
			
			int $action = $e.getAction();
			int $type;
			
			//Record the input's type and position
			if ($action == MotionEvent.ACTION_DOWN){
				$type = TouchEvent.TOUCH_PRESS;
			} else if ($action == MotionEvent.ACTION_CANCEL || $action == MotionEvent.ACTION_UP){
				$type = TouchEvent.TOUCH_RELEASE;
			} else if ($action == MotionEvent.ACTION_MOVE){
				$type = TouchEvent.TOUCH_MOVE;
			} else return false;
			
			//Register the input information and store it
			TouchEvent $touchEvent = (TouchEvent) pool.get();
			$touchEvent.x = (int) ($e.getX() / Main.CANVAS_SCALE_X);
			$touchEvent.y = (int) ($e.getY() / Main.CANVAS_SCALE_Y);
			$touchEvent.type = $type;
			
			events.add($touchEvent);
			
			return true;
		}
	}

	@Override
	public void pause() {
		frameRenderer.setOnTouchListener(null);
	}

	@Override
	public void resume() {
		frameRenderer.setOnTouchListener(this);
	}

	@Override
	public ArrayList<AndroidTouchEvent> getEvents() {
		return events;
	}

	@Override
	public void recycle(AndroidTouchEvent $touchEvent) {
		if ($touchEvent == null) return;
		
		pool.add($touchEvent);
	}
	
	@Override
	public void clear(){
		
		synchronized(events){
			events.clear();
		}
		
	}
	
	@Override
	public void insertBackPressed() {
		synchronized(events){
			TouchEvent $touchEvent = (TouchEvent) pool.get();
			$touchEvent.type = TouchEvent.TOUCH_BACK;
			events.add($touchEvent);
		}
	}
	
	
	
}
