import jade.core.Agent;
import jade.core.AID;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import java.io.*;
import javax.swing.*;

public class ManualRobotAgent extends RobotAgent {
	
	//indicates, if the ManualRobotAgent is alive or not;
	//whenever a ManualRobotAgent exploded due to a mine contact,
	//this variable is set to 'false'; note, that the robot
	//still remains in the jade environment
	private boolean alive;
	
	//indicates if the RobotAgent is suspended or not
	private boolean suspended;
	
	
	//indicates the direction, the RobotAgent is currently
	//looking at
	private int direction;
	
	
	//variable keeping the result of a touch sensor action in mind
	private String sensorData;
	
	
	//saves the images of the optic and infra-red sensor
	private ImageIcon optic, infraRed;
	
	
	//reference to the main behaviour coordinating the whole
	//action invocations of the RobotAgent
	private RunRobotBehaviour runBehaviour;
	
	
	//satic variables representing a direction when moving
	final static int NORTH = 1;
	final static int NORTH_EAST = 2;
	final static int EAST = 3;
	final static int SOUTH_EAST = 4;
	final static int SOUTH = 5;
	final static int SOUTH_WEST = 6;
	final static int WEST = 7;
	final static int NORTH_WEST = 8;
	
	
	//speed of robot  meter/sec.
	private double speed;
	
	//reference to GUI of ManualRobotAgent
	public ManualRobotAgentGUI myGUI;
	
	//attributes representing states of RobotAgent
	private boolean actionState;
	
	//behaviour objects
	private RobotMoveBehaviour moveBehaviour;
	
	//contains the AID of the server agent for now it is a given AID
	private AID server;
	
		
	protected void setup() {
		init();
		
	}
	
	
	
	//method to initialize ManualRobotAgent
	public void init() {
		
		Object[] args = getArguments();
   		String fieldSize = (String)args[0]; 
		
		alive = true;
		suspended = false;
		
		direction = RobotAgent.SOUTH_EAST;
		speed = 2;
		
		server = new AID("server@"+getHap(), AID.ISGUID);
		
		runBehaviour = new RunRobotBehaviour(this, server);
		addBehaviour(runBehaviour);
				
		myGUI = new ManualRobotAgentGUI(this, fieldSize);
		setManualAgent(true);
		
		addBehaviour(new RobotAgentRegisterBehaviour(this, server));
		addBehaviour(new RobotAgentDeregisterBehaviour(this, server));
		addBehaviour(new RobotReceiveSimpleMessage(this));
		
		ACLMessage requestMessage = new ACLMessage(ACLMessage.REQUEST);
		requestMessage.setLanguage("REGISTER-INFO");
		requestMessage.addReceiver(server);
		send(requestMessage);
		
		System.out.println("\n>>> Robot has been started! It`s name is " + getLocalName() + "\n");
	}
	
	

	//closes ManualRobotAgentGUI when ManualRobotAgent is about to be killed
	protected void takeDown() {
		try {
			myGUI.loeschen();
		} catch (NullPointerException e) {}
		//+zusätziche Aufräumarbeiten wie Abmelden beim FieldAgent und ServerAgent!!!
		System.out.println("\n----------------------------------");
		System.out.println(">>> RobotAgent "+getLocalName()+" switched off!");
		System.out.println("----------------------------------");
	}
	
	
	//deregister method is called by takeDown() to deregister the RobotAgent with the
	//server
	public void deregister() {
		
		ACLMessage deregisterMessage = new ACLMessage(ACLMessage.REQUEST);
		
		deregisterMessage.setLanguage("DEREGISTER");
		deregisterMessage.setContent(getLocalName());
		deregisterMessage.addReceiver(server);
		send(deregisterMessage);
	}
	
		
	//method move() is used whenever Robot decides to move
	//required parameters: distance, direction
	public void move(int distance, int direction) {

		if (myGUI.getEnergyLevel() > 0) {
			if (this.direction != direction) {
				turn(direction);
			}
			runBehaviour.move(distance, direction);
		}
		
		/*if (!suspended && alive) {
			movingState = true;
			moveBehaviour = new RobotMoveBehaviour((RobotAgent)this, server, distance, direction);
			addBehaviour(moveBehaviour);
		}*/
	}
	
	
	//method move() is used whenever Robot decides to move to the RobotAgent direction
	//required parameters: direction
	public void move(int distance) {
	
		if (myGUI.getEnergyLevel() > 0) {
			runBehaviour.move(distance, this.direction);
		}
	}
	
	
	
