package jp.sf.amateras.mirage.test;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;

import java.util.ArrayList;
import java.util.List;

import junit.framework.Assert;

/**
 *
 * @author Naoki Takezoe
 * @see MockSqlManager
 */
public class MirageTestContext {

	private static List<Object> resultList = new ArrayList<Object>();
	private static List<ExecutedSQLInfo> executedSqlList = new ArrayList<ExecutedSQLInfo>();

	/**
	 * Initializes the MirageTestContext.
	 * <p>
	 * This method clears the result list and the executed sql list.
	 * You have to invoke this method at <code>setUp()</code> of your test case.
	 */
	public static void initMirageTestContext(){
		resultList.clear();
		executedSqlList.clear();
	}

	public static void addResult(Object result){
		resultList.add(result);
	}

	static boolean hasNextResult(){
		return !resultList.isEmpty();
	}

	static Object getNextResult(){
		return resultList.remove(0);
	}

	static void addExecutedSql(ExecutedSQLInfo executedSql){
		System.out.println(String.format("[SQL] %s", normalizeSql(executedSql.getSql())));

		Object[] params = executedSql.getParams();
		for(int i=0; i < params.length; i++){
			System.out.println(String.format("[SQL] params[%d]: %s", i, params[i]));
		}

		executedSqlList.add(executedSql);
	}

	/**
	 * Verifies the number of executed SQLs.
	 *
	 * @param expected the expected number of executed SQLs
	 */
	public static void verifySqlCount(int expected){
		assertEquals(expected, executedSqlList.size());
	}

	/**
	 * Verifies the executed SQL.
	 *
	 * @param indexOfSql the index of executed SQL
	 * @param sql the expected SQL
	 */
	public static void verifySql(int indexOfSql, String sql){
		ExecutedSQLInfo executedSql = executedSqlList.get(indexOfSql);
		String result = executedSql.getSql();
		Assert.assertEquals(normalizeSql(sql), normalizeSql(result));
	}

	/**
	 * Verifies the executed SQL using the regular expression.
	 *
	 * @param indexOfSql the index of executed SQL
	 * @param pattern the pattern of expected SQL
	 */
	public static void verifySqlByRegexp(int indexOfSql, String regexp){
		ExecutedSQLInfo executedSql = executedSqlList.get(indexOfSql);
		String result = normalizeSql(executedSql.getSql());
		Assert.assertTrue(result.matches(regexp));
	}

	/**
	 * Verifies the number of parameters of <code>PreparedStatement</code>.
	 *
	 * @param indexOfSql the index of executed SQL
	 * @param expected the expected number of parameters
	 */
	public static void verifySqlParameterCount(int indexOfSql, int expected){
		ExecutedSQLInfo executedSql = executedSqlList.get(indexOfSql);
		assertEquals(expected, executedSql.getParams().length);
	}

	/**
	 * Verifies the parameter of <code>PreparedStatement</code>.
	 *
	 * @param indexOfSql the index of executed SQL
	 * @param indexOfParam the index of parameter
	 * @param value the expected value
	 */
	public static void verifySqlParameter(int indexOfSql, int indexOfParam, Object value){
		ExecutedSQLInfo executedSql = executedSqlList.get(indexOfSql);
		Object[] params = executedSql.getParams();
		if(value == null){
			assertNull(params[indexOfParam]);
		} else {
			assertEquals(value, params[indexOfParam]);
		}
	}

	private static String normalizeSql(String sql){
		sql = sql.replaceAll("\r\n", "\n");
		sql = sql.replaceAll("\r", "\n");
		sql = sql.replaceAll("\n", " ");
		sql = sql.replaceAll("[ \t]+", " ");
		sql = sql.toUpperCase();

		return sql;
	}

}
