package com.rhomobile.rhodes.mapview;

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

import com.rhomobile.rhodes.mapview.MapTouch.Touch;

public class MultiTouchHandler implements TouchHandler {
	
	private static final String TAG = MultiTouchHandler.class.getSimpleName();
	
	private static final boolean DEBUG = false;

	private MapTouch mMapTouch;
	
	public void setMapTouch(MapTouch mapTouch) {
		mMapTouch = mapTouch;
	}
	
	private static final float CLICK_TOLERANCE = 8;
	private float mFirstTouchX;
	private float mFirstTouchY;
	private boolean mIsClickPossible;
	
	
	private void dumpEvent(MotionEvent event) {
		String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",
				"POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
		StringBuilder sb = new StringBuilder();
		int action = event.getAction();
		int actionCode = action & MotionEvent.ACTION_MASK;
		sb.append("event ACTION_").append(names[actionCode]);
		if (actionCode == MotionEvent.ACTION_POINTER_DOWN
				|| actionCode == MotionEvent.ACTION_POINTER_UP) {
			sb.append("(pid ").append(
					action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
			sb.append(")");
		}
		sb.append("[");
		for (int i = 0; i < event.getPointerCount(); i++) {
			sb.append("#").append(i);
			sb.append("(pid ").append(event.getPointerId(i));
			sb.append(")=").append((int) event.getX(i));
			sb.append(",").append((int) event.getY(i));
			if (i + 1 < event.getPointerCount())
				sb.append(";");
		}
		sb.append("]");
		Log.d(TAG, sb.toString());
	}
	
	@Override
	public boolean handleTouch(MotionEvent event) {
		if (DEBUG)
			dumpEvent(event);
		
		int action = event.getAction();
		int actionCode = action & MotionEvent.ACTION_MASK;
		
		Touch[] data = new Touch[Math.max(2, event.getPointerCount())];
		int i, lim;
		for (i = 0, lim = Math.min(data.length, event.getPointerCount()); i < lim; ++i)
			data[i] = new Touch(event.getX(i), event.getY(i));
		for (; i < data.length; ++i)
			data[i] = null;
		
		boolean isSingleTouch = (event.getPointerCount() < 2);
		
		switch (actionCode) {
		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_POINTER_DOWN:
			mIsClickPossible = isSingleTouch;
			mFirstTouchX = data[0].x;
			mFirstTouchY = data[0].y;
			mMapTouch.touchDown(data[0], data[1]);
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_UP:
			mMapTouch.touchUp(data[0], data[1]);
			if (isSingleTouch) {
				if (checkDistance(data[0].x, data[0].y, mFirstTouchX, mFirstTouchY, CLICK_TOLERANCE)) {
					mMapTouch.touchClick(data[0]);
				}
			}
			break;
		case MotionEvent.ACTION_MOVE:
			if (isSingleTouch) {
				if (!checkDistance(data[0].x, data[0].y, mFirstTouchX, mFirstTouchY, CLICK_TOLERANCE)) {
					mIsClickPossible = false;
				}
			}
			else {
				mIsClickPossible = false;
			}
			mMapTouch.touchMove(data[0], data[1]);
			break;
		}
		
		return true;
	}

	private boolean checkDistance(float x1, float y1, float x2, float y2, float delta) {
		float dx = x1 - x2;
		if (dx < 0) dx = -dx;
		float dy = y1 - y2;
		if (dy < 0) dy = -dy;
		return ((dx <= delta) && (dy <= delta));
	}
	
	
}