package nuts.core.beans;

import java.util.Calendar;
import java.util.Date;

import junit.framework.TestCase;

import nuts.core.beans.BeanHandler;
import nuts.core.beans.BeanHandlerFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * JavaBeanHandlerTest
 */
public class JavaBeanHandlerTest extends TestCase {

	private static Log log = LogFactory.getLog(JavaBeanHandlerTest.class);

	protected BeanHandler getBeanHandler(Class type) {
		return BeanHandlerFactory.getInstance().getBeanHandler(type);
	}

	@SuppressWarnings("unchecked")
	protected void testGetType(Object beanObject, String propertyName, Class expected) {
		log.debug("testGetType: " + beanObject.getClass().getName() + " - " + propertyName + " [ "
				+ expected.getName() + " ]");

		Class actual;
		try {
			BeanHandler bh = getBeanHandler(beanObject.getClass());
			actual = bh.getBeanType(beanObject, propertyName);
		}
		catch (RuntimeException e) {
			log.error("exception", e);
			throw e;
		}
		assertEquals(expected, actual);
	}

	@SuppressWarnings("unchecked")
	protected void testSetGetValue(Object beanObject, String propertyName, Object expected) {
		log.debug("testSetGetValue: " + beanObject.getClass().getName() + " - " + propertyName
				+ " - " + expected + " [ " + expected.getClass().getName() + " ]");

		Object actual;
		try {
			BeanHandler bh = getBeanHandler(beanObject.getClass());
			bh.setBeanValue(beanObject, propertyName, expected);
			actual = bh.getBeanValue(beanObject, propertyName);
		}
		catch (RuntimeException e) {
			log.error("exception", e);
			throw e;
		}
		assertEquals(expected, actual);
	}

	/**
	 * testCreateObject
	 */
	public void testCreateObject() {
		TestA actual;
		try {
			BeanHandler bh = getBeanHandler(TestA.class);
			actual = (TestA) bh.createObject();
		}
		catch (RuntimeException e) {
			log.error("exception", e);
			throw e;
		}
		assertNotNull(actual);
	}

	/**
	 * testGetPropertyType
	 */
	public void testGetPropertyType() {
		TestA a = new TestA();

		testGetType(a, "boolField", boolean.class);
		testGetType(a, "byteField", byte.class);
		testGetType(a, "charField", char.class);
		testGetType(a, "doubleField", double.class);
		testGetType(a, "floatField", float.class);
		testGetType(a, "intField", int.class);
		testGetType(a, "longField", long.class);
		testGetType(a, "shortField", short.class);

		testGetType(a, "boolArray", boolean[].class);
		testGetType(a, "byteArray", byte[].class);
		testGetType(a, "charArray", char[].class);
		testGetType(a, "doubleArray", double[].class);
		testGetType(a, "floatArray", float[].class);
		testGetType(a, "intArray", int[].class);
		testGetType(a, "longArray", long[].class);
		testGetType(a, "shortArray", short[].class);

		testGetType(a, "boolWrap", Boolean.class);
		testGetType(a, "byteWrap", Byte.class);
		testGetType(a, "charWrap", Character.class);
		testGetType(a, "doubleWrap", Double.class);
		testGetType(a, "floatWrap", Float.class);
		testGetType(a, "intWrap", Integer.class);
		testGetType(a, "longWrap", Long.class);
		testGetType(a, "shortWrap", Short.class);

		testGetType(a, "stringField", String.class);
		testGetType(a, "dateField", Date.class);
		testGetType(a, "stringArray", String[].class);
		testGetType(a, "dateArray", Date[].class);

		testGetType(a, "testB", TestB.class);

		testGetType(a, "testB.boolField", boolean.class);
		testGetType(a, "testB.byteField", byte.class);
		testGetType(a, "testB.charField", char.class);
		testGetType(a, "testB.doubleField", double.class);
		testGetType(a, "testB.floatField", float.class);
		testGetType(a, "testB.intField", int.class);
		testGetType(a, "testB.longField", long.class);
		testGetType(a, "testB.shortField", short.class);

		testGetType(a, "testB.boolArray", boolean[].class);
		testGetType(a, "testB.byteArray", byte[].class);
		testGetType(a, "testB.charArray", char[].class);
		testGetType(a, "testB.doubleArray", double[].class);
		testGetType(a, "testB.floatArray", float[].class);
		testGetType(a, "testB.intArray", int[].class);
		testGetType(a, "testB.longArray", long[].class);
		testGetType(a, "testB.shortArray", short[].class);

		testGetType(a, "testB.boolWrap", Boolean.class);
		testGetType(a, "testB.byteWrap", Byte.class);
		testGetType(a, "testB.charWrap", Character.class);
		testGetType(a, "testB.doubleWrap", Double.class);
		testGetType(a, "testB.floatWrap", Float.class);
		testGetType(a, "testB.intWrap", Integer.class);
		testGetType(a, "testB.longWrap", Long.class);
		testGetType(a, "testB.shortWrap", Short.class);

		testGetType(a, "testB.stringField", String.class);
		testGetType(a, "testB.dateField", Date.class);
		testGetType(a, "testB.stringArray", String[].class);
		testGetType(a, "testB.dateArray", Date[].class);

		testGetType(a, "testB.testA", TestA.class);
	}

