package ws.prova.jade;

/*
 * Copyright (C) 2002-2004 Jacek Gomoluch</a>
 * Copyright (C) 2002-2007 <a href="mailto:a.kozlenkov@city.ac.uk">Alex Kozlenkov</a>
 *
 * 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 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
 */

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;
import jade.lang.acl.ACLMessage;
import ws.prova.RMessage;
import ws.prova.reagent;

/**
 * Agent which is used internally by the Jade exchange.
 * It can both send and receive messages. For incoming messages, it accepts
 * an Object through the
 * object-to-agent communication channel, and queues it in the Prova
 * message queue.
 *
 * @author Jacek Gomoluch
 * @version 2.0 <25 March 2007>
 */
public class CustomAgent extends Agent {

	public void setup() {

		//System.out.println("Agent name: "+getAID().getName()+"  Agent address: "+getAID().getAddressesArray()[0]);

		// Accept objects through the object-to-agent communication
		// channel, with a maximum size of 10 queued objects
		setEnabledO2ACommunication(true, 10);

		// Add a suitable behaviour for receiving messages
		addBehaviour(new ProcessMessageBehaviour("Queue listener", (reagent) getArguments()[0]));

		// Add a suitable behaviour for sending messages
		addBehaviour(new SendMessageBehaviour());

	} // end setup method
} // End of CustomAgent class

/**
 * Class representing the JADE message sending behaviour
 */
class SendMessageBehaviour extends Behaviour {

//	private String id;
//	private reagent prova;

	ACLMessage msg = null;
	Object[] obj = null;


	public SendMessageBehaviour() {
		super();
	}

	public void action() {

		//-----------------------------------------------------------------

		// FOR SENDING MESSAGES
		// Retrieve the first object from the O2A queue - which is an ACL
		// message - and send it

		// obj[0]: name of the receiver
		// obj[1]: address of the receiver
		// obj[2]: the message object
		// obj[3]: jade_exchange for synchronization
		obj = (Object[]) myAgent.getO2AObject();

		while (obj != null) {

//	      System.out.println(myAgent.getLocalName()+": Sending message: [" + obj + "]");

			msg = new ACLMessage(ACLMessage.INFORM);

			AID to = new AID();
			to.setName((String) obj[0]);

			// if the receiver address is provided then pass it to the AID
			// else: assume it is at the local platform, therefore the
			//       sender's address can be used
			if (obj[1] != null) {
				to.addAddresses((String) obj[1]);
			} else {
				to.addAddresses(myAgent.getAID().getAddressesArray()[0]);
			}

			//System.out.println("to: name: "+to.getName());
			//System.out.println("to: address: "+to.getAddressesArray()[0]);
			//System.out.println("to: content: "+((RMessage)obj[2]).string);

			try {
				msg.addReceiver(to);
				msg.setContentObject((RMessage) obj[2]);
				msg.setOntology("whatever");
				msg.setDefaultEnvelope();
				// send it
				myAgent.send(msg);


			} catch (Exception e) {
				System.err.println(myAgent.getLocalName() + ": ProcessMessageBehaviour: Sending messages:  " + e);
			}
			synchronized (obj[3]) {
				try {
					obj[3].notifyAll();
				} catch (Exception e) {
				}
			}
			// get the next object from the O2A queue - if any
			obj = (Object[]) myAgent.getO2AObject();


		}

		//-----------------------------------------------------------------


		//System.out.println(myAgent.getLocalName()+": SendMessageBehaviour: End of action method ... now block the behaviour");
		block();

	} // end method action


	// This behaviour never ends
	public boolean done() {
		return false;
	}

} // end class SendMessageBehaviour

/*
 * This behaviour allows the agent to process messages in the
 * background which has been received by the ReceiverBehaviour
 * Whenever a MessageInvocation is received, it is executed
 * immediately. The behaviour never terminates.
 */

class ProcessMessageBehaviour extends Behaviour {

	private String id;
	private reagent prova;

	ACLMessage msg = null;

	public ProcessMessageBehaviour(String _id, reagent _prova) {
		super();
		id = _id;
		prova = _prova;
	}

	public void action() {

		msg = myAgent.receive();
//		try {
//			Thread.sleep(100);
//		}
//		catch (InterruptedException ex) {
//		}

		while (msg != null) {

			try {

				// get the message
//            System.out.println(myAgent.getLocalName()+": Received a message: "+msg);

				if (msg.getContentObject() instanceof String) {
					String content = (String) msg.getContentObject();
//				System.out.println(id + ": " + content);
					// Put the received message to the reagent queue for processing
					RMessage rmsg = new RMessage(content);
					rmsg.setProtocol("jade");
					prova.queue().add(rmsg);
				} else /*if (msg instanceof Object)*/ {
					RMessage rmsg = (RMessage) msg.getContentObject();
//				System.out.println(id + ": " + rmsg);
//				System.out.println("Content of message: " + rmsg.content());
					rmsg.setProtocol("jade");
					// Put the received message to the reagent queue for processing
					prova.queue().add(rmsg);
				}

//			System.out.println("Content of queue: ");
				// display what is now in the queue
//        	for (int i=0;i<prova.queue().size();i++)
//		      System.out.println(((RMessage)prova.queue().get(i)).content());

			} catch (Exception e) {
				System.err.println("ProcessMessageBehaviour: receive:" + myAgent.getLocalName() + e);
			}

			// in case that there is another message waiting
			msg = myAgent.receive();

		} // end if

		//-----------------------------------------------------------------

		//System.out.println(myAgent.getLocalName()+": ProcessMessageBehaviour: End of action method ... now block the behaviour");
		block();

	} // end method action


	// This behaviour never ends
	public boolean done() {
		return false;
	}

} // end class ProcessMessageBehaviour

