package w3c.pics.parser;

import java.util.*;

/**
 * This class represents a category in a PICS Service Description (.rat file)
 * Like the .rat file categories, Category objects can be arbitrarily nested.
 **/

public class Category implements java.io.Serializable
{
  Hashtable options = null;
  Hashtable optExt = null;
  Hashtable mandExt = null;
  Vector enumlist = new Vector();
  Vector children = new Vector();
  Category parent = null;
  String transmitName;
  int depth = 0;

  Category(String transmitName, Category parent) 
  {
    this.parent = parent;
    this.transmitName = transmitName;
    if (parent==null) {
      options = new Hashtable();
      optExt = new Hashtable();
      mandExt = new Hashtable();
    }
    else if (parent.parent==null) {
      Hashtable defaultoptions = parent.options;
      options = new Hashtable();
      /* if (defaultoptions.get("extension")!=null)
	options.put("extension", defaultoptions.get("extension")); */
      if (defaultoptions.get("integer")!=null)
	options.put("integer", defaultoptions.get("integer"));
      if (defaultoptions.get("label-only")!=null)
	options.put("label-only", defaultoptions.get("label-only"));
      if (defaultoptions.get("max")!=null)
	options.put("max", defaultoptions.get("max"));
      if (defaultoptions.get("min")!=null)
	options.put("min", defaultoptions.get("min"));
      if (defaultoptions.get("multivalue")!=null)
	options.put("multivalue", defaultoptions.get("multivalue"));
      if (defaultoptions.get("unordered")!=null)
	options.put("unordered", defaultoptions.get("unordered"));
      optExt = (Hashtable)parent.optExt.clone();
      mandExt = (Hashtable)parent.mandExt.clone();
      this.depth=1;
    }
    else {
      options = (Hashtable)parent.options.clone();
      optExt = (Hashtable)parent.optExt.clone();
      mandExt = (Hashtable)parent.mandExt.clone();
      this.depth = parent.depth+1;
    }

  }

  /**
   * Returns a String containing the transmit-name of this Category.
   * @return A String containing the transmit-name.
   **/

  public String getTransmitName()
  {
    return transmitName;
  }

  /**
   * Returns a String containing the full name of this Category, as it would 
   * appear in a PICS label.
   * @return A String containing the full name of this Category.
   **/

  public String getFullName()
  {
    if (parent.parent!=null)
      return parent.getFullName() + "/" + transmitName;
    else return transmitName;
  }

  /**
   * Returns the requested one of the Category's options.
   * @param optionName The option to return.
   * @return A String, the value of the option <em>optionName</em>
   **/

  public String getOption(String optionName)
  {
    return (String)options.get(optionName);
  }

  /**
   * Returns a list of this Category's children, if any.
   * @return A Vector containing this Category's children, as Category objects.
   **/
  
  public Vector getChildren()
  {
    return children;
  }

  /**
   * Adds an optional extension to this Category.
   * @param exName The extension name.
   * @param data The extension data.
   **/

  public void addOptExt(String exName, String data) {
    optExt.put(exName, data);
  }

  /**
   * Adds a mandatory extension to this Category.
   * @param exName The extension name.
   * @param data The extension data.
   **/

  public void addMandExt(String exName, String data) {
    mandExt.put(exName, data);
  }

  /**
   * Returns the value of an optional extension.
   * @param exName The extension to look up.
   * @return A String, containing the value of the extension <em>exName</em>
   **/

  public String getOptExt(String exName) {
    return optExt.get(exName).toString();
  }

  /**
   * Returns the value of a mandatory extension.
   * @param exName The extension to look up.
   * @return A String, containing the value of the extension <em>exName</em>
   **/

  public String getMandExt(String exName) {
    return mandExt.get(exName).toString();
  }

  /**
   * Writes the Category object out in PICS 1.1 format, suitable for inclusion 
   * in a .rat file.
   * @return A String containing PICS 1.1 format category information.
   **/

  public String toString()
  {
    String result = new String();
    String pad = calcPad();
    result += "(category \n";
    result += pad+"(transmit-as \"" + getTransmitName() + "\") \n";
    Enumeration e = options.keys();
    while (e.hasMoreElements())
      {
	String temp = (String)e.nextElement();
	result += pad+"(" + temp + " " + (String)options.get(temp) + ") \n";
      }
    e = optExt.keys();
    while (e.hasMoreElements()) {
      String optKey = e.nextElement().toString();
      String optVal = optExt.get(optKey).toString();
      result += pad+"(extension (optional "+optKey+" "+optVal+"))\n";
    }
    e = mandExt.keys();
    while (e.hasMoreElements()) {
      String mandKey = e.nextElement().toString();
      String mandVal = mandExt.get(mandKey).toString();
      result += pad+"(extension (mandatory "+mandKey+" "+mandVal+"))\n";
    }
    e = enumlist.elements();
    while (e.hasMoreElements()) {
      Enum tempenum = (Enum)e.nextElement();
      result += pad+tempenum.toString();
    }
    e = children.elements();
    while (e.hasMoreElements())
      result += pad+((Category)e.nextElement()).toString();
    result += pad+")\n";
    return result;
  }

  private String calcPad() {
    String retval = new String("");
    for (int i = 0; i<depth; i++) 
      retval+="  ";
    return retval;
  }

  void putChild(Category child)
  {
    children.addElement(child);
  }

  void putOption(String optionName, String value)
  {
    options.put(optionName, value);
  }

  void addEnum(Enum newenum) {
    enumlist.addElement(newenum);
  }
  
  /**
   * Returns a list of all of the labeled values contained in this Category.
   * @return A Vector containing Enums representing the labeled values.
   * @see Enum
   **/

  public Vector getEnums() {
    return enumlist;
  }

}