	/**
	 * testSetGetPropertyValue
	 */
	public void testSetGetPropertyValue() {
		TestA a = new TestA();

		testSetGetValue(a, "boolField", true);
		testSetGetValue(a, "byteField", (byte)10);
		testSetGetValue(a, "charField", 'c');
		testSetGetValue(a, "doubleField", (double)101.001);
		testSetGetValue(a, "floatField", (float)102.102);
		testSetGetValue(a, "intField", (int)1000);
		testSetGetValue(a, "longField", (long)10000);
		testSetGetValue(a, "shortField", (short)100);

		testSetGetValue(a, "boolArray", new boolean[] { true, false });
		testSetGetValue(a, "byteArray", new byte[] { 1, 2 });
		testSetGetValue(a, "charArray", new char[] { 'a', 'b' });
		testSetGetValue(a, "doubleArray", new double[] { 1.1, 2.2 });
		testSetGetValue(a, "floatArray", new float[] { 3.3F, 4.4F });
		testSetGetValue(a, "intArray", new int[] { 101, 102 });
		testSetGetValue(a, "longArray", new long[] { 1001L, 1002L });
		testSetGetValue(a, "shortArray", new short[] { 11, 12 });

		testSetGetValue(a, "boolWrap", Boolean.TRUE);
		testSetGetValue(a, "byteWrap", new Byte((byte)10));
		testSetGetValue(a, "charWrap", new Character('C'));
		testSetGetValue(a, "doubleWrap", new Double(101.101));
		testSetGetValue(a, "floatWrap", new Float(102.102));
		testSetGetValue(a, "intWrap", new Integer(1000));
		testSetGetValue(a, "longWrap", new Long(10000));
		testSetGetValue(a, "shortWrap", new Short((short)100));

		testSetGetValue(a, "stringField", "String");
		testSetGetValue(a, "dateField", Calendar.getInstance().getTime());
		testSetGetValue(a, "stringArray", new String[] { "abc", "efd" });
		testSetGetValue(a, "dateArray", new Date[] { Calendar.getInstance().getTime() });

		testSetGetValue(a, "testB", new TestB());
	}

	/**
	 * testSetGetPropertyValue02
	 */
	public void testSetGetPropertyValue02() {
		TestA a = new TestA();

		testSetGetValue(a, "testB.boolField", true);
		testSetGetValue(a, "testB.byteField", (byte)10);
		testSetGetValue(a, "testB.charField", 'c');
		testSetGetValue(a, "testB.doubleField", (double)101.001);
		testSetGetValue(a, "testB.floatField", (float)102.102);
		testSetGetValue(a, "testB.intField", (int)1000);
		testSetGetValue(a, "testB.longField", (long)10000);
		testSetGetValue(a, "testB.shortField", (short)100);

		testSetGetValue(a, "testB.boolArray", new boolean[] { true, false });
		testSetGetValue(a, "testB.byteArray", new byte[] { 1, 2 });
		testSetGetValue(a, "testB.charArray", new char[] { 'a', 'b' });
		testSetGetValue(a, "testB.doubleArray", new double[] { 1.1, 2.2 });
		testSetGetValue(a, "testB.floatArray", new float[] { 3.3F, 4.4F });
		testSetGetValue(a, "testB.intArray", new int[] { 101, 102 });
		testSetGetValue(a, "testB.longArray", new long[] { 1001L, 1002L });
		testSetGetValue(a, "testB.shortArray", new short[] { 11, 12 });

		testSetGetValue(a, "testB.boolWrap", Boolean.TRUE);
		testSetGetValue(a, "testB.byteWrap", new Byte((byte)10));
		testSetGetValue(a, "testB.charWrap", new Character('C'));
		testSetGetValue(a, "testB.doubleWrap", new Double(101.101));
		testSetGetValue(a, "testB.floatWrap", new Float(102.102));
		testSetGetValue(a, "testB.intWrap", new Integer(1000));
		testSetGetValue(a, "testB.longWrap", new Long(10000));
		testSetGetValue(a, "testB.shortWrap", new Short((short)100));

		testSetGetValue(a, "testB.stringField", "String");
		testSetGetValue(a, "testB.dateField", Calendar.getInstance().getTime());
		testSetGetValue(a, "testB.stringArray", new String[] { "abc", "efd" });
		testSetGetValue(a, "testB.dateArray", new Date[] { Calendar.getInstance().getTime() });

		testSetGetValue(a, "testB.testA", new TestA());
	}

	/**
	 * testGetPropertyValueOnly
	 */
	@SuppressWarnings("unchecked")
	public void testGetPropertyValueOnly() {
		String expected = "test getField ";
		Object actual;
		try {
			TestA testA = new TestA();

			BeanHandler bh = getBeanHandler(testA.getClass());

			testA.getField = expected;

			actual = bh.getBeanValue(testA, "getField");
		}
		catch (RuntimeException e) {
			log.error("exception", e);
			throw e;
		}
		assertEquals(expected, actual);
	}

	/**
	 * testSetPropertyValueOnly
	 */
	@SuppressWarnings("unchecked")
	public void testSetPropertyValueOnly() {
		String expected = "test getField ";
		Object actual;
		try {
			TestA testA = new TestA();

			BeanHandler bh = getBeanHandler(testA.getClass());

			bh.setBeanValue(testA, "setField", expected);
			
			actual = testA.setField;
		}
		catch (RuntimeException e) {
			log.error("exception", e);
			throw e;
		}
		assertEquals(expected, actual);
	}
}
