/*
 * The contents of this file are subject to the Mozilla Public License Version 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.mozilla.org/MPL/>.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
 * language governing rights and limitations under the License.
 * 
 * The Original Code is the Venice Web Communities System.
 * 
 * The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
 * for Silverwrist Design Studios.  Portions created by Eric J. Bowersox are
 * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.dynamo.module;

import java.io.*;
import java.sql.*;
import java.util.*;
import org.w3c.dom.*;
import com.silverwrist.util.*;
import com.silverwrist.util.xml.*;
import com.silverwrist.dynamo.except.*;
import com.silverwrist.dynamo.iface.*;

class InstallerImpl implements DatabaseInstaller
{
  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private DBConnectionPool m_pool;

  /*--------------------------------------------------------------------------------
   * Constructor
   *--------------------------------------------------------------------------------
   */

  InstallerImpl(DBConnectionPool pool)
  {
    m_pool = pool;

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Internal operations
   *--------------------------------------------------------------------------------
   */

  private static final List loadCommandList(InputStream stm, DynamoLog log) throws ModuleException
  {
    XMLLoader loader = XMLLoader.get();
    try
    { // load the script, parse it, and get the list of <command/> elements
      Document doc = loader.load(stm,false);
      Element elt = loader.getRootElement(doc,"database-info");
      return loader.getMatchingSubElements(elt,"command");

    } // end try
    catch (IOException e)
    { // translate to a ModuleException
      log.error("I/O error loading script",e);
      ModuleException me = new ModuleException(InstallerImpl.class,"ModuleMessages","dbInstall.scriptIO",e);
      me.setParameter(0,e.getMessage());
      throw me;

    } // end catch
    catch (XMLLoadException e)
    { // translate to a ModuleException
      log.error("XML error loading script",e);
      ModuleException me = new ModuleException(InstallerImpl.class,"ModuleMessages","dbInstall.parser",e);
      me.setParameter(0,e.getMessage());
      throw me;

    } // end catch

  } // end loadCommandList

  private static final List makeInstallList(List in_list) throws ModuleException
  {
    LinkedList rc = new LinkedList();
    Iterator it = in_list.iterator();
    while (it.hasNext())
    { // look through each command and find the <install/> sub-element
      Element elt = (Element)(it.next());
      DOMElementHelper h = new DOMElementHelper(elt);
      Element t = h.getSubElement("install");
      if (t!=null)
      { // get the install command
	String[] dat = new String[2];
	dat[0] = h.getSubElementText("install");
	if (dat[0]!=null)
	{ // store the command in the list
	  dat[0] = dat[0].trim();
	  if (t.hasAttribute("log"))
	    dat[1] = t.getAttribute("log");
	  else
	    dat[1] = null;
	  rc.addLast(dat);

	} // end if

      } // end if

    } // end while

    return rc;

  } // end makeInstallList

  private static final List makeUninstallList(List in_list) throws ModuleException
  {
    LinkedList rc = new LinkedList();
    Iterator it = in_list.iterator();
    while (it.hasNext())
    { // look through each command and find the <uninstall/> sub-element
      Element elt = (Element)(it.next());
      DOMElementHelper h = new DOMElementHelper(elt);
      Element t = h.getSubElement("uninstall");
      if (t!=null)
      { // get the install command
	String[] dat = new String[2];
	dat[0] = h.getSubElementText("uninstall");
	if (dat[0]!=null)
	{ // store the command in the list
	  dat[0] = dat[0].trim();
	  if (t.hasAttribute("log"))
	    dat[1] = t.getAttribute("log");
	  else
	    dat[1] = null;
	  rc.addFirst(dat);

	} // end if

      } // end if

    } // end while

    return rc;

  } // end makeUninstallList

  private final void execList(List cmds, DynamoLog log) throws ModuleException
  {
    Connection conn = null;
    Statement stmt = null;
    try
    { // get a database connection
      conn = m_pool.getConnection();
      stmt = conn.createStatement();

      // loop through the commands
      Iterator it = cmds.iterator();
      while (it.hasNext())
      { // pull out each item in turn
	String[] item = (String[])(it.next());
	try
	{ // execute the SQL statement
	  stmt.executeUpdate(item[0]);
	  if (item[1]!=null)
	    log.info("Success: " + item[1]);

	} // end try
	catch (SQLException e)
	{ // log error and throw message
	  log.error("Failure: " + ((item[1]==null) ? "statement execution" : item[1]),e);
	  log.debug("Statement: " + item[0]);
	  ModuleException me = new ModuleException(InstallerImpl.class,"ModuleMessages","dbInstall.exec",e);
	  me.setParameter(0,e.getMessage());
	  throw me;

	} // end catch
	
      } // end while

    } // end try
    catch (DatabaseException e)
    { // throw exception
      ModuleException me = new ModuleException(InstallerImpl.class,"ModuleMessages","dbInstall.execInit",e);
      me.setParameter(0,e.getMessage());
      throw me;

    } // end catch
    catch (SQLException e)
    { // throw exception
      ModuleException me = new ModuleException(InstallerImpl.class,"ModuleMessages","dbInstall.execInit",e);
      me.setParameter(0,e.getMessage());
      throw me;

    } // end catch
    finally
    { // make sure we shut down the connection before we go
      SQLUtils.shutdown(stmt);
      try
      { // return this connection to the pool
	if (conn!=null)
	  m_pool.releaseConnection(conn);

      } // end try
      catch (DatabaseException e)
      { // ignore the error
      } // end catch

    } // end finally

  } // end execList

  /*--------------------------------------------------------------------------------
   * Implementations from interface DatabaseInstaller
   *--------------------------------------------------------------------------------
   */

  public String getDatabaseType()
  {
    return m_pool.getDatabaseType();

  } // end getDatabaseType

  public void runInstallScript(InputStream script, DynamoLog log) throws ModuleException
  {
    List in_list = loadCommandList(script,log);
    List the_list = makeInstallList(in_list);
    execList(the_list,log);

  } // end runInstallScript

  public void runUninstallScript(InputStream script, DynamoLog log) throws ModuleException
  {
    List in_list = loadCommandList(script,log);
    List the_list = makeUninstallList(in_list);
    execList(the_list,log);

  } // end runUninstallScript

} // end class InstallerImpl
