/*
 * Created on 26-Jul-2006
 *
 */
package ix.robot;


//import java.io.IOException;
import ix.icore.domain.Constraint;
import ix.icore.domain.PatternAssignment;
import ix.util.lisp.LList;
import ix.util.lisp.Lisp;

import java.awt.Image;
import java.awt.image.BufferedImage;

import liburbi.call.URBIEvent;
import liburbi.call.UCallbackListener;
import liburbi.image.ImageSampler;
import liburbi.image.ImageUtilities;
import liburbi.image.ImageFilter;
import liburbi.UClient;
//import liburbi.image.MedianFilter;

public class ColourZone implements UCallbackListener{
	
	public ImageSampler imageSampler;
	
	//Set The RGB Indexes
	private static int RED = 0;
	private static int GREEN = 1;
	private static int BLUE = 2;

	//Set the zones
	public static int ZoneA = 1;
	public static int ZoneB = 2;
	public static int ZoneC = 3;
	public static int ZoneD = 4;
	public static int ZoneE = 5;
	
	public  int zonesearch;
	public boolean zoneFound=false;
	public int dirx;
	public int diry;
	
	public UClient URBI;
	public String RobotName;
	
	public ColourZone(UClient URBI, int Zone, String RobotName)
	{
		this.URBI = URBI;
		zonesearch = Zone;
		this.RobotName = RobotName;
	}
	