	//lets the RobotAgent use the touch sensor
	public void touch() {
		
		if (myGUI.getEnergyLevel() > 0) {
			runBehaviour.touch();
		}
	}
	
	
	//lets the RobotAgent use the touch sensor
	public void humidity() {
		
		if (myGUI.getEnergyLevel() > 0) {
			runBehaviour.humidity();
		}
	}
	
	
	//lets the RobotAgent use the metal sensor
	public void metall() {
		
		if (myGUI.getEnergyLevel() > 0) {
			runBehaviour.metall();
		}
	}
	
	
	//lets the RobotAgent use the optic sensor
	public void optic() {
		
		if (myGUI.getEnergyLevel() > 0) {
			runBehaviour.optic();
		}
	}
	
	
	//lets the RobotAgent use the infra-red sensor
	public void infraRed() {
		
		if (myGUI.getEnergyLevel() > 0) {
			runBehaviour.infraRed();
		}
	}
		
	
	//method finishes move action
	public void finishMove() {
		setActionState(false);
		runBehaviour.finishMove();
	}
	
	
	//method turn() is used whenever Robot decides to turn
	//required parameter: direction
	public void turn(int direction) {
		
		if (myGUI.getEnergyLevel() > 0) {
			runBehaviour.turn(direction);
		}
	}
	
	
	//method finishes turn action
	public void finishTurn() {
		setActionState(false);
		runBehaviour.finishTurn();
	}
	
	
	//method finishes sensor action
	public void finishSensor(String sensorData) {
		setActionState(false);
		this.sensorData = sensorData;
		runBehaviour.finishSensor();
	}
	
	
	//sends a message with no format to another RobotAgent
	public void sendSimpleMessage(String receiver, String content) {
		
		ACLMessage message = new ACLMessage(ACLMessage.INFORM);
		message.setLanguage("SIMPLE-MESSAGE");
		message.addReceiver(new AID(receiver+"@"+getHap(), AID.ISGUID));
		message.setContent(content);
		send(message);
	}
	
	
	//method abortMove() can be called to abort move(); if an abort has succeeded, this
	//method returns true, otherwise it returns false
	//aborting a move is only possible if the behaviour is in ABORT_POSSIBLE state
	public boolean abortMove() {
		if (actionState == true) {
			if (moveBehaviour.abortPossible()) {
				removeBehaviour(moveBehaviour);
				moveBehaviour = null;
				actionState = false;
				System.out.println("\n"+getLocalName()+": MOVE aborted!");
				return true;
			} else {
				System.out.println("\n"+getLocalName()+": MOVE cannot be aborted!");
				return false;
			}
		} else {
			return false;
		}
	}
	
	//method to set actionState
	public void setActionState(boolean state) {
		actionState = state;
	}
	
		
	public void changeEnergyLevel(double value) {
		myGUI.changeEnergyBar(value);
	}
	
	
	//returns action state
	public boolean getActionState() {
		return actionState;
	}
			
	
	public void updateGUImove(String moveData) {
		myGUI.bewegen(moveData);
	}
	

	public void updateGUIturn(String turnData) {
		this.direction = (new Integer(turnData)).intValue();
		
		myGUI.drehen(turnData);
	}
	
	
	public void updateGUIsensor(String sensorData) {
		
		String sensorType = sensorData.substring(0, sensorData.indexOf(";"));
		String data = sensorData.substring(sensorData.indexOf(";")+1, sensorData.length());
		
		if (sensorType.equals("touch")) {
			myGUI.touch(data);
		}
		
		
		if (sensorType.equals("metall")) {
			myGUI.metall(data);
		}
		
		
		if (sensorType.equals("optic")) {
			
			// String mittels Base64 decodieren
  			byte buffer_back[]=Base64.decode(data);
    		optic = new ImageIcon(buffer_back);
			
			myGUI.setFoto(optic);
		}
		
		
		if (sensorType.equals("infra")) {
			
			// String mittels Base64 decodieren
  			byte buffer_back[]=Base64.decode(data);
    		infraRed = new ImageIcon(buffer_back);
			
			myGUI.setIR(infraRed);
		}
	}
	
	
	public void updateGUIsimpleMessage(String sender, String content) {
		myGUI.addAntwort(sender, content);
	}
	

	public void updateGUIStatus(String text) {
		myGUI.addStatus(text);
	}
	
	
	public void updateRobots(String robots) {
		myGUI.addRobotToList(robots);
	}
	
	
	//returns the life-status of the RobotAgent
	public boolean isAlive() {
		return alive;
	}
	
	//sets the life-status of the RobotAgent to false
	public void kill() {
		alive = false;
		suspended = true;
	}
	
	//suspends RobotAgent
	public void suspend() {
		if (alive) {
			doSuspend();
		}
	}
	
	
	public double getSpeed() {
		return speed;
	}
	
	
	public boolean suspended() {
		return suspended;
	}
	

	public void setSpeed(double value) {
		speed = value;
	}
	
	
	public double getEnergyLevel() {
		return 2.0;
		//return myGUI.getEnergyLevel();
	}
	
	
	public int getDirection() {
		return direction;
	}
}