package w3c.pics.parser;

import java.util.*;

/**
 * A class representing a PICS 1.1 service description (a .rat file).
 **/

public class Service implements java.io.Serializable
{
  String ratingSystem = null, ratingService = null;
  String version = null;
  Category root;
  Hashtable defOptExt = new Hashtable();
  Hashtable defMandExt = new Hashtable();
  
  /**
   * Creates a new, empty Service.
   **/

  public Service() 
  {
    root = new Category(null, null);
  }

  /**
   * Adds a default optional extension to this Service.
   * @param exName The extension name.
   * @param data The extension data.
   **/

  public void addDefaultOptExt(String exName, String data) {
    defOptExt.put(exName, data);
  }

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

  public void addDefaultMandExt(String exName, String data) {
    defMandExt.put(exName, data);
  }

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

  public String getDefaultOptExt(String exName) {
    return defOptExt.get(exName).toString();
  }

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

  public String getDefaultMandExt(String exName) {
    return defMandExt.get(exName).toString();
  }

  /**
   * Returns the version of this Service.
   * @return A String containing the value of the Version attribute.
   **/
  
  public String getVersion()
  {
    return version;
  }

  /**
   * Returns the rating-system of this Service.
   * @return A String containing the value of the Rating-system attribute.
   **/

  public String getRatingSystem()
  {
    return ratingSystem;
  }

  /**
   * Returns the rating-service of this Service.
   * @return A String containing the value of the Rating-service attribute.
   **/

  public String getRatingService()
  {
    return ratingService;
  }

  /**
   * Returns the name of this Service.
   * @return A String containing the value of the Name attribute.
   **/

  public String getName()
  {
    String temp = root.getOption("name").toString();
    return temp;
  }

  /**
   * Returns the description of this Service.
   * @return A String containing the value of the Description attribute.
   **/

  public String getDescription()
  {
    String temp = root.getOption("description").toString();
    return temp;
  }

  /**
   * Returns the icon of this Service.
   * @return A String containing the value of the Icon attribute.
   **/

  public String getIcon()
  {
    String temp = root.getOption("icon").toString();
    return temp;
  }

  /**
   * Returns a list of the categories within this Service.
   * @return A Vector of Category objects representing the categories of this 
   * service.
   * @see Category
   **/

  public Vector getCategoryList()
  {
    return root.getChildren();
  }

  private boolean hasDefaults() {
    Enumeration rootoptions = root.options.keys();
    while (rootoptions.hasMoreElements()) {
      String key = rootoptions.nextElement().toString();
      if ((key.equals("integer")) || (key.equals("label-only"))
	  || (key.equals("max")) || (key.equals("min")) 
	  || (key.equals("multivalue")) || (key.equals("unordered"))) {
	return true;
      }
    }
    return false;
  }

  /**
   * Writes the Service object out in PICS 1.1 format suitable for use as a 
   * .rat file.
   * @return A String containing the Service in the format of 
   * application/pics-service.
   **/

  public String toString()
  {
    String result = new String();
    result += "((PICS-version " + version + ") \n";
    result += " (rating-system \"" + ratingSystem + "\") \n";
    result += " (rating-service \"" + ratingService + "\") \n";
    boolean def = false;
    if ((defOptExt.size()!=0) || (defMandExt.size()!=0) || (hasDefaults())) {
      result += " (default \n";
      def = true;
    }
    Enumeration optKeys = defOptExt.keys();
    while (optKeys.hasMoreElements()) {
      String optKey = optKeys.nextElement().toString();
      String optVal = defOptExt.get(optKey).toString();
      result += "  (extension (optional "+optKey+" "+optVal+" ))\n";
    }
    Enumeration mandKeys = defMandExt.keys();
    while (mandKeys.hasMoreElements()) {
      String mandKey = mandKeys.nextElement().toString();
      String mandVal = defMandExt.get(mandKey).toString();
      result += "  (extension (mandatory "+mandKey+" "+mandVal+" ))\n";
    }
    Enumeration rootoptions = root.options.keys();
    while (rootoptions.hasMoreElements()) {
      String rootname = rootoptions.nextElement().toString();
      String rootvalue = root.options.get(rootname).toString();
      if ((rootname.equals("integer")) || (rootname.equals("label-only"))
	  || (rootname.equals("max")) || (rootname.equals("min")) 
	  || (rootname.equals("multivalue")) 
	  || (rootname.equals("unordered"))) {
	result += "  ("+rootname+" "+rootvalue+") \n";
      }
    }
    if (def)
      result+=" )\n";
    rootoptions = root.options.keys();
    while (rootoptions.hasMoreElements()) {
      String rootname = rootoptions.nextElement().toString();
      String rootvalue = root.options.get(rootname).toString();
      if ((!rootname.equals("integer")) && (!rootname.equals("label-only"))
	  && (!rootname.equals("max")) && (!rootname.equals("min")) 
	  && (!rootname.equals("multivalue")) 
	  && (!rootname.equals("unordered"))) {
	result += " ("+rootname+" "+rootvalue+") \n";
      }
    }    
    Enumeration e = root.getChildren().elements();
    while (e.hasMoreElements())
      result += ((Category)e.nextElement()).toString();
    result += ")\n";
    return result;
  }
  
  void setVersion(String version)
  {
    this.version = version;
  }
  
  void setRatingSystem(String ratingSystem)
  {
    this.ratingSystem = ratingSystem;
  }

  void setRatingService(String ratingService)
  {
    this.ratingService = ratingService;
  }

  void putCategory(String parent, Category cat)
  {
    stringToCategory(root, parent).putChild(cat);
  }

  /**
   * Searches for a transmit-name from the given root.
   * @param r The root Category to start the search from.
   * @param str The String to search for
   * @return The Category, if it is found.  If not, the closest ancestor 
   * Category object.
   **/

  protected Category stringToCategory(Category r, String str)
  {
    boolean found  = false;
    do 
      {
	Vector serviceCategories = root.getChildren();
	Enumeration e = serviceCategories.elements();
	while (e.hasMoreElements()) 
	  {
	    Category tc = (Category)e.nextElement();
	    if (str.startsWith(tc.transmitName))
	      {
		found = true;
		r = tc;
	      }
	  } 
      }
    while (found);
    return r;
  }
}