	public void actionPerformed(URBIEvent event)
	{
		
		if (event.getBinBuffer() == null)
			return;
		
		//ZONE COLOUR PREPARATION
		double blue[]= new double[3];
		double red[] = new double[3];
		double green[] = new double[3];
		double yellow[] = new double[3];
		double darkkhaki[] = new double[3];
		

		//Setting zone colour references
		blue[RED]=0;blue[GREEN]=0;blue[BLUE]=255;
		red[RED]=255;red[GREEN]=0;red[BLUE]=0;
		green[RED]=0;green[GREEN]=255;green[BLUE]=0;
		yellow[RED]=255;yellow[GREEN]=255;yellow[BLUE]=0;
		darkkhaki[RED]=189;darkkhaki[GREEN]=183;darkkhaki[BLUE]=107;
		
		//This section under review ****
		double E_red = 0;
		double E_blue = 0;
		double E_green =0;
		double E_yellow =0;
		double E_darkkhaki =0;
		//*******************************
		//Accept the red colour Initialisation
		int red_accepted = 0;
		int sum_redx = 0;
		int sum_redy = 0;
		int red_red_max = 255;
		int red_red_min = 230;
		int red_green_max = 20;
		int red_green_min = 0;
		int red_blue_max = 20;
		int red_blue_min = 0;
		int red_colourx = 0;
		int red_coloury =0;
		int red_THRESHOLD = 100;
		boolean red_Zone = false;
		
		//Accept the blue colour Initialisation
		int blue_accepted = 0;
		int sum_bluex = 0;
		int sum_bluey = 0;
		int blue_red_max = 20;
		int blue_red_min = 0;
		int blue_green_max = 20;
		int blue_green_min = 0;
		int blue_blue_max = 255;
		int blue_blue_min = 230;
		int blue_colourx = 0;
		int blue_coloury =0;
		int blue_THRESHOLD = 100;
		boolean blue_Zone = false;
		
		//Accept the green colour Initialisation
		int green_accepted = 0;
		int sum_greenx = 0;
		int sum_greeny = 0;
		int green_red_max = 20;
		int green_red_min = 0;
		int green_green_max = 255;
		int green_green_min = 230;
		int green_blue_max = 20;
		int green_blue_min = 0;
		int green_colourx = 0;
		int green_coloury = 0;
		int green_THRESHOLD = 100;
		boolean green_Zone = false;
		
		//Accept the yellow colour Initialisation
		int yellow_accepted = 0;
		int sum_yellowx = 0;
		int sum_yellowy = 0;
		int yellow_red_max = 255;
		int yellow_red_min = 230;
		int yellow_green_max = 255;
		int yellow_green_min = 230;
		int yellow_blue_max = 20;
		int yellow_blue_min = 0;
		int yellow_colourx = 0;
		int yellow_coloury = 0;
		int yellow_THRESHOLD = 100;
		boolean yellow_Zone = false;
		
		//Accept the darkkhaki colour Initialisation
		int darkkhaki_accepted = 0;
		int sum_darkkhakix = 0;
		int sum_darkkhakiy = 0;
		int darkkhaki_red_max = 191;
		int darkkhaki_red_min = 170;
		int darkkhaki_green_max = 185;
		int darkkhaki_green_min = 170;
		int darkkhaki_blue_max = 115;
		int darkkhaki_blue_min = 100;
		int darkkhaki_colourx = 0;
		int darkkhaki_coloury = 0;
		int darkkhaki_THRESHOLD = 100;
		boolean darkkhaki_Zone = false;
		
		//Image in array pixels
		int pixels[];
		
		int	width = event.getWidth();
		int	height = event.getHeight();
		
		ImageUtilities.setWidth(width);
		ImageUtilities.setHeight(height);
		
		Image im = ImageUtilities.blockingLoad(event.getBinBuffer());
		BufferedImage	buffer = ImageUtilities.makeBufferedImage(im);
		pixels = buffer.getRGB(0, 0, width, height, null, 0, width);

		
		for (int i = 0; i < pixels.length; i++)
			{ 
				//Get the RGB value for each pixel
				double get_red = ImageFilter.getRed(pixels[i]);
				double get_green = ImageFilter.getGreen(pixels[i]);
				double get_blue = ImageFilter.getBlue(pixels[i]);
			
				
				//E_red = Math.sqrt(Math.pow(get_red-red[RED],2)+Math.pow(get_green-red[GREEN],2)
				//					+ Math.pow(get_blue-red[BLUE],2));
				
				//Detection for Red Colour
				if ((get_red >= red_red_min) && (get_red <= red_red_max)
					&& (get_green >= red_green_min) && (get_green <= red_green_max)
					&& (get_blue >= red_blue_min) && (get_blue <= red_blue_max))
				{
					red_accepted++;
					sum_redy += i / width;
					sum_redx += i % width;
				}
				
				//Detection for Blue Colour Colour
				if ((get_red >= blue_red_min) && (get_red <= blue_red_max)
					&& (get_green >= blue_green_min) && (get_green <= blue_green_max)
					&& (get_blue >= blue_blue_min) && (get_blue <= blue_blue_max))
				{
					blue_accepted++;
					sum_bluey += i / width;
					sum_bluex += i % width;
				}
				
				//Detection for Green Colour
				if ((get_red >= green_red_min) && (get_red <= green_red_max)
					&& (get_blue >= green_blue_min) && (get_blue <= green_blue_max)
					&& (get_green >= green_green_min) && (get_green <= green_green_max))
				{
					green_accepted++;
					sum_greeny += i / width;
					sum_greenx += i % width;
				}
				
				//Detection for Yellow Colour
				if ((get_red >= yellow_red_min) && (get_red <= yellow_red_max)
					&& (get_blue >= yellow_blue_min) && (get_blue <= yellow_blue_max)
					&& (get_green >= yellow_green_min) && (get_green <= yellow_green_max))
				{
					yellow_accepted++;
					sum_yellowy += i / width;
					sum_yellowx += i % width;
				}
				
				//Detection for darkkhaki Colour
				if ((get_red >= darkkhaki_red_min) && (get_red <= darkkhaki_red_max)
					&& (get_blue >= darkkhaki_blue_min) && (get_blue <= darkkhaki_blue_max)
					&& (get_green >= darkkhaki_green_min) && (get_green <= darkkhaki_green_max))
				{
					darkkhaki_accepted++;
					sum_darkkhakiy += i / width;
					sum_darkkhakix += i % width;
				}
				
				
			}
		
		pixels = null;
		
		
		//Setting the Zones that are currently in view
		if(green_accepted > green_THRESHOLD)
			green_Zone = true;
		else
			green_Zone = false;
		
		if(red_accepted > red_THRESHOLD)
			red_Zone = true;
		else
			red_Zone = false;
		
		if(yellow_accepted > yellow_THRESHOLD)
			yellow_Zone = true;
		else
			yellow_Zone = false;
		
		if(blue_accepted > blue_THRESHOLD)
			blue_Zone = true;
		else
			blue_Zone = false;
		
		if(darkkhaki_accepted > darkkhaki_THRESHOLD)
			darkkhaki_Zone = true;
		else
			darkkhaki_Zone = false;
		
		
		
		//Switch statement for zone search
		switch(zonesearch){
			case 1: 
				if(green_accepted >= green_THRESHOLD){
					//Setting up the recognition for the zones
					dirx = sum_greenx / green_accepted;
					diry = sum_greeny / green_accepted;
					
					zoneFound = true;

					//Notify the IP2 Panel
					Object value = new Long(calculateDistance(green_accepted));
					String patternString = "Distance(" + this.RobotName + " ZoneA)";
					LList pattern = Lisp.elementsFromString(patternString);
					PatternAssignment pa = new PatternAssignment(pattern, value );
					Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
				    RoboInfo.getIp2().handleNewConstraint(c);
					if(dirx < 140 ){
						try{
							this.URBI.effectiveSend("stop turn | stop searchprocess | unfreeze robot_searchZone,");
						} catch(Exception e){e.printStackTrace();}
					}
				} 
				else
				{
					zoneFound = false;
				}
				break;
				
			case 2:
				if(red_accepted >= red_THRESHOLD){
					//Setting up the recognition for the zones
					dirx = sum_redx / red_accepted;
					diry = sum_redy / red_accepted;
					
					
					zoneFound = true;
				
					//Notify the IP2 Panel
					Object value = new Long(calculateDistance(red_accepted));
					String patternString = "Distance(" + this.RobotName + " ZoneB)";
					LList pattern = Lisp.elementsFromString(patternString);
					PatternAssignment pa = new PatternAssignment(pattern, value );
					Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
				    RoboInfo.getIp2().handleNewConstraint(c);
					
					red_Zone = zoneFound;
					if(dirx < 140 ){
						try{
							this.URBI.effectiveSend("stop turn | stop searchprocess | unfreeze robot_searchZone,");
						} catch(Exception e){e.printStackTrace();}
					}
				} 
				else
				{
					zoneFound = false;
					
				}
				break;
			case 3:
				if(yellow_accepted >= yellow_THRESHOLD){
					//Setting up the recognition for the zones
					dirx = sum_yellowx / yellow_accepted;
					diry= sum_yellowy / yellow_accepted;
					
					zoneFound = true;

					//Notify the IP2 Panel
					Object value = new Long(calculateDistance(yellow_accepted));
					String patternString = "Distance(" + this.RobotName + " ZoneC)";
					LList pattern = Lisp.elementsFromString(patternString);
					PatternAssignment pa = new PatternAssignment(pattern, value );
					Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
				    RoboInfo.getIp2().handleNewConstraint(c);
					
					if(dirx < 140 ){
						try{
							this.URBI.effectiveSend("stop turn | stop searchprocess | unfreeze robot_searchZone,");
						} catch(Exception e){e.printStackTrace();}
					}
					
				}
				else
				{
					zoneFound = false;
				}
				
				break;
			case 4:

				if(blue_accepted >= blue_THRESHOLD){
					//Setting up the recognition for the zones
					dirx = sum_bluex / blue_accepted;
					diry = sum_bluey / blue_accepted;
					
					zoneFound = true;

					//Notify the IP2 Panel
					Object value = new Long(calculateDistance(blue_accepted));
					String patternString = "Distance(" + this.RobotName + " ZoneD)";
					LList pattern = Lisp.elementsFromString(patternString);
					PatternAssignment pa = new PatternAssignment(pattern, value );
					Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
				    RoboInfo.getIp2().handleNewConstraint(c);
					if(dirx < 140 ){
						try{
							this.URBI.effectiveSend("stop turn | stop searchprocess | unfreeze robot_searchZone,");
						} catch(Exception e){e.printStackTrace();}
					}
				} 
				else
				{
					zoneFound = false;
				}
				
				break;
			case 5:
				if(darkkhaki_accepted >= darkkhaki_THRESHOLD){
					//Setting up the recognition for the zones
					dirx = sum_darkkhakix / darkkhaki_accepted;
					diry = sum_darkkhakiy / darkkhaki_accepted;
				
					zoneFound = true;
					//System.out.println(dirx + " " + diry + " " + darkkhaki_accepted);

					//Notify the IP2 Panel
					Object value = new Long(calculateDistance(darkkhaki_accepted));
					String patternString = "Distance(" + this.RobotName + " ZoneE)";
					LList pattern = Lisp.elementsFromString(patternString);
					PatternAssignment pa = new PatternAssignment(pattern, value );
					Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
				    RoboInfo.getIp2().handleNewConstraint(c);
					
					if(dirx < 140 ){
					try{
						//Send to Robot to quit
						this.URBI.effectiveSend("stop turn | stop searchprocess | unfreeze robot_searchZone,");
						
					} catch(Exception e){e.printStackTrace();}
					}
					
				}
					
				else
					{
						zoneFound = false;
					}
				break;
		}
	

	//Notify the IP2 Panel what zones are currently insight	
	if(red_Zone)
	{
		String patternString = "Insight(" + this.RobotName + " ZoneB)";
		LList pattern = Lisp.elementsFromString(patternString);
		PatternAssignment pa = new PatternAssignment(pattern, PatternAssignment.S_TRUE);
		
	    
	    Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
	    
	    RoboInfo.getIp2().handleNewConstraint(c);
	} else
	{

		String patternString = "Insight(" + this.RobotName + " ZoneB)";
		LList pattern = Lisp.elementsFromString(patternString);
		PatternAssignment pa = new PatternAssignment(pattern, PatternAssignment.S_FALSE);
		
	    
	    Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
	    
	    RoboInfo.getIp2().handleNewConstraint(c);
	}
	
	if(green_Zone)
	{
		String patternString = "Insight(" + this.RobotName + " ZoneA)";
		LList pattern = Lisp.elementsFromString(patternString);
		PatternAssignment pa = new PatternAssignment(pattern, PatternAssignment.S_TRUE);
		
	    
	    Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
	    
	    RoboInfo.getIp2().handleNewConstraint(c);
	} else
	{

		String patternString = "Insight(" + this.RobotName + " ZoneA)";
		LList pattern = Lisp.elementsFromString(patternString);
		PatternAssignment pa = new PatternAssignment(pattern, PatternAssignment.S_FALSE);
		
	    
	    Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
	    
	    RoboInfo.getIp2().handleNewConstraint(c);
	}
	
	if(yellow_Zone)
	{
		String patternString = "Insight(" + this.RobotName + " ZoneC)";
		LList pattern = Lisp.elementsFromString(patternString);
		PatternAssignment pa = new PatternAssignment(pattern, PatternAssignment.S_TRUE);
		
	    
	    Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
	    
	    RoboInfo.getIp2().handleNewConstraint(c);
	} else
	{

		String patternString = "Insight(" + this.RobotName + " ZoneC)";
		LList pattern = Lisp.elementsFromString(patternString);
		PatternAssignment pa = new PatternAssignment(pattern, PatternAssignment.S_FALSE);
		
	    
	    Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
	    
	    RoboInfo.getIp2().handleNewConstraint(c);
	}
	
	if(blue_Zone)
	{
		String patternString = "Insight(" + this.RobotName + " ZoneD)";
		LList pattern = Lisp.elementsFromString(patternString);
		PatternAssignment pa = new PatternAssignment(pattern, PatternAssignment.S_TRUE);
		
	    
	    Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
	    
	    RoboInfo.getIp2().handleNewConstraint(c);
	} else
	{

		String patternString = "Insight(" + this.RobotName + " ZoneD)";
		LList pattern = Lisp.elementsFromString(patternString);
		PatternAssignment pa = new PatternAssignment(pattern, PatternAssignment.S_FALSE);
		
	    
	    Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
	    
	    RoboInfo.getIp2().handleNewConstraint(c);
	}
	
	if(darkkhaki_Zone)
	{
		String patternString = "Insight(" + this.RobotName + " ZoneE)";
		LList pattern = Lisp.elementsFromString(patternString);
		PatternAssignment pa = new PatternAssignment(pattern, PatternAssignment.S_TRUE);
		
	    
	    Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
	    
	    RoboInfo.getIp2().handleNewConstraint(c);
	} else
	{

		String patternString = "Insight(" + this.RobotName + " ZoneE)";
		LList pattern = Lisp.elementsFromString(patternString);
		PatternAssignment pa = new PatternAssignment(pattern, PatternAssignment.S_FALSE);
		
	    
	    Constraint c = new Constraint("world-state","effect",Lisp.list(pa));
	    
	    RoboInfo.getIp2().handleNewConstraint(c);
	}
		
		return;
	}
	

	//Calculate the distance based on the amount of the colour (being searched for) in view
	public long calculateDistance(int blobamt)
	{
		long result = 0;
		double percentage = 100.0*(blobamt/33280.0);
		
		double declineAmt = 0.50;
		double initialSteps = 50.0;
		
		double temp = 0.0;
		
		temp = initialSteps-(percentage*declineAmt);
		
		result = (long)(Math.ceil(temp));
		
		return result;
		
		
	}
}
