package jp.co.denso.fa.jmscaosql.jms;

import java.io.FileOutputStream;
import java.util.Properties;

import jp.co.denso.fa.jcaosql.CaoSQLController;
import jp.co.denso.fa.jcaosql.CaoSQLEngine;
import jp.co.denso.fa.jcaosql.CaoSQLItem;
import jp.co.denso.fa.jmscaosql.JmsCaoSQLClient;
import jp.co.denso.fa.jmscaosql.JmsCaoSQLRmiClient;
import junit.framework.TestCase;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class JmsPublishTest extends TestCase {

	private static Logger logger = LoggerFactory.getLogger(JmsPublishTest.class);

	private ClassPathXmlApplicationContext context;
	private JmsCaoSQLClient client;
	private JmsCaoSQLRmiClient rmiClient;
	private JmsMessageConsumer consumer;
	private CaoSQLEngine engine;

	public JmsPublishTest(String name) {
		super(name);
	}

	/* (非 Javadoc)
	 * @see junit.framework.TestCase#setUp()
	 */
	@Override
	protected void setUp() throws Exception {
		super.setUp();
		String basepath = System.getProperty("user.dir");
		Properties prop = new Properties();
		prop.setProperty("event.listen.target", "Ctrl1,Ctrl2");
		prop.store(new FileOutputStream(basepath + "/target/test-classes/jmscaosql.properties"), "Controller name to be published");

		context = new ClassPathXmlApplicationContext("JmsCaoSQLTest-context.xml");
		if (getName().endsWith("Rmi")) {
			rmiClient = (JmsCaoSQLRmiClient)context.getBean("rmiClient");
		} else {
			client = (JmsCaoSQLClient)context.getBean("client");
		}
		consumer = (JmsMessageConsumer)context.getBean("consumer");

		engine = CaoSQLEngine.createInstance();
	}

	/* (非 Javadoc)
	 * @see junit.framework.TestCase#tearDown()
	 */
	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
		if (client != null) {
			client.stop();
		}

		if (rmiClient != null) {
			rmiClient.stop();
		}

		if (engine != null) {
			engine.release();
			engine = null;
		}

		if (context != null) {
			context.close();
		}
	}

	/**
	 * 同期状態でスレッドを待機します。
	 *
	 * @param time 待機時間(ミリ秒)
	 */
	protected synchronized void sleep(int time) {
		try {
			wait(time);
		} catch (InterruptedException e) {
		}
	}

	protected Object[] createItemParam(String ctrlName, String itemName) {
		Object[] objArray = new Object[41];
		objArray[0] = itemName;
		objArray[1] = new Boolean(true);
		objArray[2] = itemName;
		objArray[3] = new String();
		objArray[4] = new Integer(0);
		objArray[5] = new String(ctrlName);
		objArray[6] = new String();
		objArray[7] = new Integer(0);
		objArray[8] = new String();
		objArray[9] = new Boolean(false);
		objArray[10] = new String();
		objArray[11] = new Integer(0);
		objArray[12] = new Boolean(true);
		objArray[13] = new Boolean(false);
		objArray[14] = new Boolean(true);
		objArray[15] = new Integer(0);
		objArray[16] = new Boolean(false);
		objArray[17] = new Float(0.0);
		objArray[18] = new Float(0.0);
		objArray[19] = new Boolean(false);
		objArray[20] = new Float(0.0);
		objArray[21] = new Float(0.0);
		objArray[22] = new Boolean(false);
		objArray[23] = new Integer(0);
		objArray[24] = new Boolean(false);
		objArray[25] = new Integer(0);
		objArray[26] = new Boolean(false);
		objArray[27] = new Integer(0);
		objArray[28] = new String();
		objArray[29] = new Boolean(true);
		objArray[30] = new Integer(9);
		objArray[31] = new Boolean(true);
		objArray[32] = new Integer(9);
		objArray[33] = new Boolean(false);
		objArray[34] = new Boolean(false);
		objArray[35] = new Boolean(false);
		objArray[36] = new Integer(0);
		objArray[37] = new Integer(0);
		objArray[38] = new Integer(0);
		objArray[39] = new String();
		objArray[40] = new String();

		return objArray;
	}

	public void testOnChangeState() throws Exception {
		CaoSQLController ctrl = engine.Controller("Ctrl1");
		assertNotNull(ctrl);
		// 一旦停止する
		ctrl.stop();

		client.init();
		assertTrue(client.isRunning());
		ctrl.start();
		sleep(1000);

		ctrl.stop();
		sleep(1000);

		ctrl.release();
	}

	public void testOnChangeItem() throws Exception {
		CaoSQLController ctrl = engine.Controller("Ctrl1");
		assertNotNull(ctrl);
		CaoSQLItem item1 = ctrl.Item("Item1");
		CaoSQLItem item2 = ctrl.Item("Item2");

		ctrl.start();
		sleep(1000);

		item1.putValue("");
		item2.putValue("");

		client.init();
		assertTrue(client.isRunning());

		item1.putValue("Item1 changed");
		logger.info("Item1 changed value.");
		sleep(5000);

		item2.putValue("Item2 changed");
		logger.info("Item2 changed value.");
		sleep(5000);

		ctrl.release();
	}

	public void testOnMessage() throws Exception {
		CaoSQLController ctrl = engine.Controller("Ctrl2");
		assertNotNull(ctrl);
		ctrl.start();
		sleep(1000);

		client.init();
		assertTrue(client.isRunning());

		String itemName = "Item3";
		Object[] objArray = createItemParam(ctrl.getName(), itemName);
		ctrl.additem(objArray);
		sleep(5000);

		CaoSQLItem item = ctrl.Item(itemName);
		sleep(5000);

		item.putValue(itemName + " New Create.");
		sleep(5000);

		ctrl.removeitem(itemName);
		sleep(5000);

		item.release();

		ctrl.release();
	}

	public void testOnChangeStateRmi() throws Exception {
		CaoSQLController ctrl = engine.Controller("Ctrl1");
		assertNotNull(ctrl);
		// 一旦停止する
		ctrl.stop();

		rmiClient.init();
		assertTrue(rmiClient.isRunning());
		ctrl.start();
		sleep(3000);

		ctrl.stop();
		sleep(3000);

		ctrl.release();
	}

	public void testOnChangeItemRmi() throws Exception {
		CaoSQLController ctrl = engine.Controller("Ctrl1");
		assertNotNull(ctrl);
		CaoSQLItem item1 = ctrl.Item("Item1");
		CaoSQLItem item2 = ctrl.Item("Item2");

		ctrl.start();
		sleep(1000);

		item1.putValue("");
		item2.putValue("");

		rmiClient.init();
		assertTrue(rmiClient.isRunning());

		item1.putValue("Item1 changed");
		logger.info("Item1 changed value.");
		sleep(5000);

		item2.putValue("Item2 changed");
		logger.info("Item2 changed value.");
		sleep(5000);

		ctrl.release();
	}

	public void testOnMessageRmi() throws Exception {
		CaoSQLController ctrl = engine.Controller("Ctrl2");
		assertNotNull(ctrl);
		ctrl.start();
		sleep(1000);

		rmiClient.init();
		assertTrue(rmiClient.isRunning());

		String itemName = "Item3";
		Object[] objArray = createItemParam(ctrl.getName(), itemName);
		ctrl.additem(objArray);
		sleep(5000);

		CaoSQLItem item1 = ctrl.Item(itemName);
		sleep(1000);

		item1.putValue("Item1 New Create.");
		sleep(1000);

		item1.release();

		ctrl.removeitem(itemName);
		sleep(5000);

		ctrl.release();
	}
}
