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

class Trie
{
  /*--------------------------------------------------------------------------------
   * Internal node class
   *--------------------------------------------------------------------------------
   */

  private static final class Node
  {
    /*====================================================================
     * Attributes
     *====================================================================
     */

    private boolean m_term = false;
    private Node[] m_ptr = null;

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

    Node()
    { // do nothing
    } // end constructor

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

    final Node getRef(char ltr)
    {
      if (m_ptr==null)
	return null;
      int x = permute(ltr);
      return (x<m_ptr.length) ? m_ptr[x] : null;

    } // end getRef

    final void setRef(char ltr, Node node)
    {
      int x = permute(ltr);
      if ((m_ptr==null) || (x>=m_ptr.length))
      { // the internal array needs to be expanded
	Node[] new_array = new Node[x+1];
	int i = 0;
	if (m_ptr!=null)
	{ // copy the old portion of the array over
	  System.arraycopy(m_ptr,0,new_array,0,m_ptr.length);
	  i = m_ptr.length;

	} // end if

	while (i<new_array.length)
	  new_array[i++] = null;  // null out the new portion of the array

	m_ptr = new_array;  // save off the new reference

      } // end if

      m_ptr[x] = node;  // save reference

    } // end setRef

    final boolean isTerminal()
    {
      return m_term;

    } // end isTerminal

    final void setTerminal()
    {
      m_term = true;

    } // end setTerminal

  } // end class Node

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

  private static final int[] PERMUTE_TAB =
    { 8, 22, 13, 10, 2, 14, 19, 11, 6, 26, 24, 12, 17, 4, 7, 15, 25, 5, 9, 3, 16, 21, 20, 23, 18, 27 };

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

  private Node m_root;
  private int m_count;

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

  Trie()
  {
    m_root = new Node();
    m_count = 0;

  } // end constructor

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

  private static final boolean validchar(char ch)
  {
    return ((ch>='a') && (ch<='z')) || (ch=='\'') || (ch=='-');
  }

  private static final int permute(char ltr)
  {
    if (ltr=='-')
      return 0;
    else if (ltr=='\'')
      return 1;
    else
      return PERMUTE_TAB[ltr - 'a'];

  } // end permute

  /*--------------------------------------------------------------------------------
   * External operations
   *--------------------------------------------------------------------------------
   */

  int size()
  {
    return m_count;

  } // end size

  boolean check(String s)
  {
    char[] arr = s.toLowerCase().toCharArray();
    Node cur = m_root;
    for (int i=0; i<arr.length; i++)
    { // navigate down the trie
      if (!validchar(arr[i]))
	return false;
      cur = cur.getRef(arr[i]);
      if (cur==null)
	return false;

    } // end for

    return cur.isTerminal();

  } // end check

  void add(String s)
  {
    char[] arr = s.toLowerCase().toCharArray();
    Node cur = m_root;
    for (int i=0; i<arr.length; i++)
    { // navigate down the trie
      if (!validchar(arr[i]))
	return;

      // navigate down one level
      Node next = cur.getRef(arr[i]);
      if (next==null)
      { // create a new node and set its reference
	next = new Node();
	cur.setRef(arr[i],next);

      } // end if

      cur = next;

    } // end for

    cur.setTerminal();
    m_count++;

  } // end add

} // end class Trie
