<html>
<xmp>
/**
 * Title: iSIM
 * Copyright: Copyright (c) 2002
 * Company:   University of Oregon Computer Science Dept.
 *
 * @author Jason Prideaux
 * @version 1.0
 *
 */

package agent.autonomous;

import agent.*;
import controller.*;
import gui.*;
import transport.*;
import transport.protocol.*;

import java.awt.*;
import java.awt.event.*;
import java.util.Date;
import java.io.*;


/* ====================================================================== */
/** This class represents a mobile autonomous robot.  It has knowledge and
 *  state.  The states determine the current goal of the robot.  This robot
 *  simply searches the world for a person in distress.  Once found, the
 *  robot will notify a Rescuer to save person.  Once the Rescuer has saved
 *  the person, this robot will then continue to look for more people.
 *
 *  When the robot senses data/communication it will respond by making some
 *  sort of actuation.  So if the sensors were to fail.  This robot would
 *  be dead in the water.
 *
 */
public class Searcher extends Autonomous implements SocketReceiverListener{

	/** The simulation controller, only used to determine our simulation
	    environment boundaries. */
	private Controller controller;

  // Knowledge
 	/** The location of the rescuer robot. */
	private Point rescuer;

	/** The location of person that needs to be rescued that we found. */
	private Point distress;

  // States
	/** If true then remain idle. */
	private boolean idle;

	/** If true then search the world. */
	private boolean searching;

	/** If true then go to rescuer to get help. */
	private boolean requesting;


	/* ====================================================================== */
	/** This constructor sets up the information needed for the robot.
	 *  Naturally the robot must know its own abilities.  The simulation
	 *  controller is needed so that it can be given to the mediator class,
	 *  Autonomous.java, which serves as an inbetween for a robot and the
	 *  simulator.
	 *
	 *  @param  c   The iSIM controller.
	 *  @param  loc  The location of the agent.
	 *  @param  port  The communication port need to speak with iSIM.
	 *  @param  range   The wireless max range.
	 *
	 */
	public Searcher(Controller c, Point loc, int port, int range){

		// Super our agent/user information.
		super(c, loc, port, range, "searcher");

		// Simulation controller
		controller = c;

		// our initial state.
		idle = true;
		searching = false;
		requesting = false;

	} //Constructor




	// Use this method to receive new location data.
	public void senseLocation(Point location, double heading){

		if( !idle ){

			Point newLocation = location;
			double newHeading = heading;

			if( searching ){

				// Right now we search randomly
				double coin = Math.random();
				if( coin < 0.3333 ){
					newHeading += 45;
				}else if( coin < 0.6667 ){
					newHeading -= 45;
				}
				if( newHeading < 0 ){
					newHeading = 315;
				}else if( newHeading > 315 ){
					newHeading = 0;
				}

				int x = (int)(location.getX()+(Math.cos(Math.toRadians(newHeading))*15));
				int y = (int)(location.getY()+(Math.sin(Math.toRadians(newHeading))*-15));

				if( x < 15 ){
					newHeading = 0;
				}else if( y < 15 ){
					newHeading = 270;
				}else if( x > (controller.getChartComp().getSize().getWidth()-15) ){
					newHeading = 180;
				}else if( y > (controller.getChartComp().getSize().getHeight()-15) ){
					newHeading = 90;
				}else{
					newLocation = new Point(x,y);
				}

				actuateLocation( newLocation, newHeading);


			}else if( requesting ){

				// Determine angle to rescuer to get help from
				double hyp = Controller.diff(rescuer, location);
				double opp = Math.abs(location.getY() - rescuer.getY());

				double angle = Math.toDegrees(Math.asin(opp/hyp));
				double fixed = 0;

				if( location.getX() <= rescuer.getX() && location.getY() <= rescuer.getY() ){
					fixed = 360 - angle;

				}else if( location.getX() > rescuer.getX() && location.getY() <= rescuer.getY() ){
					fixed = 180 + angle;

				}else if( location.getX() <= rescuer.getX() && location.getY() > rescuer.getY()){
					fixed = angle;

				}else if( location.getX() > rescuer.getX() && location.getY() > rescuer.getY()){
					fixed = 180 - angle;
				}

				double adjust = fixed%45;

				if( adjust < 22.5 ){
					newHeading = ((int)(fixed/45))*45;
				}else{
					newHeading = ((int)(fixed/45)+1)*45;
				}



				if( newHeading < 0 ){
					newHeading = 315;
				}else if( newHeading > 315 ){
					newHeading = 0;
				}


				int x = (int)(location.getX()+(Math.cos(Math.toRadians(newHeading))*15));
				int y = (int)(location.getY()+(Math.sin(Math.toRadians(newHeading))*-15));

				if( x < 15 ){
					newHeading = 0;
				}else if( y < 15 ){
					newHeading = 270;
				}else if( x > (controller.getChartComp().getSize().getWidth()-15) ){
					newHeading = 180;
				}else if( y > (controller.getChartComp().getSize().getHeight()-15) ){
					newHeading = 90;
				}else{
					newLocation = new Point(x,y);
				}

				actuateLocation( newLocation, newHeading);

			}
		}

	}



	// Use this method to receive communication from other robots
	// and people agents.
	public void senseMessage(HelpMessage msg){

		// If idle then we only listen to rescuer to tell us to search again.
		if( idle ){

			if( ((HelpMessage)msg).getMessage().equalsIgnoreCase("rescuer") ){

				rescuer = ((HelpMessage)msg).getLocation();
				idle = false;
				searching = true;
				actuateMessage(new HelpMessage("searching", getPort(), 1, null ));
				actuateLocation( this.getLocation(), this.getPosition().getHeading());
			}

		// If searching then we only listen to a person in distress
		}else if( searching ){

			if( ((HelpMessage)msg).getMessage().equalsIgnoreCase("help") ){

				distress = ((HelpMessage)msg).getLocation();
				searching = false;
				requesting = true;

			}

		// If going to request help, then we only listen for a rescuer.
		}else if( requesting ){

			if( ((HelpMessage)msg).getMessage().equalsIgnoreCase("rescuer") ){

				actuateMessage(new HelpMessage("request", getPort(), 1, distress ));

			}else if( ((HelpMessage)msg).getMessage().equalsIgnoreCase("idle") ){

				idle = true;
				requesting = false;
			}

		}
	}



} //class: Searcher
</xmp>
</html>
