/**
 *   Copyright 2007 Y.Murakamin
 *
 *  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 net.murakamin.sticker.commands;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

import net.murakamin.sticker.CommandRunner;
import net.murakamin.sticker.Commands;
import net.murakamin.sticker.ConnectionPool;
import net.murakamin.sticker.StickerContext;
import net.murakamin.sticker.commands.enums.PostChildCommandExecutionType;
import net.murakamin.sticker.commands.enums.PreChildCommandExecutionType;
import net.murakamin.sticker.commands.enums.TargetType;
import net.murakamin.sticker.commands.exception.CommandExecutionException;

import org.apache.commons.lang.SystemUtils;

/**
 * When the cursor is opened, and the value specified by the value and the
 * attribute named value is the same referring to the value of the first field
 * on the first record, the child element is executed.
 * 
 * @author Y.Murakamin
 * @see net.murakamin.sticker.commands.CursorCommand
 * @see net.murakamin.sticker.commands.IfCommand
 * @see net.murakamin.sticker.commands.ExportCommand
 * @see net.murakamin.sticker.commands.ImportCommand
 * @see net.murakamin.sticker.commands.InfoCommand
 * @see net.murakamin.sticker.commands.QueryImportCommand
 * @see net.murakamin.sticker.commands.Shell
 * @see net.murakamin.sticker.commands.SqlCommand
 * @see net.murakamin.sticker.commands.ParentCommand
 * @see net.murakamin.sticker.commands.ForCommand
 * @see net.murakamin.sticker.commands.enums.TargetType
 * 
 */
public class IfCommand implements ParentCommand
{

	Commands childlen = new Commands();
	private TargetType target = TargetType.remote;
	private String name;
	private String value;

	private boolean childExecute = false;

	/**
	 * @see net.murakamin.sticker.commands.ParentCommand#addChild(ExecutableCommand)
	 */
	public void addChild(final ExecutableCommand child)
	{
		this.childlen.add(child);
	}

	/**
	 * The cursor is opened, and the value of the first field on the first
	 * record is reference. When the value specified by the value and the
	 * attribute named value is the same, the child element is executed.
	 * 
	 * @see net.murakamin.sticker.commands.ExecutableCommand#execute(CommandRunner)
	 */
	public void execute(final CommandRunner runner) throws Exception
	{
		ConnectionPool pool = runner.getConnectionPool();
		StickerContext context = runner.getStickerContext();

		this.childExecute = false;
		Connection con = pool.getLocalConnection();

		CursorCommand cursor = (CursorCommand) context
		        .get(CursorCommand.CURSOR_NAME_PREFIX + this.getName());
		if (cursor == null)
		{
			throw new CommandExecutionException(
			        Messages
			                .getString("net.murakamin.sticker.commands.CursorCommand.Corsor_not_found") //$NON-NLS-1$
			                + this.getName());
		}

		if (this.target == TargetType.remote)
		{
			con = pool.getRemoteConnection();
		}

		Statement stmt = null;
		ResultSet rs = null;

		try
		{
			try
			{
				stmt = con.createStatement();
				rs = stmt.executeQuery(cursor.getSql());

			} catch (SQLException se)
			{
				throw new CommandExecutionException(
				        this,
				        Messages
				                .getString("net.murakamin.sticker.commands.CursorCommand.Cursor_open_failure") //$NON-NLS-1$
				                + this.getName(), se);
			}

			ResultSetMetaData meta = rs.getMetaData();
			while (rs.next())
			{
				if (meta.getColumnCount() > 0)
				{
					// first column exists
					if (this.getValue().equals(rs.getObject(1).toString()))
					{
						this.childExecute = true;
						runner.run(this);
					}
				}

				break;
			}

		} finally
		{
			if (stmt != null)
			{
				stmt.close();
			}
			if (rs != null)
			{
				rs.close();
			}
			rs = null;
		}
	}

	/**
	 * @see net.murakamin.sticker.commands.ParentCommand#getChildlen()
	 */
	public Commands getChildlen()
	{
		return this.childlen;
	}

	/**
	 * get the cursor name
	 * 
	 * @return cursor name
	 */
	public String getName()
	{
		return name;
	}

	/**
	 * The kind of the data base is acquired the data acquisition of the
	 * {@link net.murakamin.sticker.commands.CursorCommand &lt;cursor&gt;}
	 * command ahead.
	 * 
	 * @return the source of data acquisition
	 */
	public String getTarget()
	{
		return target.name();
	}

	/**
	 * Get the comparison value
	 * 
	 * @return the comparison value
	 */
	public String getValue()
	{
		return value;
	}

	/**
	 * @see net.murakamin.sticker.commands.ExecutableCommand#getVersionTerm()
	 */
	public VersionTerm getVersionTerm()
	{
		return new VersionTerm("0.1.3");
	}

	/**
	 * @see net.murakamin.sticker.commands.ExecutableCommand#isDebugPrint()
	 */
	public boolean isDebugPrint()
	{
		return false;
	}

	/**
	 * @return always PostChildCommandExecutionType.NOT_REPEAT
	 * @see net.murakamin.sticker.commands.ParentCommand#postChildCommandExecute(CommandRunner)
	 * @see net.murakamin.sticker.commands.enums.PostChildCommandExecutionType
	 */
	public PostChildCommandExecutionType postChildCommandExecute(
	        final CommandRunner runner) throws Exception
	{
		return PostChildCommandExecutionType.NOT_REPEAT;
	}

	/**
	 * @return PreChildCommandExecutionType.CHILD_EXECUTE when child element is
	 *         executed
	 * @see net.murakamin.sticker.commands.ParentCommand#preChildCommandExecute(CommandRunner)
	 * @see net.murakamin.sticker.commands.enums.PreChildCommandExecutionType
	 */
	public PreChildCommandExecutionType preChildCommandExecute(
	        final CommandRunner runner) throws Exception
	{
		return this.childExecute ? PreChildCommandExecutionType.CHILD_EXECUTE
		        : PreChildCommandExecutionType.CHILD_NOT_EXECUTE;
	}

	/**
	 * Set the cursor name
	 * 
	 * @param name
	 *            the cursor name
	 */
	public void setName(final String name)
	{
		this.name = name;
	}

	/**
	 * set the target
	 * 
	 * @param target
	 *            the target name
	 */
	public void setTarget(final String target)
	{
		this.target = TargetType.valueOf(target);
	}

	/**
	 * Set the comparison value
	 * 
	 * @param value
	 *            the comparison value
	 */
	public void setValue(final String value)
	{
		this.value = value;
	}

	@Override
	public String toString()
	{
		StringBuffer buffer = new StringBuffer();

		buffer.append("<if> : child execute ... ");
		buffer.append(this.childExecute);
		buffer.append(SystemUtils.LINE_SEPARATOR);

		buffer.append(" cursor:");
		buffer.append(this.getName());
		buffer.append(SystemUtils.LINE_SEPARATOR);

		buffer.append(" target:");
		buffer.append(this.getTarget());
		buffer.append(SystemUtils.LINE_SEPARATOR);

		return buffer.toString();
	}

}
