package ws.prova.test;

/*
 * 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 org.mandarax.kernel.InferenceException;
import ws.prova.Communicator;
import ws.prova.RMessage;
import ws.prova.esb.ProvaUMO;
import ws.prova.examples.Order;
import ws.prova.parser.ParsingException;

import java.io.IOException;
import java.util.List;

/**
 * Standalone test of consulting and querying a Prova rulebase from Java
 * <p>Title: Prova </p>
 * <p>Description: Standalone test of consulting and querying a Prova rulebase from Java</p>
 * <p>Copyright: Copyright (C) 2002-2008</p>
 *
 * @author <A HREF="mailto:alex.kozlenkov@googlemail.com">Alex Kozlenkov</A>
 * @version 2.0 <19 February 2008>
 */

public class ProvaRunner2 {
	static final String kAgent = "prova";
	// Port equal to null denotes no external communication protocols activated
	static final String kPort = null;

	Communicator comm;

	private Object synch = "";
	private Object result;
	private Thread resultsThread;

	public ProvaRunner2(String rulebase) {
		// First, create a thread that waits for results (or exceptions)
		resultsThread = new Thread() {
			public void run() {
				synchronized (synch) {
					try {
						while (!isInterrupted()) {
							System.out.println("waiting starting...");
							synch.wait();
							System.out.println("...waiting complete");
							System.out.println(result);
						}
					} catch (InterruptedException ex) {
					}
				}
			}
		};
		resultsThread.start();

		// Create an out-of-thread Communicator that will keep the message loop indefinitely
		//    to make asynchronous queries from other (including main) threads possible.
		// "-1" is the timeout for the message queue: in this case, the queue will exist indefinitely
		// IMPORTANT NOTE: All communication with an asynchronous Communicator must go through
		//    consultAsync or sendMsg
		comm = new Communicator(kAgent, kPort, rulebase, -1, Communicator.ASYNC);
    }

	/**
	 * Accept the query results from the rulebase and notify the caller.
	 *
	 * @param res The results of the query as a List.
	 *            <br> Note that the Prova code may return either a Prova list or a Java list--both will work.
	 *            <br> In the first case, a Prova list is transparently converted to a Java list passed as a parameter here.
	 */
	public void results_ready(List res) {
		synchronized (synch) {
			result = res;
			synch.notifyAll();
		}
	}

	/**
	 * An example method for demonstrating how a call from Prova can intercept the exception raised here.
	 *
	 * @throws Exception
	 */
	public void results_ready_raising_exception() throws Exception {
		throw new Exception("A Java method that raises exception has been called.");
	}

	/**
	 * Test ws.prova.reagent.consultAsync by running an example of Karsten Kuhla.
	 * We run the goal twice and each run returns two results with one instantiated variable in each.
	 * Java objects can now be inserted into the consulted code as _0, _1, ..., _n
	 * corresponding to the elements in the Object[] array supplied to
	 * ws.prova.Communicator.consultAsync().
	 */
	public void testConsultAsync() throws Exception {
		String input = ":- eval(happy_for_eval(_0)).";
		comm.consultAsync(input, new Object[]{this});
	}

	/**
	 * Test ws.prova.reagent.consultAsync by running an example of Karsten Kuhla.
	 */
	public void testSendMsg() throws Exception {
		comm.sendMsg(null, "self", "0", "eval", "happy_for_eval,%0", new Object[]{this});
	}

	/**
	 * Test ws.prova.reagent.consultAsync by running an example of Karsten Kuhla.
	 */
	public void testDiscountExample() throws IOException, ParsingException, InferenceException {
		comm.sendMsg(null, "self", "0", "eval", "consult,%0", new Object[]{"rules/prova-examples/discount.prova"});
		Order order = new Order("cust_A");
		order.addItem("item_A");
		order.addItem("item_B");
		order.addItem("item_C");
		comm.sendMsg(null, "self", "0", "process", "order,%0", new Object[]{order});
		comm.sendMsg(null, "self", "0", "submit", "order,%0", new Object[]{order});

		// The second order from the same customer
		order = new Order("cust_A");
		order.addItem("item_B");
		comm.sendMsg(null, "self", "0", "process", "order,%0", new Object[]{order});
		comm.sendMsg(null, "self", "0", "submit", "order,%0", new Object[]{order});
	}

	public void runTests() {
		// Start an event generator
		try {
			testDiscountExample();
			for (int i = 0; i < 1; i++) {
				testConsultAsync();
			}
			for (int i = 0; i < 0; i++) {
				testSendMsg();
			}
		} catch (Exception e) {
			System.out.println("Test fails.");
		}
	}

	public static void main(String[] args) {
		ProvaRunner2 runner = new ProvaRunner2("rules/prova-examples/kk_rules001.prova");
		runner.runTests();
	}

}
