package gov.va.med.authentication.kernel.sspi.authentication.manageable;

import java.util.Enumeration;
import java.util.Properties;

/**
 * Used to return a list of user or group names
 * matching a wildcard.  The list is bounded by a
 * maximum number of elements to return.
 *
 * 
 * @author VHIT Security and Other Common Services (S&OCS)
 * @version 1.1.0.002
 */

class KaajeeUserOrGroupList implements KaajeeListManager.List
{
  private KaajeeUserGroupDatabase database;   // the user/group database
  private Enumeration       e;          // an enumeration of the keys in the database
  private boolean           listUsers;  // are we listing users (true) or groups (false)
  private boolean           matchAll;   // are we listing all users/groups (true) or matching a prefix or exact name (false)
  private String            startsWith; // if matching a prefix, what must the user/group name be prefixed with to match?
  private String            matchExact; // if matching an exact name, what is the name we're looking for?
  private int               maxLeft;    // how many more matches is the list allowed to return?
  private String            current;    // what is the name of the current user/group?

  /*
   * The constructor.
   *
   * @param database a UserGroupDatabase containing the
   * users and groups for the manageable sample authenticator.
   *
   * @param listUsers a boolean indicating if users (true)
   * or groups (false) should be returned by this list.
   *
   * @param wildcard a String containing the rules for name matching.
   * "*" means all names match.
   * "Foo*" means that names starting with "Foo" match.
   * "FooBar" means that only the name "FooBar" matches.
   * These are the only supported wildcard forms.
   * The matching is case sensitive.
   *
   * @param max an int containing the maximum number of names
   * that the list is allowed to return.  It must be greater than zero.
   *
   * @throws IllegalArgumentException if max is not greater than zero.
   */
  /*package*/ KaajeeUserOrGroupList(KaajeeUserGroupDatabase database, boolean listUsers, String wildcard, int max)
  {
    if (max < 1) {
      throw new IllegalArgumentException("Max must be greater than 0: " + max);
    }

    // Make sure that the wildcard doesn't contain invalid characters.
    Utils.checkVal(wildcard);

    this.database = database;
    this.listUsers = listUsers;

    e           = database.getKeys(); // get the keys for all the users/groups in the database.
	//for (Enumeration e = database.getKeys() ; e.hasMoreElements() ;) {
     //    System.out.println("UORGLIST :"+ e.nextElement());
     //}

    matchAll    = false;
    startsWith  = null;
    matchExact  = null;
    maxLeft     = max;
    current     = null;

    // parse the wildcard to figure out the matching rules.
    if ("*".equals(wildcard)) {
      matchAll = true;
    } else if (wildcard.endsWith("*")) {
      startsWith = wildcard.substring(0, wildcard.length()-1);
    } else {
      matchExact = wildcard;
    }

    // advance the list to its first matching element.
    _advance();
  }

  /*
   * Does the list have a current element?
   *
   * @return a boolean indicating if the list has a current element
   *
   * @throws IllegalStateException if the list does not have a current element.
   */
  public boolean haveCurrent()
  {
    return (current != null);
  }

  /*
   * Get the current matching user/group's name.
   *
   * @return a String containing the current element's name
   *
   * @throws IllegalStateException if the list does not have a current element.
   */
  public String getCurrentName()
  {
    checkNotDone();
    return current;
  }

  /*
   * Advance the list to the next element.
   *
   * @throws IllegalStateException if the list does not have a current element.
   */
  public void advance()
  {
    checkNotDone();
    _advance();
  }

  /*
   * Terminate the list, freeing up any resources held on behalf of the list.
   * This closes the list regardless of whether or not the list has been
   * completely traversed.  This allows the customer to partially traverse
   * the list without leaking memory or resources.
   */
  public void close()
  {
    current = null;
  }


  /**
   * A utility to check that the list still has a current element.
   *
   * @throws IllegalStateException if the list does not have a current element.
   */
  private void checkNotDone()
  {
    if (!haveCurrent()) {
      throw new IllegalStateException("List out of elements");
    }
  }

  /**
   * A utility to advance the list to the next element.
   */
  private void _advance()
  {
    // Loop until we find a match or run out of elements
    String temp = null;
    while (temp == null && e.hasMoreElements() && maxLeft > 0) {

      // get the next key name in the database
      String key = (String)e.nextElement();

      // convert the key to either a user or group name.
      // null is returned if the name is for the opposite type
      // (eg. we're listing users and the current name is for a group)
      String name = (listUsers) ? KaajeeUserEntry.getNameFromKey(key) : KaajeeGroupEntry.getNameFromKey(key);

      // see if it matches
      if (name != null && matchesWildcard(name)) {
        temp = name;
      }
    }
    if (temp != null) {
      current = temp;
      maxLeft--;
    } else {
      current = null;
    }
  }

  /**
   * A utility to determine if a user or group name matches a wildcard.
   *
   * @return a boolean indicating if the name matches the wildcard.
   */
  private boolean matchesWildcard(String name)
  {
    if (matchAll) return true;
    if (matchExact != null && matchExact.equals(name)) return true;
    if (startsWith != null && name.startsWith(startsWith)) return true;
    return false;
  }
}
