package com.nutiteq.bbmaps;

import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.TouchEvent;

import com.nutiteq.BasicMapComponent;
import com.nutiteq.components.WgsPoint;
import com.nutiteq.listeners.MapListener;
import com.nutiteq.wrappers.AppContext;

public class MapFieldTouch extends Field implements MapListener{

	private int fieldWidth;
	private int fieldHeight;

    private final BasicMapComponent map;
    private MapListener mapListener;

    private Graphics wrapped;
    private com.nutiteq.wrappers.Graphics graphicsWrapper;

	private boolean dualZoom;

	// BlackBerry specific key and touch control handlers

	// Take it out for older than 4.7 BB API
	private int firstPointerX;
	private int firstPointerY;
	protected boolean touchEvent(TouchEvent event) {

		int eventCode = event.getEvent();
		boolean hasSecondPointer=true;
		if (event.getX(2)==-1 || event.getY(2)==-1){
			hasSecondPointer=false;
		}
		
		switch (eventCode) {
		case TouchEvent.CLICK:
			map.pointerPressed(event.getX(1), event.getY(1));
			break;
		case TouchEvent.DOWN:
			if (!hasSecondPointer){
				firstPointerX=event.getX(1);
				firstPointerY=event.getY(1);
				map.pointerPressed(firstPointerX, firstPointerY);
			}
			else if (hasSecondPointer && !dualZoom){
				dualZoom=true;
				double dist=Math.sqrt(
						(event.getX(2)-firstPointerX)  * (event.getX(2)-firstPointerX) +
						(event.getY(2)-firstPointerY)  * (event.getY(2)-firstPointerY));
				map.pointerDraggedDual(dist);
				map.startDualZoom((event.getX(1)+event.getX(2))/2, (event.getY(1)+event.getY(2))/2, dist);
			}
			break;
		case TouchEvent.MOVE:
			if (!hasSecondPointer && !dualZoom) {
				map.pointerDragged(event.getX(1), event.getY(1));
			} 
			else if (hasSecondPointer && dualZoom){
				double dist=Math.sqrt(
						(event.getX(2)-event.getX(1))  * (event.getX(2)-event.getX(1)) +
						(event.getY(2)-event.getY(1))  * (event.getY(2)-event.getY(1)));
				map.pointerDraggedDual(dist);
			}
			break;
		case TouchEvent.UNCLICK:
			map.pointerReleased(event.getX(1), event.getY(1));
			break;
		case TouchEvent.UP:
			map.pointerReleased(event.getX(1), event.getY(1));
			if (dualZoom){
				dualZoom=false; 
				map.stopDualZoom();
			}
			break;
		}

		return false;
	}


	protected boolean keyDown(int keycode, int time) {
		System.out.println("keyDown " + keycode + " time: " + time);
		map.keyPressed(Keypad.key(keycode));
		return super.keyDown(keycode, time);
	}

	protected boolean keyRepeat(int keycode, int time) {
		System.out.println("keyRepeat" + keycode + " time: " + time);
		map.keyRepeated(Keypad.key(keycode));
		return super.keyRepeat(keycode, time);
	}

    public MapFieldTouch(final String label, final String licenseKey,
            final String vendor, final String appname, final int width,
            final int height, final WgsPoint startPoint, final int zoom) {
        super(Field.FOCUSABLE);
        fieldWidth = width;
        fieldHeight = height;
        map = new BasicMapComponent(licenseKey, new AppContext(this), fieldWidth,
                fieldHeight, startPoint, zoom);
        map.setMapListener(this);
        
        this.setPadding(2, 2, 2, 2);
    }
	protected boolean keyUp(int keycode, int time) {
		System.out.println("keyUp" + keycode + " time: " + time);
		map.keyReleased(Keypad.key(keycode));
		return super.keyUp(keycode, time);
	}

	protected boolean navigationMovement(int dx, int dy, int status, int time) {
		System.out.println("navigationMovement dx" + dx + " dy " + dy
				+ " status " + status + " time " + time);
		map.panMap(dx * 10, dy * 10);
		// return super.navigationMovement(dx, dy, status, time);
		return false;
	}

	// General Map object handlers



	/**
	 * Initialize needed resources for mapping and start internal threads. This
	 * is a required step for application
	 */

	protected boolean navigationClick(int status, int time) {
		fieldChangeNotify(1);
		return true;
	}

	protected void onFocus(int direction) {
		System.out.println("onFocus map");
		invalidate();
	}

	protected void onUnfocus() {
		System.out.println("onUnfocus map");
		invalidate();
	}

	/*  
    public int getPreferredWidth() {
        return Display.getWidth();
    }

    public int getPreferredHeight() {
        return Display.getHeight()-40;
    }
	 */

	protected void layout(int w, int h) {
		setExtent(w, h);
	}

	protected void drawFocus(Graphics graphics, boolean on) {

	}
	
    protected void paint(Graphics g) {
        if (wrapped != g) {
            wrapped = g;
            graphicsWrapper = new com.nutiteq.wrappers.Graphics(g);
        }
		// paint on wrapper (in effect painting on native graphics)
		map.paint(graphicsWrapper);
		// remove pushContext() done inside library
		graphicsWrapper.popAll();
    }
        
	protected void fieldChangeNotify(int context) {
		try {
			this.getChangeListener().fieldChanged(this, context);
		} catch (Exception e) {
		}
	}


	// universial accessor for the map
	public BasicMapComponent getMap(){
		return this.map;
	}

	public void mapClicked(WgsPoint p) {
		if (mapListener != null) {
			mapListener.mapClicked(p);
		}
	}

	public void mapMoved() {
		if (mapListener != null) {
			mapListener.mapMoved();
		}
	}

	public void needRepaint(boolean mapIsComplete) {
		invalidate();
		if (mapListener != null) {
			mapListener.needRepaint(mapIsComplete);
		}
	}

	public void setMapListener(final MapListener mL) {
		mapListener = mL;
	}

}

