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

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

public class ResourceDictionary implements NamedObject, ComponentInitialize, ComponentShutdown, DynamoDictionary
{
  /*--------------------------------------------------------------------------------
   * Internal class that loads the trie
   *--------------------------------------------------------------------------------
   */

  private static class TrieLoader implements BackgroundTask
  {
    /*====================================================================
     * Attributes
     *====================================================================
     */

    private Reader m_rdr;
    private String m_rdrname;
    private volatile Trie m_trie = null;

    /*====================================================================
     * Constructor
     *====================================================================
     */

    TrieLoader(Reader rdr, String rdrname)
    {
      m_rdr = rdr;
      m_rdrname = rdrname;

    } // end constructor

    /*====================================================================
     * Implementations from interface BackgroundTask
     *====================================================================
     */

    /**
     * Execute the background task.
     *
     * @param services A {@link com.silverwrist.dynamo.iface.ServiceProvider ServiceProvider} which provides all
     *                 services that the <CODE>BackgroundTask</CODE> is permitted to use.
     */
    public void run(ServiceProvider services)
    {
      if (logger.isDebugEnabled())
	logger.debug("now loading resource " + m_rdrname);
      Trie trie = new Trie();
      try
      { // create the appropriate reader
	BufferedReader r = new BufferedReader(m_rdr);
	int counter = 0;
	String word = r.readLine();
	while (word!=null)
	{ // load words into the lexicon
	  trie.add(word);
	  word = r.readLine();
	  if (((++counter % 1000)==0) && logger.isDebugEnabled())
	    logger.debug("loaded " + counter + " words");

	} // end while

	r.close();
	if (logger.isDebugEnabled())
	  logger.debug("finished loading resource " + m_rdrname + ", " + counter + " words loaded");

      } // end try
      catch (IOException e)
      { // trap it and go on to the next one
	logger.error("IOException loading resource " + m_rdrname,e);

      } // end catch

      synchronized (this)
      { // save off the trie
	m_trie = trie;
	m_rdr = null;
	notifyAll();

      } // end synchronized block

      System.gc();  // clean up any crap left over from the load

    } // end run

    /*====================================================================
     * External operations
     *====================================================================
     */

    synchronized Trie getTrie()
    {
      while (m_trie==null)
      { // not loaded yet - wait for it
	if (logger.isDebugEnabled())
	  logger.debug("waiting for trie to load...");

	try
	{ // park the thread here until we know what's up
	  wait();

	} // end try
	catch (InterruptedException e)
	{ // do nothing
	} // end catch

      } // end while

      return m_trie;

    } // end getTrie

  } // end class TrieLoader

  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

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

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

  private String m_name;                       // name of this object
  private TrieLoader m_loader;                 // contains the trie we're loading

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

  public ResourceDictionary()
  { // do nothing
  } // end constructor

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

  private static final boolean checkHyphenates(Trie trie, String word)
  {
    if (word.indexOf('-')<0)
      return false;  // no hyphenates

    String[] parts = StringUtils.split1(word,'-');
    boolean ok = true;
    for (int i=0; ok && (i<parts.length); i++)
      if (parts[i].length()>1)
	ok = trie.check(parts[i]);

    return ok;

  } // end checkHyphenates

  /*--------------------------------------------------------------------------------
   * 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
  {
    XMLLoader loader = XMLLoader.get();
    String resource_name = null;
    try
    { // verify the right node name
      loader.verifyNodeName(config_root,"dictionary");

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

      // get the name of the resource to load
      resource_name = loader.getAttribute(config_root,"resource");

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

    } // end catch

    // Create the loader object.
    m_loader = new TrieLoader(new InputStreamReader(getClass().getResourceAsStream(resource_name)),resource_name);

    // Queue the loader up as a background task.
    BackgroundScheduler sched = (BackgroundScheduler)(services.queryService(BackgroundScheduler.class));
    sched.runTaskLater(m_loader,false);

  } // end initialize

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

  public void shutdown()
  {
    m_loader = null;

  } // end shutdown

  /*--------------------------------------------------------------------------------
   * Implementations from interface DynamoDictionary
   *--------------------------------------------------------------------------------
   */

  public int size()
  {
    return m_loader.getTrie().size();

  } // end size

  public boolean check(String word)
  {
    if (word==null)
      return false;
    if (word.length()<=1)
      return true;
    String real_word = word.toLowerCase();
    Trie trie = m_loader.getTrie();
    if (trie.check(real_word))
      return true;
    if (real_word.endsWith("'s"))
    { // check the non-possessive form
      String base = real_word.substring(0,real_word.length()-2);
      if (trie.check(base))
	return true;
      else
	return checkHyphenates(trie,base);

    } // end if
    else // check all hyphenates
      return checkHyphenates(trie,real_word);

  } // end check

} // end class ResourceDictionary
