/*
 * Copyright 2006-2011 the Seasar Foundation and the Others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.seasar.codegen.lib.internal.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.seasar.codegen.sample.condition.EmpTableCondition;
import org.seasar.codegen.sample.condition.EmpTableRelationCondition;
import org.seasar.codegen.sample.dao.EmpTableDao;
import org.seasar.codegen.sample.entity.EmpTable;
import org.seasar.codegen.sample.entity.EmpTableRelation;
import org.seasar.dao.ResultSetHandlerFactory;
import org.seasar.dao.pager.PagerContext;
import org.seasar.dao.pager.PagingSqlRewriter;
import org.seasar.dao.unit.S2DaoTestCase;
import org.seasar.extension.jdbc.ResultSetFactory;
import org.seasar.extension.jdbc.ResultSetHandler;
import org.seasar.extension.jdbc.StatementFactory;
import org.seasar.framework.beans.factory.BeanDescFactory;

/**
 * @author azusa
 * 
 */
public class FindSqlCommandTest extends S2DaoTestCase {

    private FindSqlCommand findSqlCommand;

    private static final String BASE_SQL = "SELECT EMP_TABLE.EMP_NO, EMP_TABLE.ENAME, EMP_TABLE.JOB, EMP_TABLE.MGR, EMP_TABLE.HIRE_DATE, EMP_TABLE.SAL, EMP_TABLE.COMM, EMP_TABLE.DEPT_NO, EMP_TABLE.TSTAMP, EMP_TABLE.VERSIONNO FROM EMP_TABLE";

    private StatementFactory statementFactory;

    private ResultSetHandlerFactory resultSetHandlerFactory;

    private ResultSetFactory resultSetFactory;

    private PagingSqlRewriter pagingSqlRewriter;

    /*
     * (非 Javadoc)
     * 
     * @see junit.framework.TestCase#setUp()
     */
    protected void setUp() throws Exception {
        // pass nullパターン
        findSqlCommand = new FindSqlCommand(null, null, null, null, null, BASE_SQL);
        include("dao.dicon");
    }

    /**
     * {@link org.seasar.codegen.lib.internal.impl.CodeGenDaoMetaDataFactoryImpl.FindSqlCommand#execute(java.lang.Object[])}
     * のためのテスト・メソッド。
     * 
     * @throws Exception
     * @throws SecurityException
     */
    public void testExecuteObjectArray() throws Exception {
        ResultSetHandler resultSetHandler = resultSetHandlerFactory.getResultSetHandler(getAnnotationReaderFactory()
                .createDaoAnnotationReader(BeanDescFactory.getBeanDesc(EmpTableDao.class)), getBeanMetaDataFactory()
                .createBeanMetaData(EmpTable.class), EmpTableDao.class.getMethod("find", EmpTableCondition.class));
        createResultSetHandler(resultSetHandler);

        EmpTableCondition empCondition = new EmpTableCondition();
        empCondition.selectEmpNo().equal(100);
        Object[] args = new Object[] { empCondition };
        PagerContext.start();
        PagerContext.getContext().pushArgs(args);
        try {
            Object result = findSqlCommand.execute(args);
            assertNotNull(result);
        } finally {
            PagerContext.end();
        }

    }

    /**
     * 引数がない場合
     * 
     * @throws Exception
     */
    public void testExecuteVoid() throws Exception {
        ResultSetHandler resultSetHandler = resultSetHandlerFactory.getResultSetHandler(getAnnotationReaderFactory()
                .createDaoAnnotationReader(BeanDescFactory.getBeanDesc(EmpTableDao.class)), getBeanMetaDataFactory()
                .createBeanMetaData(EmpTableRelation.class), EmpTableDao.class.getMethod("getAllEmpTableWithRelation",
                null));
        createResultSetHandler(resultSetHandler);
        Object[] args = new Object[0];
        PagerContext.start();
        PagerContext.getContext().pushArgs(args);
        try {
            Object result = findSqlCommand.execute(args);
            assertNotNull(result);
        } finally {
            PagerContext.end();
        }

    }

    private void createResultSetHandler(ResultSetHandler resultSetHandler) {
        findSqlCommand = new FindSqlCommand(getDataSource(), statementFactory, resultSetHandler, resultSetFactory,
                pagingSqlRewriter, BASE_SQL);
    }

    /**
     * {@link org.seasar.codegen.lib.internal.impl.CodeGenDaoMetaDataFactoryImpl.FindSqlCommand#createSql(java.lang.Object[], org.seasar.dao.BeanMetaData, org.seasar.codegen.lib.ConditionResult, org.seasar.framework.beans.BeanDesc)}
     * のためのテスト・メソッド。
     */
    public void testCreateSql_aliasなし() {
        EmpTableCondition empCondition = new EmpTableCondition();
        empCondition.selectEmpNo().equal(100);
        empCondition.selectSal().not(new BigDecimal(200000));
        empCondition.selectEname().isNull();
        empCondition.selectHireDate().isNotNull();
        // TODO lessthan,less,morethan,more

        StringBuilder result = findSqlCommand.createSql(empCondition.getConditionResult());

        assertEquals(
                " WHERE EMP_TABLE.EMP_NO =? AND EMP_TABLE.SAL <>? AND EMP_TABLE.ENAME IS NULL AND EMP_TABLE.HIRE_DATE IS NOT NULL",
                result.toString());

    }

