/*
 * 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) 2001-02 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.venice.core.impl;

import java.sql.*;
import java.util.*;
import org.apache.log4j.*;
import com.silverwrist.util.ParallelRunQueue;
import com.silverwrist.util.cache.ObjectCache;
import com.silverwrist.venice.core.internals.*;
import com.silverwrist.venice.db.*;
import com.silverwrist.venice.except.DataException;
import com.silverwrist.venice.except.InternalStateError;

class BackgroundCommunityPurge implements Runnable
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static Category logger = Category.getInstance(BackgroundCommunityPurge.class);

  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private EnvCommunity env;
  private int cid;
  private int num_confs;
  private int max_confid;
  private ObjectCache conf_objcache;

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

  BackgroundCommunityPurge(EnvCommunity env, int cid, int num_confs, int max_confid, ObjectCache conf_objcache)
  {
    this.env = env;
    this.cid = cid;
    this.num_confs = num_confs;
    this.max_confid = max_confid;
    this.conf_objcache = conf_objcache;

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Implementations from interface Runnable
   *--------------------------------------------------------------------------------
   */

  public void run()
  {
    if (logger.isDebugEnabled())
      logger.debug("BackgroundCommunityPurge running on community #" + cid);

    Connection conn = null;  // pooled database connection
    Statement stmt = null;
    ParallelRunQueue rq = new ParallelRunQueue(2);

    try
    { // get a database connection from the pool
      conn = env.getConnection();
      stmt = conn.createStatement();

      // run some "lower priority" deletes
      stmt.executeUpdate("DELETE FROM contacts WHERE owner_sigid = " + cid + ";");
      stmt.executeUpdate("DELETE FROM sigftrs WHERE sigid = " + cid + ";");
      stmt.executeUpdate("DELETE FROM sigban WHERE sigid = " + cid + ";");
      stmt.executeUpdate("DELETE FROM propcomm WHERE cid = " + cid + ";");

      // look up all conference IDs in this community
      int[] conf_ids = new int[num_confs];
      StringBuffer sql = new StringBuffer("SELECT confid FROM sigtoconf WHERE sigid = ");
      sql.append(cid).append(" AND confid <= ").append(max_confid).append(" ORDER BY confid;");
      ResultSet rs = stmt.executeQuery(sql.toString());
      int conferences = 0;
      while (rs.next())
	conf_ids[conferences++] = rs.getInt(1);
      SQLUtil.shutdown(rs);

      for (int i=0; i<conferences; i++)
      { // look to see if there's a conference community object first
	Integer key = new Integer(conf_ids[i]);
	ConferenceCommunityContext confobj = (ConferenceCommunityContext)(conf_objcache.get(key));
	if (confobj!=null)
	{ // OK, there's an object - do the delete internally and release the object
	  conf_objcache.detach(key);
	  confobj.delete(env);
	  
	} // end if
	else
	{ // we need to manually remove the conference ourselves
	  boolean delete_core = true;

	  // see if conference is linked to other communities - will determine whether we do the core purge
	  // routine
	  sql.setLength(0);
	  sql.append("SELECT sigid FROM sigtoconf WHERE confid = ").append(key).append(" AND sigid <> ");
	  sql.append(cid).append(" LIMIT 1;");
	  rs = stmt.executeQuery(sql.toString());
	  if (rs.next())
	    delete_core = false;
	  SQLUtil.shutdown(rs);

	  // delete the sigtoconf record
	  sql.setLength(0);
	  sql.append("DELETE FROM sigtoconf WHERE sigid = ").append(cid).append(" AND confid = ");
	  sql.append(key).append(';');

	  if (delete_core)
	  { // OK, we officially need to delete the whole core now...purge from the two important
	    // tables first
	    stmt.executeUpdate("DELETE FROM confs WHERE confid = " + key + ";");
	    stmt.executeUpdate("DELETE FROM confalias WHERE confid = " + key + ";");
	    stmt.executeUpdate("DELETE FROM propconf WHERE confid = " + key + ";");
	    stmt.executeUpdate("DELETE FROM confcustom WHERE confid = " + key + ";");

	    // determine the number of topics in this conference, and the maximum topic ID, and use
	    // that information to queue up the conference deletion
	    sql.setLength(0);
	    sql.append("SELECT COUNT(*), MAX(topicid) FROM topics WHERE confid = ").append(key).append(';');
	    rs = stmt.executeQuery(sql.toString());
	    if (!(rs.next()))
	      throw new InternalStateError("BackgroundCommunityPurge.run screwup on conference SELECT");
	    rq.queue(new BackgroundConferencePurge(env,key.intValue(),rs.getInt(1),rs.getInt(2)));
	    SQLUtil.shutdown(rs);

	  } // end if (have to delete conference data)

	} // end else (deleting conference data manually)

      } // end for

      if (logger.isDebugEnabled())
	logger.debug("BackgroundCommunityPurge basic delete complete for community #" + cid);

    } // end try
    catch (SQLException e)
    { // on an error, just die
      logger.error("BackgroundCommunityPurge FATAL EXCEPTION purging #" + cid + ": " + e.getMessage(),e);
      return;

    } // end catch
    catch (DataException de)
    { // on an error, just die
      logger.error("BackgroundCommunityPurge FATAL EXCEPTION purging #" + cid + ": " + de.getMessage(),de);
      return;

    } // end catch
    finally
    { // make sure we release the connection before we go
      SQLUtil.shutdown(stmt);
      env.releaseConnection(conn);

    } // end finally

    rq.run();  // now run the parallel queue to finish processing

    if (logger.isDebugEnabled())
      logger.debug("BackgroundCommunityPurge COMPLETE for community #" + cid);

  } // end run

} // end class BackgroundCommunityPurge
