/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (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.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * 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 com.queplix.core.modules.services.utils.db;

import com.queplix.core.error.GenericSystemException;
import com.queplix.core.modules.services.jxb.Task;
import com.queplix.core.modules.services.jxb.types.DelayunitSType;
import com.queplix.core.modules.services.jxb.types.StatusSType;
import com.queplix.core.modules.services.utils.TaskDAO;
import com.queplix.core.utils.dao.AbstractDAO;
import com.queplix.core.utils.sql.SqlWrapper;
import com.queplix.core.utils.sql.SqlWrapperFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;

/**
 * Project-specific implementation of the TaskDAO
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:31:01 $
 */

public class TaskDAOImpl
        extends AbstractDAO implements TaskDAO {

    // ===================================================== Fields

    /**
     * SQL wrapper implementation reference.
     */
    protected SqlWrapper sqlWrapper = SqlWrapperFactory.getSqlWrapper();

    // ===================================================== Overridden methods

    /*
     * (non-javadoc)
     *
     * @see TaskDAO#deleteTaskVO
     */

    public int deleteTaskVO(Task task) {
        Connection con = null;
        PreparedStatement ps = null;

        try {
            con = sqlWrapper.doConnection();
            ps = sqlWrapper.doPreparedStatement(con, DBRealmManager.getSql(
                    "delete_task"));
            ps.setLong(1, task.getId().longValue());

            return sqlWrapper.executeUpdate(ps);

        } catch (SQLException ex) {
            throw new GenericSystemException(
                    "SQL exception: " + ex.getMessage(), ex);

        } finally {
            sqlWrapper.closeConnection(con, ps);
        }
    }

    /*
     * (non-javadoc)
     *
     * @see TaskDAO#updateTaskVO
     */
    public int updateTaskVO(Task task) {
        Connection con = null;
        PreparedStatement ps = null;

        try {
            con = sqlWrapper.doConnection();
            ps = sqlWrapper.doPreparedStatement(con, DBRealmManager.getSql(
                    "update_task"));

            // Store status and 'next start'.
            int i = 1;
            ps.setInt(i++, task.getStatus().getType());
            if(task.getNextStart() != null) {
                sqlWrapper.getTimestampParser().setObject(ps, i++, new Date(
                        task.getNextStart().longValue()));
            } else {
                ps.setNull(i++, Types.TIMESTAMP);
            }
            ps.setLong(i++, task.getId().longValue());

            return sqlWrapper.executeUpdate(ps);

        } catch (SQLException ex) {
            throw new GenericSystemException(
                    "SQL exception: " + ex.getMessage(), ex);

        } finally {
            sqlWrapper.closeConnection(con, ps);
        }
    }

    /*
     * (non-javadoc)
     *
     * @see TaskDAO#loadTaskVO
     */
    public Task loadTaskVO(long taskId) {

        if(getLogger().isDebugEnabled()) {
            DEBUG("Try to get data for " + taskId + " task");
        }

        Task task = null;
        Connection con = null;
        PreparedStatement ps = null;

        try {
            // Open connection.
            con = sqlWrapper.doConnection();

            // Execute main SQL query.
            String sql = DBRealmManager.getSql("select_task");
            ps = sqlWrapper.doPreparedStatement(con, sql);
            ps.setLong(1, taskId);

            // Read main data.
            ResultSet rs = sqlWrapper.executeQuery(ps);
            if(!rs.next()) {
                return null;
            }
            task = createTask(rs);
            rs.close();
            ps.close();

        } catch (SQLException ex) {
            throw new GenericSystemException(
                    "SQL exception: " + ex.getMessage(), ex);

        } finally {
            sqlWrapper.closeConnection(con, ps);
        }

        if(getLogger().isDebugEnabled()) {
            DEBUG("Got task VO for " + taskId + " : " + task);
        }

        return task;
    }

    /*
     * (non-javadoc)
     *
     * @see TaskDAO#loadTaskVO
     */
    public Task loadTaskVO(String taskName) {
        /** @todo [ALB] implement it */
        throw new UnsupportedOperationException();
    }

    /*
     * (non-javadoc)
     *
     * @see TaskDAO#loadAllTaskVO
     */
    public Collection loadAllTaskVO() {

        Connection con = null;
        PreparedStatement ps = null;

        Collection taskList = new ArrayList();

        try {
            con = sqlWrapper.doConnection();
            ps = sqlWrapper.doPreparedStatement(con, DBRealmManager.getSql(
                    "select_all_task"));
            ResultSet rs = sqlWrapper.executeQuery(ps);
            while(rs.next()) {
                Task task = createTask(rs);
                taskList.add(task);
            }

        } catch (SQLException ex) {
            throw new GenericSystemException(
                    "SQL exception: " + ex.getMessage(), ex);

        } finally {
            sqlWrapper.closeConnection(con, ps);
        }

        return taskList;
    }

    // ===================================================== Protected methods

    //
    // Creates Task from ResultSet
    // [ALB] without task parameters
    //

    protected Task createTask(ResultSet rs)
            throws SQLException {

        // Read mandatory data.
        int i = 1;
        long taskID = rs.getLong(i++);
        int scriptID = rs.getInt(i++);
        String name = rs.getString(i++);
        int taskStatus = rs.getInt(i++);
        Integer delay = sqlWrapper.getIntParser().getValue(rs, i++);
        Integer delayUnit = sqlWrapper.getIntParser().getValue(rs, i++);
        Integer repeat = sqlWrapper.getIntParser().getValue(rs, i++);
        Integer autoStart = sqlWrapper.getIntParser().getValue(rs, i++);
        Date firstStart = sqlWrapper.getTimestampParser().getValue(rs, i++);
        Date nextStart = sqlWrapper.getTimestampParser().getValue(rs, i++);

        // create Task object
        Task task = new Task();
        task.setId(new Long(taskID));
        task.setScriptId(new Integer(scriptID));
        task.setName(name);

        if(delay != null) {
            task.setDelay(delay);
        }
        if(repeat != null) {
            task.setRepeat(new Boolean(repeat.intValue() == 1));
        } else {
            task.setRepeat(Boolean.FALSE);
        }
        if(autoStart != null) {
            task.setAutoStart(new Boolean(autoStart.intValue() == 1));
        } else {
            task.setAutoStart(Boolean.FALSE);
        }
        if(firstStart != null) {
            task.setFirstStart(new Long(firstStart.getTime()));
        }
        if(nextStart != null) {
            task.setNextStart(new Long(nextStart.getTime()));
        }

        // set Task status
        switch(taskStatus) {
            case StatusSType.NEW_TYPE:
                task.setStatus(StatusSType.NEW);
                break;
            case StatusSType.READY_TYPE:
                task.setStatus(StatusSType.READY);
                break;
            case StatusSType.RUN_TYPE:
                task.setStatus(StatusSType.RUN);
                break;
            case StatusSType.WAITED_TYPE:
                task.setStatus(StatusSType.WAITED);
                break;
            case StatusSType.COMPLETED_TYPE:
                task.setStatus(StatusSType.COMPLETED);
                break;
            case StatusSType.INTERRUPTED_TYPE:
                task.setStatus(StatusSType.INTERRUPTED);
                break;
            default:
                throw new IllegalStateException(
                        "Unsupported task status: " + taskStatus);
        }

        // set Task delay units
        if(delayUnit != null) {
            switch(delayUnit.intValue()) {
                case DelayunitSType.MIN_TYPE:
                    task.setDelayunit(DelayunitSType.MIN);
                    break;
                case DelayunitSType.HOUR_TYPE:
                    task.setDelayunit(DelayunitSType.HOUR);
                    break;
                case DelayunitSType.DAY_TYPE:
                    task.setDelayunit(DelayunitSType.DAY);
                    break;
                case DelayunitSType.MONTH_TYPE:
                    task.setDelayunit(DelayunitSType.MONTH);
                    break;
                default:
                    throw new IllegalStateException(
                            "Unsupported task delayunit type: " + delayUnit);
            }
        }

        // get list of task parameters
        /* We don't use parameters yet 
        PreparedStatement ps = null;

        try {
            ps = sqlWrapper.doPreparedStatement( rs.getStatement().getConnection(), DBRealmManager.getSql( "select_task_parameters" ) );
            ps.setLong( 1, taskID );
            ResultSet rs2 = sqlWrapper.executeQuery( ps );
            while( rs2.next() ) {
                i = 1;
                String paramName = rs2.getString( i++ );
                String paramValue = rs2.getString( i++ );
                Integer paramRequired = sqlWrapper.getIntParser().getValue( rs2, i++ );
                Integer paramType = sqlWrapper.getIntParser().getValue( rs2, i++ );

                Param param = new Param();
                param.setName( paramName );
                param.setValue( paramValue );
                if( paramRequired != null ) {
                    param.setRequired( new Boolean( paramRequired.intValue() == 1 ) );
                } else {
                    param.setRequired( Boolean.FALSE );
                }

                // set param type
                if( paramType != null ) {
                    int param_type = paramType.intValue();
                    switch( param_type ) {
                        case ParamTypeSType.INT_TYPE:
                            param.setType( ParamTypeSType.INT );
                            break;
                        case ParamTypeSType.LONG_TYPE:
                            param.setType( ParamTypeSType.LONG );
                            break;
                        case ParamTypeSType.FLOAT_TYPE:
                            param.setType( ParamTypeSType.FLOAT );
                            break;
                        case ParamTypeSType.STRING_TYPE:
                            param.setType( ParamTypeSType.STRING );
                            break;
                        default:
                            throw new IllegalStateException( "Unsupported task param type: " + param_type );
                    }
                }

                // add Param object into Task object
                task.addParam( param );
            }

        } catch( SQLException ex ) {
            ERROR( ex );
            throw new GenericSystemException( "SQL exception: " + ex.getMessage(), ex );

        } finally {
            sqlWrapper.closeConnection( ps );
        }
*/
        return task;
    }
}
