/*
  Part of the G4P library for Processing 
  	http://www.lagers.org.uk/g4p/index.html
	http://sourceforge.net/projects/g4p/files/?source=navbar

  Copyright (c) 2012 Peter Lager

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
 */

package g4p_controls;

import processing.core.PApplet;
import processing.core.PImage;

/**
 * Base class for different types of hot spot.
 * 
 * @author Peter Lager
 *
 */
abstract class HotSpot implements GConstants, Comparable<HotSpot> {

	public final Integer id;
	public float x, y;

	abstract public boolean contains(float px, float py);

	protected HotSpot(int id){
		this.id = Math.abs(id);
	}

	public void adjust(Object ... arguments){}

	public int compareTo(HotSpot spoto) {
		return id.compareTo(spoto.id);
	}

	/**
	 * Hit is based on being inside a rectangle.
	 * 
	 * @author Peter Lager
	 */
	static class HSrect extends HotSpot {
		public float w, h;

		public HSrect(int id, float x, float y, float w, float h) {
			super(id);
			this.x = x;
			this.y = y;
			this.w = w;
			this.h = h;
		}

		@Override
		public boolean contains(float px, float py) {
			return (px >= x && py >= y && px <= x + w && py <= y + h);
		}
	}

	/**
	 * Hit based on an arc (pie slice)
	 * 
	 * @author Peter Lager
	 *
	 */
	static class HSarc extends HotSpot {

		public float sa, ea, r, r2;

		public HSarc(int id, float x, float y, float r, float sa, float ea) {
			super(id);
			this.x = x;
			this.y = y;
			this.r = r;
			this.r2 = r * r;
			this.sa = sa;
			this.ea = ea;
		}


		@Override
		public boolean contains(float px, float py) {
			if((px-x)*(px-x) + (py-y)*(py-y) > r2)
				return false;
			// Now check angle
			float a = (float) Math.toDegrees(Math.atan2(py-y, px-x));
			if(a < 0) a += 360;
			if(a < sa) a += 360;
			return (a >= sa && a <= ea);
		}
	}

	/**
	 * Hit is based on being inside a rectangle.
	 * 
	 * @author Peter Lager
	 */
	static class HScircle extends HotSpot {
		public float r, r2;

		public HScircle(int id, float x, float y, float r) {
			super(id);
			this.x = x;
			this.y = y;
			this.r = r;
			this.r2 = r * r;
		}

		@Override
		public boolean contains(float px, float py) {
			return ((px-x)*(px-x) + (py-y)*(py-y) <= r2);
		}

		/**
		 * If used the parameters must be in the order x, y then r. <br>
		 * 
		 */
		@SuppressWarnings(value={"fallthrough"})
		public void adjust(Object ... arguments){
			switch(arguments.length){
			case 3:
				r = Float.valueOf(arguments[2].toString());
				r2 = r * r;
			case 2:
				y = Float.valueOf(arguments[1].toString());
			case 1:
				x = Float.valueOf(arguments[0].toString());
			}
		}


		public String toString(){
			return "HS circle ["+x+", "+y+"]  radius = "+r;
		}
	}

	/**
	 * Hit depends on the mask image. non-transparent areas are black and
	 * transparent areas are white. <br>
	 * 
	 * It is better this way because scaling the image can change the 
	 * colour white to very nearly white but black is unchanged so is 
	 * easier to test.
	 * 
	 * @author Peter Lager
	 *
	 */
	static class HSmask extends HotSpot {

		private PImage mask = null;

		protected HSmask(int id, PImage mask) {
			super(id);
			this.mask = mask;
		}

		@Override
		public boolean contains(float px, float py) {
			if(mask != null){
				int pixel = mask.get((int)px, (int)py);
				float alpha = (pixel >> 24) & 0xff;
				// A > 0 and RGB = 0 is transparent
				if(alpha > 0 && (pixel & 0x00ffffff) == 0){
					return true;
				}
			}
			return false;
		}

		public String toString(){
			return "HS mask ["+x+", "+y+"]";
		}

	}

	/**
	 * Hit is determined by the alpha channel value.
	 * @author Peter
	 *
	 */
	static class HSalpha extends HotSpot {

		private PImage image = null;

		private int offX, offY;

		protected HSalpha(int id, float x, float y, PImage image, int imageMode) {
			super(id);
			this.image = image;
			this.x = x;
			this.y = y;
			if(imageMode == PApplet.CENTER){
				offX = -image.width/2;
				offY = -image.height/2;
			}
			else
				offX = offY = 0;
		}

		/**
		 * If used the parameters must be in the order x, y then image. <br>
		 */
		@SuppressWarnings(value={"fallthrough"})
		public void adjust(Object ... arguments){
			switch(arguments.length){
			case 3:
				image = (PImage) arguments[2];
			case 2:
				y = Float.valueOf(arguments[1].toString());
			case 1:
				x = Float.valueOf(arguments[0].toString());
			}
		}

		@Override
		public boolean contains(float px, float py) {
			if(image != null){
				int imgX = Math.round(px - x) - offX;
				int imgY = Math.round(py - y) - offY;
				float alpha = (image.get(imgX, imgY) >> 24) & 0xff;
				if(alpha >  ALPHA_PICK)
					return true;
			}
			return false;
		}

		public String toString(){
			return "HS alpha ["+x+", "+y+"]";
		}

	}
}
