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

import java.io.*;
import org.apache.log4j.*;
import com.silverwrist.venice.htmlcheck.SpellingDictionary;

public class LazyTreeLexicon implements Runnable, SpellingDictionary
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

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

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

  volatile TreeLexicon inner_lex = null;
  private String[] filenames;

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

  public LazyTreeLexicon(String[] filenames)
  {
    this.filenames = filenames;  // save off the file names to be loaded

    // do not start a new thread, we'll queue the lexicon up as a task

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Internal functions
   *--------------------------------------------------------------------------------
   */

  private synchronized TreeLexicon getLex()
  {
    while (inner_lex==null)
    { // wait for the inner thread to finish creating the lexicon
      if (logger.isDebugEnabled())
	logger.debug("LazyTreeLexicon: waiting for lex 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 inner_lex;

  } // end getLex

  /*--------------------------------------------------------------------------------
   * Implementations from class Runnable
   *--------------------------------------------------------------------------------
   */

  public void run()
  {
    TreeLexicon lex = new TreeLexicon();

    if (logger.isDebugEnabled())
      logger.debug("LazyTreeLexicon loading " + filenames.length + " lexicon(s)");

    for (int i=0; i<filenames.length; i++)
    { // load data into the lexicon in turn
      if (logger.isDebugEnabled())
	logger.debug("LazyTreeLexicon loading file: " + filenames[i]);

      try
      { // start reading the file
	BufferedReader rdr = new BufferedReader(new FileReader(filenames[i]));

	int counter = 0;
	String word = rdr.readLine();
	while (word!=null)
	{ // add each word to the lexicon as we go
	  lex.addWord(word);
	  word = rdr.readLine();
	  if (((++counter % 1000)==0) && logger.isDebugEnabled())
	    logger.debug("loaded " + counter + " words");

	} // end while

	rdr.close();
	if (logger.isDebugEnabled())
	  logger.debug("finished loading " + filenames[i] + ", " + counter + " words loaded");

      } // end try
      catch (IOException e)
      { // trap it and go on to the next one
	logger.error("IOException loading lexfile " + filenames[i] + ": " + e.getMessage());

      } // end catch

    } // end for

    if (logger.isDebugEnabled())
      logger.debug("LazyTreeLexicon load complete.");

    synchronized (this)
    { // set the lexicon reference and wake up all waiting threads
      inner_lex = lex;
      notifyAll();

    } // end synchronized block

    System.gc();  // free any extra crap generated by the lexicon load

    if (logger.isDebugEnabled())
      logger.debug("LazyTreeLexicon GC complete.");

  } // end run

  /*--------------------------------------------------------------------------------
   * Implementations from interface SpellingDictionary
   *--------------------------------------------------------------------------------
   */

  public int size()
  {
    return getLex().size();

  } // end size

  public boolean checkWord(String word)
  {
    return getLex().checkWord(word);

  } // end checkWord

} // end class LazyTreeLexicon
