/*
 * 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.htmlcheck;

import java.util.*;
import org.apache.commons.collections.*;
import org.apache.log4j.Logger;
import org.w3c.dom.*;
import com.silverwrist.util.xml.*;
import com.silverwrist.dynamo.db.NamespaceCache;
import com.silverwrist.dynamo.except.*;
import com.silverwrist.dynamo.iface.*;
import com.silverwrist.dynamo.util.*;

public class HTMLCheckerManager
    implements NamedObject, ComponentInitialize, ComponentShutdown, HTMLCheckerService, HTMLCheckerConfigRegister
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static Logger logger = Logger.getLogger(HTMLCheckerManager.class);

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

  private String m_name;                       // name of this object
  private ProfileOps m_ops;                    // profile operations
  private NamespaceCache m_ns_cache;           // namespace cache object
  private ComponentShutdown m_hook_rt;         // hook runtime services
  private ComponentShutdown m_hook_init;       // hook initialization services
  private Vector m_configurators;              // registered configurators
  private ReferenceMap m_profiles;             // profile map
  private ReferenceMap m_frozen_profiles;      // frozen profile map

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

  public HTMLCheckerManager()
  {
    m_configurators = new Vector();
    m_profiles = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT);
    m_frozen_profiles = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT);
    m_configurators.add(new EncodeHTML());
    m_configurators.add(new EncodeSQL());
    m_configurators.add(new RewriteEMailAddresses());
    m_configurators.add(new RewriteURLs());

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Implementations from interface NamedObject
   *--------------------------------------------------------------------------------
   */

  public String getName()
  {
    return m_name;

  } // end getName

  /*--------------------------------------------------------------------------------
   * Implementations from interface ComponentInitialize
   *--------------------------------------------------------------------------------
   */

  /**
   * Initialize the component.
   *
   * @param config_root Pointer to the section of the Dynamo XML configuration file that configures this
   *                    particular component.  This is to be considered "read-only" by the component.
   * @param services An implementation of {@link com.silverwrist.dynamo.iface.ServiceProvider ServiceProvider}
   *                 which provides initialization services to the component.  This will include an implementation
   *                 of {@link com.silverwrist.dynamo.iface.ObjectProvider ObjectProvider} which may be used to
   *                 get information about other objects previously initialized by the application.
   * @exception com.silverwrist.dynamo.except.ConfigException If an error is encountered in the component
   *            configuration.
   */
  public void initialize(Element config_root, ServiceProvider services) throws ConfigException
  {
    logger.info("HTMLCheckerManager initializing");
    XMLLoader loader = XMLLoader.get();
    String conn_name = null;
    String nscache_name = null;
    try
    { // verify the right node name
      loader.verifyNodeName(config_root,"object");

      // get the object's name
      m_name = loader.getAttribute(config_root,"name");

      // get the database configuration connection
      DOMElementHelper config_root_h = new DOMElementHelper(config_root);
      Element elt = loader.getSubElement(config_root_h,"database");
      conn_name = loader.getAttribute(elt,"connection");
      nscache_name = loader.getAttribute(elt,"namespaces");

    } // end try
    catch (XMLLoadException e)
    { // error loading XML config data
      throw new ConfigException(e);

    } // end catch

    // Get the database connection pool and namespace cache.
    DBConnectionPool pool = GetObjectUtils.getDatabaseConnection(services,conn_name);
    m_ns_cache =
        (NamespaceCache)(GetObjectUtils.getDynamoComponent(services,NamespaceCache.class,nscache_name));

    // Get the database operations object.
    m_ops = ProfileOps.get(pool);

    // Register ourselves with the runtime services.
    SingletonServiceProvider ssp = new SingletonServiceProvider("HTMLCheckerManager",HTMLCheckerService.class,this);
    HookServiceProviders hooker = (HookServiceProviders)(services.queryService(HookServiceProviders.class));
    m_hook_rt = hooker.hookRuntimeServiceProvider(ssp);

    // Register ourselves with the init services.
    ssp = new SingletonServiceProvider("HTMLCheckerManager",HTMLCheckerConfigRegister.class,this);
    m_hook_init = hooker.hookInitServiceProvider(ssp);

  } // end initialize

  /*--------------------------------------------------------------------------------
   * Implementations from interface ComponentShutdown
   *--------------------------------------------------------------------------------
   */

  public void shutdown()
  {
    m_hook_rt.shutdown();
    m_hook_rt = null;
    m_hook_init.shutdown();
    m_hook_init = null;
    m_ns_cache = null;
    m_ops.dispose();
    m_ops = null;
    m_frozen_profiles.clear();
    m_profiles.clear();
    m_configurators.clear();

  } // end shutdown

  /*--------------------------------------------------------------------------------
   * Implementations from interface HTMLCheckerService
   *--------------------------------------------------------------------------------
   */

  public HTMLChecker createHTMLChecker(String profile_namespace, String profile_name) throws DatabaseException
  {
    QualifiedNameKey key = new QualifiedNameKey(profile_namespace,profile_name);

    FrozenProfileObject p = null;
    synchronized (this)
    { // retrieve profile from the internal cache
      p = (FrozenProfileObject)(m_frozen_profiles.get(key));
      if (p==null)
      { // OK, look up the profile object
	ProfileObject profile = (ProfileObject)(m_profiles.get(key));
	if (profile==null)
	{ // get the index of the profile from the database
	  int prof_ndx = m_ops.getProfileIndex(m_ns_cache.namespaceNameToId(profile_namespace),profile_name);

	  // create the profile object
	  profile = new ProfileObject(m_ops,m_ns_cache,prof_ndx);

	  // Now we have to let the configurator objects have their way with it.
	  Iterator it = m_configurators.iterator();
	  while (it.hasNext())
	  { // run each configurator in turn
	    HTMLCheckerConfigurator conf = (HTMLCheckerConfigurator)(it.next());
	    conf.configure(profile);

	  } // end while

	  m_profiles.put(key,profile);

	} // end if (need to get profile)

	// Freeze the profile.
	p = new FrozenProfileObject(profile);
	m_frozen_profiles.put(key,p);

      } // end if

    } // end synchronized block

    return new CheckerObject(p);

  } // end createHTMLChecker

  /*--------------------------------------------------------------------------------
   * Implementations from interface HTMLCheckerConfigRegister
   *--------------------------------------------------------------------------------
   */

  public ComponentShutdown registerConfigurator(HTMLCheckerConfigurator cfg)
  {
    m_configurators.add(cfg);
    return new ShutdownVectorRemove(m_configurators,cfg);

  } // end registerConfigurator

} // end class HTMLCheckerManager
