package anyframe.core.query.ria.gauce.impl;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import anyframe.common.util.DateUtil;
import anyframe.core.query.ria.gauce.IGauceQueryService;

import com.gauce.GauceDataColumn;
import com.gauce.GauceDataRow;
import com.gauce.GauceDataSet;

public class GauceQueryServiceTestGeneral extends AbstractTest {

	/**
	 * 테스트 수행을 위한 main
	 */
	public static void main(String[] args) throws Exception {
		GauceQueryServiceTestGeneral queryTest = new GauceQueryServiceTestGeneral();
		// 1. initialize context
		queryTest.setup();
		// 2. testInsertGauceDataSet();
		queryTest.testInsertGauceDataSet();
		// 3. testUpdateGauceDataSet();
		queryTest.testUpdateGauceDataSet();
		// 4. testFindGauceDataSet();
		queryTest.testFindGauceDataSet();
		// 5. testFindGauceDataSetWithActionCommand();
		queryTest.testFindGauceDataSetWithActionCommand();
		// 6. testProcessAllGauceDataSet();
		queryTest.testProcessAllGauceDataSet();

		// 7. close context
		queryTest.teardown();

		System.out.println("Successful!!!!!");
	}

	protected void setup() {
		super.setup();
		try {
			testInit();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void testInit() throws Exception {
		DataSource dataSource = (DataSource) context
				.getBean("common_datasource");
		try {
			Connection conn = dataSource.getConnection();
			try {
				conn.setAutoCommit(true);
				Statement statement = conn.createStatement();

				try {
					statement.executeUpdate("DROP TABLE TBL_GAUCE_TEST");
				} catch (SQLException e) {
					System.out.println("Fail to DROP Table");
				}

				StringBuffer createSql = new StringBuffer();
				createSql.append(" CREATE TABLE TBL_GAUCE_TEST ( ");
				createSql
						.append(" testchar CHAR(1), testvarchar VARCHAR2(255), ");
				createSql.append(" testint INTEGER, testnumber NUMBER(9,2), ");
				createSql.append(" testbignumber NUMBER(38), testdate DATE )");
				statement.executeUpdate(createSql.toString());

				statement
						.executeUpdate("INSERT INTO TBL_GAUCE_TEST(testchar, testvarchar, testint, testnumber, testbignumber, testdate) "
								+ " values ( 'A', 'Anyframe Test', '123456', 1234567.89, 12345678901234567890123456789012345678, sysdate)");
				statement
						.executeUpdate("INSERT INTO TBL_GAUCE_TEST(testchar, testvarchar, testint, testnumber, testbignumber, testdate) "
								+ " values ( 'B', '애니프레임자바 테스트', '987654', 9876543.21, 98765432109876543210987654321098765432, sysdate)");

			} finally {
				conn.close();
			}
		} catch (SQLException e) {
			System.err.println("Unable to initialize database for test." + e);
		}
	}

	/**
	 * Gauce용 Query 서비스를 통해 DB에 신규 데이터를 입력하는 테스트 코드
	 */
	public void testInsertGauceDataSet() throws Exception {
		IGauceQueryService gauceQueryService = (IGauceQueryService) context
				.getBean("gauceQueryService");
		Map queryMap = new HashMap();
		queryMap.put(new Integer(GauceDataRow.TB_JOB_INSERT),
				"createGauceQueryService");

		// JOB의 유형별로 사용할 query id를 정의한 Map과 DB에 반영해야 할
		// GauceDataSet을 전달. GauceDataSet에는 다수의 데이터를 저장할 수 있음.
		int resultInsert = gauceQueryService.update(queryMap,
				makeInsertGauceDataSet());
		if (resultInsert != 3)
			throw new Exception("GauceDataSet Insert failed");
	}

	/**
	 * Gauce용 Query 서비스를 통해 DB에 입력된 데이터를 수정하는 테스트 코드
	 */
	public void testUpdateGauceDataSet() throws Exception {
		IGauceQueryService gauceQueryService = (IGauceQueryService) context
				.getBean("gauceQueryService");
		Map queryMap = new HashMap();
		queryMap.put(new Integer(GauceDataRow.TB_JOB_UPDATE),
				"updateGauceQueryService");

		// JOB의 유형별로 사용할 query id를 정의한 Map과 DB에 반영해야 할
		// GauceDataSet을 전달. GauceDataSet에는 다수의 데이터를 저장할 수 있음.
		int resultUpdate = gauceQueryService.update(queryMap,
				makeUpdateGauceDataSet());
		if (resultUpdate != 1)
			throw new Exception("GauceDataSet Update failed");
	}

	/**
	 * Gauce용 Query 서비스를 통해 DB에 데이터를 입력/수정/삭제하는 테스트 코드
	 */
	public void testProcessAllGauceDataSet() throws Exception {
		IGauceQueryService gauceQueryService = (IGauceQueryService) context
				.getBean("gauceQueryService");
		Map queryMap = new HashMap();
		queryMap.put(new Integer(GauceDataRow.TB_JOB_UPDATE),
				"updateGauceQueryService");
		queryMap.put(new Integer(GauceDataRow.TB_JOB_INSERT),
				"createGauceQueryService");
		queryMap.put(new Integer(GauceDataRow.TB_JOB_DELETE),
				"deleteGauceQueryService");

		// JOB의 유형별로 사용할 query id를 정의한 Map과 DB에 반영해야 할
		// GauceDataSet을 전달. GauceDataSet에는 다수의 데이터를 저장할 수 있음.
		int resultUpdate = gauceQueryService.update(queryMap,
				makeAllGauceDataSet());
		if (resultUpdate != 2)
			throw new Exception("GauceDataSet ProcessAll failed");
	}

	/**
	 * Gauce용 Query 서비스를 통해 DB에 입력된 데이터를 조회하는 테스트 코드
	 */
	public void testFindGauceDataSet() throws Exception {
		IGauceQueryService gauceQueryService = (IGauceQueryService) context
				.getBean("gauceQueryService");

		// 실행할 query id와 GauceDataSet 형태의 검색 조건을 전달
		GauceDataSet resultDataSet = gauceQueryService.search(
				"findGauceQueryService", makeFindGauceDataSet());
		if (resultDataSet.getDataRowCnt() != 1)
			throw new Exception("GauceDataSet find failed");

		if (!"애니프레임자바 테스트".equals(resultDataSet.getDataRow(0).getColumnValue(
				resultDataSet.indexOfColumn("testvarchar"))))
			throw new Exception("GauceDataSet find failed");
	}

	/**
	 * Gauce용 Query 서비스를 통해 DB에 입력된 데이터를 조회하는 테스트 코드 이때, ActionCommand를 통해 전후처리
	 * 수행
	 */
	public void testFindGauceDataSetWithActionCommand() throws Exception {
		IGauceQueryService gauceQueryService = (IGauceQueryService) context
				.getBean("gauceQueryService");
		Map queryMap = new HashMap();
		queryMap.put(new Integer(GauceDataRow.TB_JOB_UPDATE),
				"updateGauceQueryService");
		queryMap.put(new Integer(GauceDataRow.TB_JOB_INSERT),
				"createGauceQueryService");
		queryMap.put(new Integer(GauceDataRow.TB_JOB_DELETE),
				"deleteGauceQueryService");

		// JOB의 유형별로 사용할 query id를 정의한 Map과 DB에 반영해야 할
		// GauceDataSet, DB에 접근하기 전과 후에 처리해야 할 작업을 정의한 ActionCommand를 전달
		// Dataset에는 다수의 데이터를 저장할 수 있음.
		int resultUpdate = gauceQueryService.update(queryMap,
				makeAllGauceDataSet(), new TestGauceActionCommand(
						"command_test"));
		if (resultUpdate != 3)
			throw new Exception("GauceDataSet find with ActionCommand failed");
	}

	private GauceDataSet makeDataSetHeader() {
		GauceDataSet dataSet = new GauceDataSet("Anyframe_DS");
		dataSet.addDataColumn(new GauceDataColumn("testchar",
				GauceDataColumn.TB_STRING));
		dataSet.addDataColumn(new GauceDataColumn("testvarchar",
				GauceDataColumn.TB_STRING));
		dataSet.addDataColumn(new GauceDataColumn("testint",
				GauceDataColumn.TB_INT));
		dataSet.addDataColumn(new GauceDataColumn("testnumber",
				GauceDataColumn.TB_DECIMAL));
		dataSet.addDataColumn(new GauceDataColumn("testbignumber",
				GauceDataColumn.TB_DECIMAL));
		dataSet.addDataColumn(new GauceDataColumn("testdate",
				GauceDataColumn.TB_STRING));

		return dataSet;
	}

	private GauceDataSet makeDataSet() {
		return makeDataSet(GauceDataRow.TB_JOB_NORMAL, "1");
	}

	private GauceDataSet makeDataSet(int jobType, String key) {
		GauceDataSet dataSet = makeDataSetHeader();
		makeRow(dataSet, jobType, key);

		return dataSet;
	}

	private GauceDataSet makeDataSet(int jobType, int rowNum) {
		GauceDataSet dataSet = makeDataSetHeader();
		for (int i = 1; i <= rowNum; i++) {
			makeRow(dataSet, jobType, Integer.toString(rowNum));
		}

		return dataSet;
	}

	private void makeRow(GauceDataSet ds, int jobType, String key) {
		GauceDataRow row = new GauceDataRow(jobType, 6);
		row.addColumnValue(key);
		row.addColumnValue("Anyframe Test " + key);
		row.addColumnValue(12345);
		row.addColumnValue(9999999.99);
		row.addColumnValue(new BigDecimal("98765432109876543210"));
		row.addColumnValue(getDate().toString().split("\\.")[0]);
		ds.addDataRow(row);
	}

	private Timestamp getDate() {
		return DateUtil.string2Timestamp("2008-12-01", "yyyy-MM-dd");
	}

	private GauceDataSet makeInsertGauceDataSet() {
		return makeDataSet(GauceDataRow.TB_JOB_INSERT, 3);
	}

	private GauceDataSet makeUpdateGauceDataSet() {
		GauceDataSet dataSet = makeDataSet(GauceDataRow.TB_JOB_UPDATE, "A");
		dataSet.getDataRow(0).setString(dataSet.indexOfColumn("testvarchar"),
				"Anyframe UPDATE");
		dataSet.getDataRow(0).setInt(dataSet.indexOfColumn("testint"), 67890);
		dataSet.getDataRow(0).setDouble(dataSet.indexOfColumn("testnumber"),
				8888888.88);
		dataSet.getDataRow(0).setString(dataSet.indexOfColumn("testbignumber"),
				"12345678901234567890");

		return dataSet;
	}

	private GauceDataSet makeAllGauceDataSet() {
		GauceDataSet dataSet = makeDataSet(GauceDataRow.TB_JOB_INSERT, 1);
		makeRow(dataSet, GauceDataRow.TB_JOB_UPDATE, "A");
		makeRow(dataSet, GauceDataRow.TB_JOB_DELETE, "B");

		dataSet.getDataRow(1).setString(dataSet.indexOfColumn("testvarchar"),
				"Anyframe UPDATE");
		dataSet.getDataRow(1).setInt(dataSet.indexOfColumn("testint"), 67890);
		dataSet.getDataRow(1).setDouble(dataSet.indexOfColumn("testnumber"),
				8888888.88);
		dataSet.getDataRow(1).setString(dataSet.indexOfColumn("testbignumber"),
				"12345678901234567890");

		return dataSet;
	}

	private GauceDataSet makeFindGauceDataSet() {
		GauceDataSet dataSet = makeDataSet(GauceDataRow.TB_JOB_NORMAL, "B");
		return dataSet;
	}

	public class TestGauceActionCommand extends GauceActionCommand {

		private String userParam;

		public TestGauceActionCommand(String userParam) {
			super();
			this.userParam = userParam;
		}

		public void postDelete(GauceDataSet ds, int currentRow) {
			System.out
					.println("== TestGauceActionCommand.postDelete executed ==");
		}

		public void postInsert(GauceDataSet ds, int currentRow) {
			System.out
					.println("== TestGauceActionCommand.postInsert executed ==");
		}

		public void postUpdate(GauceDataSet ds, int currentRow) {
			System.out
					.println("== TestGauceActionCommand.postUpdate executed ==");
		}

		public void preDelete(GauceDataSet ds, int currentRow) {
			System.out
					.println("== TestGauceActionCommand.preDelete executed ==");
		}

		public void preInsert(GauceDataSet ds, int currentRow) {
			ds.getDataRow(currentRow).setString(
					ds.indexOfColumn("testvarchar"),
					userParam
							+ ds.getDataRow(currentRow).getString(
									ds.indexOfColumn("testvarchar")));
			System.out
					.println("== TestGauceActionCommand.preInsert executed ==");
		}

		public void preUpdate(GauceDataSet ds, int currentRow) {
			ds.getDataRow(currentRow).setString(
					ds.indexOfColumn("testvarchar"),
					userParam
							+ ds.getDataRow(currentRow).getString(
									ds.indexOfColumn("testvarchar")));
			System.out
					.println("== TestGauceActionCommand.preUpdate executed ==");
		}
	}

	protected String[] getConfigLocations() {
		return new String[] {
				"classpath*:/common/applicationContext-*.xml",
				"classpath*:/services/datasource/applicationContext-datasource-oracle.xml",
				"classpath*:/services/query/applicationContext-query-gauce.xml",
				"classpath*:/services/query/applicationContext-query-sqlloader.xml" };
	}
}

