/*
 * Copyright 2007 Andrew Wills
 *
 * 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.danann.cernunnos.sql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.dom4j.Node;

import org.danann.cernunnos.AttributePhrase;
import org.danann.cernunnos.EntityConfig;
import org.danann.cernunnos.Formula;
import org.danann.cernunnos.Phrase;
import org.danann.cernunnos.Reagent;
import org.danann.cernunnos.ReagentType;
import org.danann.cernunnos.SimpleFormula;
import org.danann.cernunnos.SimpleReagent;
import org.danann.cernunnos.Task;
import org.danann.cernunnos.TaskRequest;
import org.danann.cernunnos.TaskResponse;

public class StatementTask implements Task {

	// Instance Members.
	private Phrase connection;
	private Phrase sql;
	private List<Phrase> parameters;

	/*
	 * Public API.
	 */

	public static final Reagent CONNECTION = new SimpleReagent("CONNECTION", "@connection", ReagentType.PHRASE, Connection.class,
										"Optional name of a request attribute containing a dgatabase connection.  If omitted, "
										+ "the name 'SqlAttributes.CONNECTION' will be used.", 
										new AttributePhrase(SqlAttributes.CONNECTION));

	public static final Reagent SQL = new SimpleReagent("SQL", "@sql", ReagentType.PHRASE, String.class, 
										"The SQL statement that will be executed.");

	public static final Reagent PARAMETERS = new SimpleReagent("PARAMETERS", "parameter/@value", ReagentType.NODE_LIST, List.class, 
										"The parameters (if any) for the PreparedStatement that will execute the SQL.  "
										+ "WARNING:  Parameters must appear in the same order in both update and insert statements.", 
										Collections.emptyList());

	public Formula getFormula() {
		Reagent[] reagents = new Reagent[] {CONNECTION, SQL, PARAMETERS};
		final Formula rslt = new SimpleFormula(StatementTask.class, reagents);
		return rslt;
	}
	
	public void init(EntityConfig config) {

		this.connection = (Phrase) config.getValue(CONNECTION); 
		this.sql = (Phrase) config.getValue(SQL); 
		this.parameters = new LinkedList<Phrase>();
		List nodes = (List) config.getValue(PARAMETERS);		
		for (Iterator it = nodes.iterator(); it.hasNext();) {
			Node n = (Node) it.next();
			parameters.add(config.getGrammar().newPhrase(n.getText()));
		}
		
	}
	
	public void perform(TaskRequest req, TaskResponse res) {
		
		String fSql = (String) sql.evaluate(req, res);
		PreparedStatement pstmt = null;
		try {

			Connection conn = (Connection) connection.evaluate(req, res);

			pstmt = conn.prepareStatement(fSql);
			int i=0;
			for (Phrase p : parameters) {
				pstmt.setObject(++i, p.evaluate(req, res));
			}
			pstmt.execute();
			
		} catch (Throwable t) {
			String msg = "Unable to execute the specified sql:  " + fSql;
			throw new RuntimeException(msg, t);
		} finally {
			
			// Cleanup...
			if (pstmt != null) {
				try {
					pstmt.close();
				} catch (Throwable t) {
					String msg = "Unable to close the statement.";
					throw new RuntimeException(msg, t);
				}
			}
			
		}
		
	}

}
@@ -1644,51 +1644,9 @@
 nal 
-name of a request attribute containing a dg
+d
 atab
@@ -1659,16 +1659,23 @@
 nnection
+ object
 .  If om
@@ -1680,16 +1680,44 @@
 omitted,
+ the request attribute under
  %22%0D%0A%09%09%09%09
@@ -1776,17 +1776,16 @@
  used.%22,
- 
 %0D%0A%09%09%09%09%09%09
@@ -1936,25 +1936,24 @@
 tring.class,
- 
 %0D%0A%09%09%09%09%09%09%09%09%09%09
@@ -2128,17 +2128,16 @@
 t.class,
- 
 %0D%0A%09%09%09%09%09%09
@@ -2325,17 +2325,16 @@
 ments.%22,
- 
 %0D%0A%09%09%09%09%09%09
@@ -2557,25 +2557,24 @@
  rslt;%0D%0A%09%7D%0D%0A
-%09
 %0D%0A%09public vo
@@ -2664,17 +2664,16 @@
 ECTION);
- 
 %0D%0A%09%09this
@@ -2709,17 +2709,16 @@
 ue(SQL);
- 
 %0D%0A%09%09this
@@ -2808,18 +2808,16 @@
 METERS);
-%09%09
 %0D%0A%09%09for 
@@ -2971,17 +2971,14 @@
 %09%7D%0D%0A
-%09%09
 %0D%0A%09%7D%0D%0A
-%09
 %0D%0A%09p
@@ -3034,18 +3034,16 @@
 res) %7B%0D%0A
-%09%09
 %0D%0A%09%09Stri
@@ -3364,19 +3364,16 @@
 ute();%0D%0A
-%09%09%09
 %0D%0A%09%09%7D ca
@@ -3514,19 +3514,16 @@
 ally %7B%0D%0A
-%09%09%09
 %0D%0A%09%09%09// 
@@ -3732,20 +3732,15 @@
 %09%7D%0D%0A
-%09%09%09
 %0D%0A%09%09%7D%0D%0A
-%09%09
 %0D%0A%09%7D

Corrected Reagent description.