public interface MixContextInterface {

	void loadMixViewWebPage(String url)  throws Exception ;

} public interface MixStateInterface {

	boolean handleEvent(MixContextInterface ctx, String onPress);
	
} public class Label implements ScreenObj, Parcelable {
	private float x, y;
	private float width, height;
	private ScreenObj obj;

	public void prepare(ScreenObj drawObj) {
		obj = drawObj;
		float w = obj.getWidth();
		float h = obj.getHeight();

		x = w / 2;
		y = 0;

		width = w * 2;
		height = h * 2;
	}
	
	public Label(){
		
	}

	public static final Parcelable.Creator<Label> CREATOR = new Parcelable.Creator<Label>() {
		public Label createFromParcel(Parcel in) {
			return new Label(in);
		}

		public Label[] newArray(int size) {
			return new Label[size];
		}
	};

	public Label(Parcel in){
		readParcel(in);
	}
	
	public void paint(PaintScreen dw) {
		dw.paintObj(obj, x, y, 0, 1);
	}

	public float getX() {
		return x;
	}

	public float getY() {
		return y;
	}

	public float getWidth() {
		return width;
	}

	public float getHeight() {
		return height;
	}
	
	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeFloat(x);
		dest.writeFloat(y);
		dest.writeFloat(width);
		dest.writeFloat(height);	
	}

	public void readParcel(Parcel in){
		x = in.readFloat();
		x = in.readFloat();
		width = in.readFloat();
		height = in.readFloat();
	}

	@Override
	public int describeContents() {
		return 0;
	}
} public class PaintScreen implements Parcelable{
	Canvas canvas;
	int width, height;
	Paint paint = new Paint();
	Paint bPaint = new Paint();

	public PaintScreen() {
		paint.setTextSize(16);
		paint.setAntiAlias(true);
		paint.setColor(Color.BLUE);
		paint.setStyle(Paint.Style.STROKE);
	}

	public PaintScreen(Parcel in){
		readFromParcel(in);
		paint.setTextSize(16);
		paint.setAntiAlias(true);
		paint.setColor(Color.BLUE);
		paint.setStyle(Paint.Style.STROKE);
	}

	public static final Parcelable.Creator<PaintScreen> CREATOR = new Parcelable.Creator<PaintScreen>() {
		public PaintScreen createFromParcel(Parcel in) {
			return new PaintScreen(in);
		}

		public PaintScreen[] newArray(int size) {
			return new PaintScreen[size];
		}
	};

	public Canvas getCanvas() {
		return canvas;
	}

	public void setCanvas(Canvas canvas) {
		this.canvas = canvas;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public int getWidth() {
		return width;
	}

	public int getHeight() {
		return height;
	}

	public void setFill(boolean fill) {
		if (fill)
			paint.setStyle(Paint.Style.FILL);
		else
			paint.setStyle(Paint.Style.STROKE);
	}

	public void setColor(int c) {
		paint.setColor(c);
	}

	public void setStrokeWidth(float w) {
		paint.setStrokeWidth(w);
	}

	public void paintLine(float x1, float y1, float x2, float y2) {
		canvas.drawLine(x1, y1, x2, y2, paint);
	}

	public void paintRect(float x, float y, float width, float height) {
		canvas.drawRect(x, y, x + width, y + height, paint);
	}

	public void paintRoundedRect(float x, float y, float width, float height) {
		//rounded edges. patch by Ignacio Avellino
		RectF rect = new RectF(x, y, x + width, y + height);
		canvas.drawRoundRect(rect, 15F, 15F, paint);
	}

	public void paintBitmap(Bitmap bitmap, float left, float top) {
		canvas.drawBitmap(bitmap, left, top, paint);
	}

	public void paintPath(Path path,float x, float y, float width, float height, float rotation, float scale) {
		canvas.save();
		canvas.translate(x + width / 2, y + height / 2);
		canvas.rotate(rotation);
		canvas.scale(scale, scale);
		canvas.translate(-(width / 2), -(height / 2));
		canvas.drawPath(path, paint);
		canvas.restore();
	}

	public void paintCircle(float x, float y, float radius) {
		canvas.drawCircle(x, y, radius, paint);
	}

	public void paintText(float x, float y, String text, boolean underline) {
		paint.setUnderlineText(underline);
		canvas.drawText(text, x, y, paint);
	}

	public void paintObj(ScreenObj obj, float x, float y, float rotation,
			float scale) {
		canvas.save();
		canvas.translate(x + obj.getWidth() / 2, y + obj.getHeight() / 2);
		canvas.rotate(rotation);
		canvas.scale(scale, scale);
		canvas.translate(-(obj.getWidth() / 2), -(obj.getHeight() / 2));
		obj.paint(this);
		canvas.restore();
	}

	public float getTextWidth(String txt) {
		return paint.measureText(txt);
	}

	public float getTextAsc() {
		return -paint.ascent();
	}

	public float getTextDesc() {
		return paint.descent();
	}

	public float getTextLead() {
		return 0;
	}

	public void setFontSize(float size) {
		paint.setTextSize(size);
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeInt(width);
		dest.writeInt(height);
	}


	public void readFromParcel(Parcel in) {
		height = in.readInt();
		width  = in.readInt();
		canvas = new Canvas();
	}

} public interface Marker extends Comparable<Marker>{

	String getTitle();

	String getURL();

	double getLatitude();

	double getLongitude();

	double getAltitude();

	MixVector getLocationVector();

	void update(Location curGPSFix);

	void calcPaint(Camera viewCam, float addX, float addY);

	void draw(PaintScreen dw);

	double getDistance();

	void setDistance(double distance);

	String getID();

	void setID(String iD);

	boolean isActive();

	void setActive(boolean active);

	int getColour();
	
	public void setTxtLab(Label txtLab);

	Label getTxtLab();

	public boolean fClick(float x, float y, MixContextInterface ctx, MixStateInterface state);

	int getMaxObjects();
	
	void setExtras(String name, ParcelableProperty parcelableProperty);
	
	void setExtras(String name, PrimitiveProperty primitiveProperty);

} public class ClickHandler implements Parcelable{

	private String url;
	private boolean active;
	private Label txtLab;
	private MixVector signMarker;
	private MixVector cMarker;
	private final ScreenLine pPt = new ScreenLine();
	
	public ClickHandler(String url, boolean active, Label txtLab, MixVector signMarker, MixVector cMarker){
		this.url = url;
		this.active = active;
		this.txtLab = txtLab;
		this.signMarker = signMarker;
		this.cMarker = cMarker;		
	}
	
	public ClickHandler(Parcel in){
		readFromParcel(in);
	}
	
	/**
	 * A click handler without a click valid check.
	 */
	public boolean fakeClick(MixContextInterface ctx, MixStateInterface state){
		return state.handleEvent(ctx, url);
	}
	
	public boolean handleClick(float x, float y, MixContextInterface ctx, MixStateInterface state){
		if(isClickValid(x, y)){
			return state.handleEvent(ctx, url);
		}
		return false;
	}
	
	private boolean isClickValid(float x, float y) {
	
		float currentAngle = MixUtils.getAngle(cMarker.x, cMarker.y,
				signMarker.x, signMarker.y);
		//if the marker is not active (i.e. not shown in AR view) we don't have to check it for clicks
		if (!active)
			return false;

		//TODO adapt the following to the variable radius!
		pPt.x = x - signMarker.x;
		pPt.y = y - signMarker.y;
		pPt.rotate((float) Math.toRadians(-(currentAngle + 90)));
		pPt.x += txtLab.getX();
		pPt.y += txtLab.getY();

		float objX = txtLab.getX() - txtLab.getWidth() / 2;
		float objY = txtLab.getY() - txtLab.getHeight() / 2;
		float objW = txtLab.getWidth();
		float objH = txtLab.getHeight();

		if (pPt.x > objX && pPt.x < objX + objW && pPt.y > objY
				&& pPt.y < objY + objH) {
			return true;
		} else {
			return false;
		}
	}
	
	public static final Parcelable.Creator<ClickHandler> CREATOR = new Parcelable.Creator<ClickHandler>() {
		public ClickHandler createFromParcel(Parcel in) {
			return new ClickHandler(in);
		}
		
		public ClickHandler[] newArray(int size) {
			return new ClickHandler[size];
		}
	};
	
	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeString(url);	
		dest.writeString(String.valueOf(active));	
		dest.writeParcelable(txtLab, 0);
		dest.writeParcelable(signMarker, 0);
		dest.writeParcelable(cMarker, 0);
	}
	
	public void readFromParcel(Parcel in){
		url = in.readString();
		active = Boolean.valueOf(in.readString());
		txtLab = in.readParcelable(Label.class.getClassLoader());
		signMarker = in.readParcelable(MixVector.class.getClassLoader());
		cMarker = in.readParcelable(MixVector.class.getClassLoader());
	}

} public abstract class DrawCommand implements Parcelable{

	private String command;
	
	private final Map<String, Object> properties=new LinkedHashMap<String, Object>();
	
	protected DrawCommand(String command){
		this.command=command;
	}
	
	protected void setProperty(String key,Object value){
		properties.put(key, value);
	}
	
	public Object getProperty(String key){
		return properties.get(key);
	}
	
	public abstract void draw(PaintScreen dw);
		
	Boolean getBooleanProperty(String key){
		return (Boolean)properties.get(key);
	}
	
	MixVector getMixVectorProperty(String key){
		return (MixVector)getParcelableProperty(key);
	}
	
	Bitmap getBitmapProperty(String key){
		return (Bitmap)getParcelableProperty(key);
	}
	
	String getStringProperty(String key){
		return (String)properties.get(key);
	}
	
	Float getFloatProperty(String key){
		return (Float)properties.get(key);
	}
	
	Integer getIntegerProperty(String key){
		return (Integer)properties.get(key);
	}
	
	Double getDoubleProperty(String key){
		return (Double)properties.get(key);
	}
	
	byte[] getByteArrayProperty(String key){
		return (byte[])properties.get(key);
	}
	
	Parcelable getParcelableProperty(String key){
		Parcelable o = (Parcelable)properties.get(key);
		if(o instanceof ParcelableProperty){
			return ((ParcelableProperty)o).getObject();
		}
		return o;
	}
	
	public static final Parcelable.Creator<DrawCommand> CREATOR = new Parcelable.Creator<DrawCommand>() {
		public DrawCommand createFromParcel(Parcel in) {
			return DrawCommand.buildObject(in);
		}
		
		public DrawCommand[] newArray(int size) {
			return new DrawCommand[size];
		}
	};
	
	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeString(command);
		for (String s: properties.keySet()) {
			
            if(properties.get(s) instanceof String){
            	dest.writeString(getStringProperty(s));
            } 
            else if(properties.get(s) instanceof Boolean){
            	dest.writeString(String.valueOf(getBooleanProperty(s)));
            }
			else if(properties.get(s) instanceof Float){
				dest.writeFloat(getFloatProperty(s));
			}			            	
			else if(properties.get(s) instanceof Integer){
				dest.writeInt(getIntegerProperty(s));
			}
			else if(properties.get(s) instanceof Double){
				dest.writeDouble(getDoubleProperty(s));
			}
			else if(properties.get(s) instanceof Byte[]){
				dest.writeByteArray(getByteArrayProperty(s));
			}
			else if(properties.get(s) instanceof ParcelableProperty){
				dest.writeParcelable((ParcelableProperty)properties.get(s), 0);
			}
        }
	}
	
	@SuppressWarnings("rawtypes")
	public static DrawCommand buildObject(Parcel in){
		String className = in.readString();
		String methodName = "init";
		Class[] args = new Class[1];
		args[0] = Parcel.class;
		try {
			Method m = Class.forName(className).getMethod(methodName, args);
			return (DrawCommand) m.invoke(null, in);			
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}	
	
} public class ParcelableProperty implements Parcelable {

	private String className;
	private Parcelable object;

	public ParcelableProperty(String className, Parcelable object) {
		this.className = className;
		this.object = object;
	}

	public static final Parcelable.Creator<ParcelableProperty> CREATOR = new Parcelable.Creator<ParcelableProperty>() {
		public ParcelableProperty createFromParcel(Parcel in) {
			return new ParcelableProperty(in);
		}

		public ParcelableProperty[] newArray(int size) {
			return new ParcelableProperty[size];
		}
	};

	private ParcelableProperty(Parcel in) {
		className = in.readString();
		object = in.readParcelable(getClassLoader());
	}

	public ClassLoader getClassLoader() {
		try {
			return Class.forName(className).getClassLoader();
		} catch (ClassNotFoundException e) {
			throw new RuntimeException();
		}
	}

	public Parcelable getObject() {
		return object;
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeString(className);
		dest.writeParcelable(object, 0);
	}

} public class PrimitiveProperty implements Parcelable {

	private String primitivename;
	private Object object;

	public enum primitive {
		STRING, INT, DOUBLE, FLOAT, LONG, BYTE;
	}

	public PrimitiveProperty(String primitivename, Object object) {
		this.primitivename = primitivename;
		this.object = object;
	}

	public PrimitiveProperty(Parcel in) {
		primitivename = in.readString();
		if (primitivename.equals(primitive.STRING.name())) {
			object = in.readString();
		}
		else if (primitivename.equals(primitive.INT.name())) {
			object = in.readInt();
		}
		else if (primitivename.equals(primitive.DOUBLE.name())) {
			object = in.readDouble();
		}
		else if (primitivename.equals(primitive.FLOAT.name())) {
			object = in.readFloat();
		}
		else if (primitivename.equals(primitive.LONG.name())) {
			object = in.readLong();
		}
		else if (primitivename.equals(primitive.BYTE.name())) {
			in.readByteArray((byte[])object);
		}
	}

	public static final Parcelable.Creator<PrimitiveProperty> CREATOR = new Parcelable.Creator<PrimitiveProperty>() {
		public PrimitiveProperty createFromParcel(Parcel in) {
			return new PrimitiveProperty(in);
		}

		public PrimitiveProperty[] newArray(int size) {
			return new PrimitiveProperty[size];
		}
	};

	public Object getObject() {
		return object;
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeString(primitivename);
		if (primitivename.equals(primitive.STRING.name())) {
			dest.writeString((String)object);
		}
		else if (primitivename.equals(primitive.INT.name())) {
			dest.writeInt((Integer)object);
		}
		else if (primitivename.equals(primitive.DOUBLE.name())) {
			dest.writeDouble((Double)object);
		}
		else if (primitivename.equals(primitive.FLOAT.name())) {
			dest.writeFloat((Float)object);
		}
		else if (primitivename.equals(primitive.LONG.name())) {
			dest.writeLong((Long)object);
		}
		else if (primitivename.equals(primitive.BYTE.name())) {
			dest.writeByteArray((byte[])object);
		}
	}

} public class Camera implements Parcelable {

	public static final float DEFAULT_VIEW_ANGLE = (float) Math.toRadians(45);

	public int width, height;

	public Matrix transform = new Matrix();
	public MixVector lco = new MixVector();

	float viewAngle;
	float dist;

	public Camera(int width, int height) {
		this(width, height, true);
	}

	public Camera(int width, int height, boolean init) {
		this.width = width;
		this.height = height;

		transform.toIdentity();
		lco.set(0, 0, 0);
	}

	public Camera(Parcel in) {
		readFromParcel(in);
	}

	public static final Parcelable.Creator<Camera> CREATOR = new Parcelable.Creator<Camera>() {
		public Camera createFromParcel(Parcel in) {
			return new Camera(in);
		}

		public Camera[] newArray(int size) {
			return new Camera[size];
		}
	};

	public void setViewAngle(float viewAngle) {
		this.viewAngle = viewAngle;
		this.dist = (this.width / 2) / (float) Math.tan(viewAngle / 2);
	}

	public void setViewAngle(int width, int height, float viewAngle) {
		this.viewAngle = viewAngle;
		this.dist = (width / 2) / (float) Math.tan(viewAngle / 2);
	}

	public void projectPoint(MixVector orgPoint, MixVector prjPoint,
			float addX, float addY) {
		prjPoint.x = dist * orgPoint.x / -orgPoint.z;
		prjPoint.y = dist * orgPoint.y / -orgPoint.z;
		prjPoint.z = orgPoint.z;
		prjPoint.x = prjPoint.x + addX + width / 2;
		prjPoint.y = -prjPoint.y + addY + height / 2;
	}

	@Override
	public String toString() {
		return "CAM(" + width + "," + height + ")";
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int arg1) {
		dest.writeInt(width);
		dest.writeInt(height);
		dest.writeParcelable(transform, 0);
		dest.writeParcelable(lco, 0);
		dest.writeFloat(viewAngle);
		dest.writeFloat(dist);
	}

	public void readFromParcel(Parcel in) {
		width = in.readInt();
		height = in.readInt();
		transform = in.readParcelable(Matrix.class.getClassLoader());
		lco = in.readParcelable(MixVector.class.getClassLoader());
		viewAngle = in.readFloat();
		dist = in.readFloat();
	}
} public class MixVector implements Parcelable{
	public float x;
	public float y;
	public float z;

	public MixVector() {
		this(0, 0, 0);
	}

	public MixVector(MixVector v) {
		this(v.x, v.y, v.z);
	}

	public MixVector(float v[]) {
		this(v[0], v[1], v[2]);
	}

	public MixVector(float x, float y, float z) {
		set(x, y, z);
	}

	public MixVector(Parcel in){
		readParcel(in);
	}

	public static final Parcelable.Creator<MixVector> CREATOR = new Parcelable.Creator<MixVector>() {
		public MixVector createFromParcel(Parcel in) {
			return new MixVector(in);
		}

		public MixVector[] newArray(int size) {
			return new MixVector[size];
		}
	};

	@Override
	public boolean equals(Object obj) {
		MixVector v = (MixVector) obj;
		return (v.x == x && v.y == y && v.z == z);
	}

	public boolean equals(float x, float y, float z) {
		return (this.x == x && this.y == y && this.z == z);
	}
	
	@Override
	public int hashCode() {
		Float xf = x;
		Float yf = y;
		Float zf = z;
		return xf.hashCode()+yf.hashCode()+zf.hashCode();
	}

	@Override
	public String toString() {
		return "<" + x + ", " + y + ", " + z + ">";
	}

	public void set(MixVector v) {
		set(v.x, v.y, v.z);
	}

	public void set(float x, float y, float z) {
		this.x = x;
		this.y = y;
		this.z = z;
	}

	public void add(float x, float y, float z) {
		this.x += x;
		this.y += y;
		this.z += z;
	}

	public void add(MixVector v) {
		add(v.x, v.y, v.z);
	}

	public void sub(float x, float y, float z) {
		add(-x, -y, -z);
	}

	public void sub(MixVector v) {
		add(-v.x, -v.y, -v.z);
	}

	public void mult(float s) {
		x *= s;
		y *= s;
		z *= s;
	}

	public void divide(float s) {
		x /= s;
		y /= s;
		z /= s;
	}

	public float length() {
		return (float) FloatMath.sqrt(x * x + y * y + z * z);
	}

	public float length2D() {
		return (float) FloatMath.sqrt(x * x + z * z);
	}

	public void norm() {
		divide(length());
	}

	public float dot(MixVector v) {
		return x * v.x + y * v.y + z * v.z;
	}

	public void cross(MixVector u, MixVector v) {
		float x = u.y * v.z - u.z * v.y;
		float y = u.z * v.x - u.x * v.z;
		float z = u.x * v.y - u.y * v.x;
		this.x = x;
		this.y = y;
		this.z = z;
	}

	public void prod(Matrix m) {
		float xTemp = m.a1 * x + m.a2 * y + m.a3 * z;
		float yTemp = m.b1 * x + m.b2 * y + m.b3 * z;
		float zTemp = m.c1 * x + m.c2 * y + m.c3 * z;

		x = xTemp;
		y = yTemp;
		z = zTemp;
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeFloat(x);
		dest.writeFloat(y);
		dest.writeFloat(z);
	}

	public void readParcel(Parcel in) {
		x = in.readFloat();
		y = in.readFloat();
		z = in.readFloat();
	}
} public class PluginNotFoundException extends RuntimeException{
	
	private static final long serialVersionUID = 1L;

	public PluginNotFoundException() {
		super();
	}
	
	public PluginNotFoundException(Throwable throwable){
		super(throwable);
	}

	public PluginNotFoundException(String message) {
		super(message);
	}

}
import be.artoria.belfortapp.mixare.plugin.PluginNotFoundException;
import android.location.Location;
import android.os.RemoteException;
import be.artoria.belfortapp.mixare.lib.MixContextInterface;
import be.artoria.belfortapp.mixare.lib.MixStateInterface;
import be.artoria.belfortapp.mixare.lib.gui.Label;
import be.artoria.belfortapp.mixare.lib.gui.PaintScreen;
import be.artoria.belfortapp.mixare.lib.marker.Marker;
import be.artoria.belfortapp.mixare.lib.marker.draw.ClickHandler;
import be.artoria.belfortapp.mixare.lib.marker.draw.DrawCommand;
import be.artoria.belfortapp.mixare.lib.marker.draw.ParcelableProperty;
import be.artoria.belfortapp.mixare.lib.marker.draw.PrimitiveProperty;
import be.artoria.belfortapp.mixare.lib.render.Camera;
import be.artoria.belfortapp.mixare.lib.render.MixVector;
import be.artoria.belfortapp.mixare.lib.service.IMarkerService;
/*
 * Copyright (C) 2012- Peer internet solutions & Finalist IT Group
 * 
 * This file is part of be.artoria.belfortapp.mixare.
 * 
 * This program is free software: you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 * for more details. 
 * 
 * You should have received a copy of the GNU General Public License along with 
 * this program. If not, see <http://www.gnu.org/licenses/>
 */
package be.artoria.belfortapp.mixare.plugin.remoteobjects;



/**
 * The remote marker sends request to the (remote)plugin that it is connected to through IMarkerService.
 * the remote marker is treated like a normal marker in the core. And it overrides the marker interface.
 * @author A. Egal
 */
public class RemoteMarker implements Marker{

	private String markerName;
	private IMarkerService iMarkerService;
	
	public RemoteMarker(IMarkerService iMarkerService){
		this.iMarkerService = iMarkerService;
	}

	public int getPid() {
		return 0;
	}

	public void buildMarker(int id, String title, double latitude, double longitude, double altitude, String url, int type, int color){
		try {
			this.markerName = iMarkerService.buildMarker(id, title, latitude, longitude, altitude, url, type, color);
		} catch (RemoteException e) {
			throw new PluginNotFoundException(e);
		}
	}

	public String getPluginName(){
		try {
			return iMarkerService.getPluginName();
		} catch (RemoteException e) {
			throw new PluginNotFoundException(e);
		}
	}

	@Override
	public void calcPaint(Camera viewCam, float addX, float addY){	