package com.beloko.idtech;

import java.io.IOException;

import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;

import com.beloko.idtech.GD.IDGame;
import com.beloko.idtech.QuakeControlConfig.Type;

public class QuakeControlInterpreter {

	String LOG = "QuakeControlInterpreter";

	QuakeControlInterface quakeIf;
	QuakeControlConfig config;

	boolean gamePadEnabled;
	
	int screenWidth, screenHeight;

	public QuakeControlInterpreter(QuakeControlInterface qif,IDGame game,String controlfile,boolean ctrlEn)
	{
		
		gamePadEnabled = ctrlEn;
		
		config = new QuakeControlConfig(controlfile,game);
		try {
			config.loadControls();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		quakeIf = qif;
	}

	public void setScreenSize(int w,int h)
	{
		screenWidth = w;
		screenHeight = h;
	}

	public boolean onTouchEvent(MotionEvent event)
	{
		int action = event.getAction();
		int actionCode = action & MotionEvent.ACTION_MASK;

		if (actionCode == MotionEvent.ACTION_MOVE)
		{
			for (int i = 0; i < event.getPointerCount(); i++) {

				float x = event.getX(i)/screenWidth;
				float y = event.getY(i)/screenHeight;
				int pid = event.getPointerId(i);
				quakeIf.touchEvent_if(3, pid, x, y);
			}
		}
		else if (actionCode == MotionEvent.ACTION_DOWN)
		{
			float x = event.getX()/screenWidth;
			float y = event.getY()/screenHeight;

			quakeIf.touchEvent_if(1, 0, x, y);
		}
		else if (actionCode == MotionEvent.ACTION_POINTER_DOWN)
		{
			int index = event.getActionIndex();
			if (index != -1)
			{
				float x = event.getX(index)/screenWidth;
				float y = event.getY(index)/screenHeight;
				int pid = event.getPointerId(index);
				quakeIf.touchEvent_if(1, pid, x, y); 
			}
		}
		else if (actionCode == MotionEvent.ACTION_POINTER_UP)
		{
			int index = event.getActionIndex();
			if (index != -1)
			{

				float x = event.getX(index)/screenWidth;
				float y = event.getY(index)/screenHeight;
				int pid = event.getPointerId(index);
				quakeIf.touchEvent_if(2, pid, x, y);
			}
		}
		else if (actionCode == MotionEvent.ACTION_UP)
		{
			float x = event.getX()/screenWidth;
			float y = event.getY()/screenHeight;
			int index = event.getActionIndex();
			int pid = event.getPointerId(index);

			quakeIf.touchEvent_if(2, pid, x, y);
		}

		return true;
	}



	public boolean onKeyDown(int keyCode, KeyEvent event)
	{
		if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) ||
				(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) ||
				(keyCode == KeyEvent.KEYCODE_SEARCH))
			return false;

		if (gamePadEnabled)
		{
			

			for (ActionInput ai: config.actions)
			{
				if ((ai.sourceType == Type.BUTTON) && (ai.source == keyCode))
				{
					quakeIf.doAction_if(1, ai.actionCode);
					Log.d(LOG,"key down intercept");
					return true;
				}
			}
		}
		Log.d(LOG,"key down = " + keyCode);
		int uc = event.getUnicodeChar();
		quakeIf.keyPress_if(1, quakeIf.mapKey(keyCode, event), uc);
		return true;
	}

	public boolean onKeyUp(int keyCode, KeyEvent event)
	{
		if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) ||
				(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) ||
				(keyCode == KeyEvent.KEYCODE_SEARCH))
			return false;

		if (gamePadEnabled)
		{
			for (ActionInput ai: config.actions)
			{
				if ((ai.sourceType == Type.BUTTON) && (ai.source == keyCode))
				{
					quakeIf.doAction_if(0, ai.actionCode);
					return true;
				}
			}
		}

		int uc = event.getUnicodeChar();
		quakeIf.keyPress_if(0, quakeIf.mapKey(keyCode, event), uc);
		return true;
	}

	float deadRegion = 0.2f;
	private float analogCalibrate(float v)
	{
		if ((v < deadRegion) && (v > -deadRegion))
			return 0;
		else
		{
			if (v > 0)
				return(v-deadRegion) / (1-deadRegion);
			else
				return(v+deadRegion) / (1-deadRegion);
			//return v;
		}
	}

	public boolean onGenericMotionEvent(MotionEvent event) {
		if (GD.DEBUG) Log.d(LOG,"onGenericMotionEvent" );

		boolean used = false;
		if (gamePadEnabled)
		{
			for (ActionInput ai: config.actions)
			{
				if ((ai.sourceType == Type.ANALOG) && (ai.source != -1))
				{
					int invert;
					invert = ai.invert?-1:1;
					if (ai.actionCode == QuakeControlConfig.ACTION_ANALOG_PITCH)
						quakeIf.analogPitch_if(QuakeControlConfig.LOOK_MODE_JOYSTICK, analogCalibrate(event.getAxisValue(ai.source)) * invert * ai.scale);
					else if (ai.actionCode == QuakeControlConfig.ACTION_ANALOG_YAW)
						quakeIf.analogYaw_if(QuakeControlConfig.LOOK_MODE_JOYSTICK, -analogCalibrate(event.getAxisValue(ai.source)) * invert * ai.scale);
					else if (ai.actionCode == QuakeControlConfig.ACTION_ANALOG_FWD)
						quakeIf.analogFwd_if(-analogCalibrate(event.getAxisValue(ai.source)) * invert * ai.scale);
					else if (ai.actionCode == QuakeControlConfig.ACTION_ANALOG_STRAFE)
						quakeIf.analogSide_if(analogCalibrate(event.getAxisValue(ai.source)) * invert * ai.scale);
					else //Must be using analog as a button
					{  
						if (GD.DEBUG) Log.d(LOG,"Analog as button" );

						if (GD.DEBUG) Log.d(LOG,ai.toString());
						
						if (((ai.sourcePositive) && (event.getAxisValue(ai.source)) > 0.5) ||
								((!ai.sourcePositive) && (event.getAxisValue(ai.source)) < -0.5) )
							quakeIf.doAction_if(1, ai.actionCode); //press
						else
							quakeIf.doAction_if(0, ai.actionCode); //un-press

					}
					used = true;
				}
			}

		}


		return used;

	}
}