    /**
     * {@link org.seasar.codegen.lib.internal.impl.CodeGenDaoMetaDataFactoryImpl.FindSqlCommand#createSql(java.lang.Object[], org.seasar.dao.BeanMetaData, org.seasar.codegen.lib.ConditionResult, org.seasar.framework.beans.BeanDesc)}
     * のためのテスト・メソッド。
     */
    public void testCreateSql_QUERY() {
        EmpTableCondition empCondition = new EmpTableCondition();
        empCondition.selectEmpNo().equal(100);
        empCondition.selectSal().not(new BigDecimal(200000));
        empCondition.addQuery("ENAME = ?", "aaa");
        // TODO lessthan,less,morethan,more

        StringBuilder result = findSqlCommand.createSql(empCondition.getConditionResult());
        System.out.println(result);
        assertEquals(" WHERE EMP_TABLE.EMP_NO =? AND EMP_TABLE.SAL <>? AND ENAME = ?", result.toString());

    }

    public void testCreateSql_INとNOTINで引数が可変長の場合() {
        EmpTableCondition empCondition = new EmpTableCondition();
        empCondition.selectEmpNo().in(100, 200);
        empCondition.selectSal().notIn(new BigDecimal(300), new BigDecimal(400));

        StringBuilder result = findSqlCommand.createSql(empCondition.getConditionResult());

        assertEquals(" WHERE EMP_TABLE.EMP_NO IN(?,?) AND EMP_TABLE.SAL not in(?,?)", result.toString());
    }

    public void testCreateSql_INとNOTINで引数がListの場合() {
        EmpTableCondition empCondition = new EmpTableCondition();
        {
            List<Integer> list = new ArrayList<Integer>();
            list.add(300);
            list.add(400);
            empCondition.selectEmpNo().in(list);
        }
        {
            List<BigDecimal> list = new ArrayList<BigDecimal>();
            list.add(new BigDecimal(500F));
            list.add(new BigDecimal(600F));
            empCondition.selectSal().notIn(list);

        }

        String result = findSqlCommand.createSql(empCondition.getConditionResult()).toString();

        assertEquals(" WHERE EMP_TABLE.EMP_NO IN(?,?) AND EMP_TABLE.SAL not in(?,?)", result);
    }

    public void testCreateSql_aliasあり() {

        findSqlCommand = new FindSqlCommand(null, null, null, null, null, getDbms().getAutoSelectSql(
                getBeanMetaDataFactory().createBeanMetaData(EmpTableRelation.class)));

        EmpTableRelationCondition empRelationCondition = new EmpTableRelationCondition();
        // empRelationCondition.selectDeptTableDtoDeptId().equal(100);
        //
        empRelationCondition.selectDeptTableRelation().selectDeptId().equal(100);
        empRelationCondition.selectEmpNo().equal(200);
        String result = findSqlCommand.createSql(empRelationCondition.getConditionResult()).toString();
        assertEquals(" WHERE deptTableEntity.DEPT_ID =? AND EMP_TABLE.EMP_NO =?", result);
    }

    public void testCreateSql_Orderあり() {
        EmpTableCondition empCondition = new EmpTableCondition();
        empCondition.selectEmpNo().addOrderAsc();
        empCondition.selectEmpNo().addOrderDesc();

        String result = findSqlCommand.createSql(empCondition.getConditionResult()).toString();

        assertEquals("  ORDER BY EMP_TABLE.EMP_NO,EMP_TABLE.EMP_NO DESC ", result);

    }

    /**
     * {@link org.seasar.codegen.lib.internal.impl.CodeGenDaoMetaDataFactoryImpl.FindSqlCommand#createVariables(org.seasar.framework.beans.BeanDesc, org.seasar.codegen.lib.ConditionResult)}
     * のためのテスト・メソッド。
     */
    public void testCreateVariables() {
        EmpTableCondition empCondition = new EmpTableCondition();
        empCondition.selectEmpNo().equal(100);
        empCondition.selectDeptNo().moreThan(900);
        Object[] result = findSqlCommand.createVariables(empCondition.getConditionResult());
        assertEquals(2, result.length);
        assertEquals(100, result[0]);
        assertEquals(900, result[1]);
    }

    public void testCreateVariables_INの場合() {
        EmpTableCondition empCondition = new EmpTableCondition();
        empCondition.selectEmpNo().in(300, 400);
        empCondition.selectDeptNo().moreThan(1000);
        Object[] result = findSqlCommand.createVariables(empCondition.getConditionResult());
        assertEquals(3, result.length);
        assertEquals(300, result[0]);
        assertEquals(400, result[1]);
        assertEquals(1000, result[2]);

    }

    public void testCreateVariables_QUERYつきの場合() {
        EmpTableCondition empCondition = new EmpTableCondition();
        empCondition.selectEmpNo().in(300, 400);
        empCondition.addQuery("ENAME in( ?, ?)", "azusa", "oonaka");
        Object[] result = findSqlCommand.createVariables(empCondition.getConditionResult());
        assertEquals(4, result.length);
        assertEquals(300, result[0]);
        assertEquals(400, result[1]);
        assertEquals("azusa", result[2]);
        assertEquals("oonaka", result[3]);

    }

    /**
     * {@link org.seasar.codegen.lib.internal.impl.CodeGenDaoMetaDataFactoryImpl.FindSqlCommand#createVariablesTypes(java.lang.Object[])}
     * のためのテスト・メソッド。
     */
    public void testCreateVariablesTypes() {
        // むーん
        EmpTableCondition empCondition = new EmpTableCondition();
        empCondition.selectEmpNo().in(300, 400);
        empCondition.selectEname().equal("azusa");
        Object[] objects = findSqlCommand.createVariables(empCondition.getConditionResult());
        Class<?>[] result = findSqlCommand.createVariablesTypes(objects);
        assertEquals(3, result.length);
        assertEquals(Integer.class, result[0]);
        assertEquals(Integer.class, result[1]);
        assertEquals(String.class, result[2]);

    }

}
