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

import java.util.BitSet;

/**
 * A variant of the <CODE>BitSet</CODE> that can express itself as a character string, where each
 * character represents a flag that is "set."  Up to 91 flags can be specified pre <CODE>OptionSet</CODE>.
 *
 * @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
 * @version X
 * @see java.util.BitSet
 */
public class OptionSet extends BitSet
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  // The alphabet to use to store individual flags.
  private static final String ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
                                    + "!#$%&()*+,-./:;<=>?@[]^_`{|}~";

  /*--------------------------------------------------------------------------------
   * Constructors
   *--------------------------------------------------------------------------------
   */

  /**
   * Creates a new <CODE>OptionSet</CODE>.  All bits are initially <CODE>false</CODE>.
   */
  public OptionSet()
  {
    super();

  } // end constructor

  /**
   * Creates an <CODE>OptionSet</CODE> whose initial size is large enough to explicitly represent bits with
   * indices in the range 0 through nbits-1. All bits are initially <CODE>false</CODE>.  The maximum
   * size of the <CODE>OptionSet</CODE> is 91.
   *
   * @param nbits The initial size of the bit set.
   * @exception java.lang.NegativeArraySizeException If the specified initial size is negative.
   */
  public OptionSet(int nbits)
  {
    super(Math.min(nbits,ALPHA.length()));

  } // end constructor

  /**
   * Creates an <CODE>OptionSet</CODE> from an array of characters representing "set" options.
   *
   * @param options The options to be set in the new <CODE>OptionSet</CODE>.
   */
  public OptionSet(char[] options)
  {
    super();  // initialize all bits to 0
    for (int i=0; i<options.length; i++)
    { // look at all the chars in the option string and set bits accordingly
      int ndx = ALPHA.indexOf(options[i]);
      if (ndx>=0)
	super.set(ndx);

    } // end for

  } // end constructor

  /**
   * Creates an <CODE>OptionSet</CODE> from a string of characters representing "set" options.
   *
   * @param options The options to be set in the new <CODE>OptionSet</CODE>.
   */
  public OptionSet(String options)
  {
    this(options.toCharArray());

  } // end constructor

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

  /**
   * Returns a <CODE>StringBuffer</CODE> representing the current state of this <CODE>OptionSet</CODE>,
   * with one character in it for each bit that is set.
   *
   * @return A <CODE>StringBuffer</CODE> containing the current state of the <CODE>OptionSet</CODE>.
   */
  private StringBuffer asStringBuffer()
  {
    StringBuffer b = new StringBuffer();
    for (int i=0; i<super.length(); i++)
      if (super.get(i))
	b.append(ALPHA.charAt(i));
    return b;

  } // end asStringBuffer

  /*--------------------------------------------------------------------------------
   * Overrides from class BitSet
   *--------------------------------------------------------------------------------
   */

  /**
   * Sets the bit specified by the index to <CODE>false</CODE>.
   *
   * @param bitIndex The index of the bit to be cleared.
   * @exception java.lang.IndexOutOfBoundsException - If the specified index is negative or greater than the
   *            maximum option for an <CODE>OptionSet</CODE>.
   */
  public void clear(int bitIndex)
  {
    if (bitIndex>=ALPHA.length())
      throw new IndexOutOfBoundsException();
    super.clear(bitIndex);

  } // end clear

  /**
   * Returns the value of the bit with the specified index. The value is <CODE>true</CODE> if the bit with
   * the index <CODE>bitIndex</CODE> is currently set in this <CODE>OptionSet</CODE>; otherwise, the result
   * is <CODE>false</CODE>.
   *
   * @param bitIndex The bit index.
   * @return The value of the bit with the specified index.
   * @exception java.lang.IndexOutOfBoundsException - If the specified index is negative or greater than the
   *            maximum option for an <CODE>OptionSet</CODE>.
   */
  public boolean get(int bitIndex)
  {
    if (bitIndex>=ALPHA.length())
      throw new IndexOutOfBoundsException();
    return super.get(bitIndex);

  } // end get

  /**
   * Sets the bit specified by the index to <CODE>true</CODE>.
   *
   * @param bitIndex The index of the bit to be set.
   * @exception java.lang.IndexOutOfBoundsException - If the specified index is negative or greater than the
   *            maximum option for an <CODE>OptionSet</CODE>.
   */
  public void set(int bitIndex)
  {
    if (bitIndex>=ALPHA.length())
      throw new IndexOutOfBoundsException();
    super.set(bitIndex);

  } // end set

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

  /**
   * Sets the value of the specified bit in the <CODE>OptionSet</CODE> to a specified Boolean
   * value, and returns an indication of whether that value was changed.
   *
   * @param ndx The index of the bit to be assigned.
   * @param val <CODE>true</CODE> to set the corresponding bit, <CODE>false</CODE> to clear it.
   * @return <CODE>true</CODE> if the value of the bit in the <CODE>OptionSet</CODE> was changed by this
   *         operation, <CODE>false</CODE> if not.
   * @exception java.lang.IndexOutOfBoundsException - If the specified index is negative or greater than the
   *            maximum option for an <CODE>OptionSet</CODE>.
   */
  public boolean assign(int ndx, boolean val)
  {
    if (ndx>=ALPHA.length())
      throw new IndexOutOfBoundsException();
    boolean old = super.get(ndx);
    if (val)
      super.set(ndx);
    else
      super.clear(ndx);
    return (old!=val);

  } // end assign

  /**
   * Resets the state of this <CODE>OptionSet</CODE> from an array of characters representing "set" options.
   *
   * @param options The options to be set in the new <CODE>OptionSet</CODE>.  All options not specified will
   *                be cleared.
   */
  public void assign(char[] options)
  {
    int i;
    for (i=0; i<super.length(); i++)
      super.clear(i);

    for (i=0; i<options.length; i++)
    { // look at all the chars in the option string and set bits accordingly
      int ndx = ALPHA.indexOf(options[i]);
      if (ndx>=0)
	super.set(ndx);

    } // end for

  } // end assign

  /**
   * Resets the state of this <CODE>OptionSet</CODE> from a string of characters representing "set" options.
   *
   * @param options The options to be set in the new <CODE>OptionSet</CODE>.  All options not specified will
   *                be cleared.
   */
  public void assign(String options)
  {
    if (options!=null)
      assign(options.toCharArray());

  } // end assign

  /**
   * Returns a character array representing the current state of this <CODE>OptionSet</CODE>,
   * with one character in it for each bit that is set.
   *
   * @return A character array containing the current state of the <CODE>OptionSet</CODE>.
   */
  public char[] asCharArray()
  {
    return asStringBuffer().toString().toCharArray();

  } // end asCharArray

  /**
   * Returns a string representing the current state of this <CODE>OptionSet</CODE>,
   * with one character in it for each bit that is set.
   *
   * @return A string containing the current state of the <CODE>OptionSet</CODE>.
   */
  public String asString()
  {
    return asStringBuffer().toString();

  } // end asString

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

  public static final char getOptionChar(int index)
  {
    if ((index<0) || (index>=ALPHA.length()))
      throw new IndexOutOfBoundsException();
    return ALPHA.charAt(index);

  } // end getOptionChar

} // end class OptionSet
