package w3c.pics.parser;

import java.util.*;
import java.io.StringBufferInputStream;

/**
 * A class that represents a single PICS label.
 **/

public class Label implements java.io.Serializable, Cloneable
{ 
  String serviceURL;
  Hashtable options = new Hashtable();
  Hashtable ratings = new Hashtable();
  Hashtable mextensions = new Hashtable();
  Hashtable oextensions = new Hashtable();
  
  /**
   * Creates a new, empty Label.
   **/

  public Label() { }

  /**
   * Returns the requested one of the Label'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);
  }

  /**
   * Changes the value of one of the Label's options.
   * @param optionName The option to change.
   * @param value The new value.
   **/

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

  /**
   * Adds a mandatory extension to this Label.
   * @param exName The name of the extension.
   * @param data The extension data.
   **/

  public void addMExtension(String exName, String data) {
    mextensions.put(exName, data);
  }

  /**
   * Adds an optional extension to this Label.
   * @param exName The name of the extension.
   * @param data The extension data.
   **/

  public void addOExtension(String exName, String data) {
    oextensions.put(exName, data);
  }

  /**
   * Returns the requested one of the Label's mandatory extensions.
   * @param exName The extension to return.
   * @return A String, the data of the mandatory extension <em>exName</em>
   **/
 
  public String getMExtension(String exName) {
    return (String)mextensions.get(exName);
  }

  /**
   * Returns the requested one of the Label's optional extensions.
   * @param exName The extension to return.
   * @return A String, the data of the optional extension <em>exName</em>
   **/

  public String getOExtension(String exName) {
    return (String)oextensions.get(exName);
  }

  /**
   * Returns the Service URL associated with this Label.
   * @return A String containing the Service URL.
   **/

  public String getService()
  {
    return serviceURL;
  }

  /**
   * Changes the Service URL associated with this Label.
   * @param serURL The new Service URL.
   **/

  public void setService(String serURL)
  {
    serviceURL = serURL;
  }

  /**
   * Returns all of the ratings in a Label.
   * @return A Hashtable mapping keys to Vectors of Rating objects.
   **/

  public Hashtable getRatings()
  {
    return ratings;
  }

  /**
   * Changes the rating(s) for a particular category.
   * @param name The name of the Category to change.
   * @param rating A Vector containing one or more Rating objects.
   **/

  public void setRating(String name, Vector rating)
  {
    ratings.put(name,rating);
  }

  /**
   * Returns the ratings for a particular category in this Label.
   * @param categoryName The category whose ratings are to be returned.
   * @return A Vector, containing the Rating objects for the category 
   * <em>categoryName</em>.
   **/

  public Vector getCategory(String categoryName)
  {
    return (Vector)ratings.get(categoryName);
  }

  /**
   * Returns a String containing the PICS 1.1 representation of this Label.
   * @return A String with a valid PICS 1.1 label representation of this 
   * Label object.
   **/

  public String toString()
  {
    String retval = new String("");
    retval+="(PICS-1.1 \"";
    retval+=serviceURL;
    retval+="\"\n";
    retval+="\tlabels \n";
    Enumeration oList = options.keys();
    while (oList.hasMoreElements()) {
      String oKey = oList.nextElement().toString();
      String oVal = options.get(oKey).toString();
      if (oKey.equals("generic"))
	retval+="\t\t"+oKey+" "+oVal+"\n";
      else
	retval+="\t\t"+oKey+" \""+oVal+"\"\n";
    }
    Enumeration mandList = mextensions.keys();
    while (mandList.hasMoreElements()) {
      String mandKey = mandList.nextElement().toString();
      String mandVal = mextensions.get(mandKey).toString();
      retval+="\t\textension (mandatory \""+mandKey+"\" "+mandVal+")\n";
    }
    Enumeration optList = oextensions.keys();
    while (optList.hasMoreElements()) {
      String optKey = optList.nextElement().toString();
      String optVal = oextensions.get(optKey).toString();
      retval+="\t\textension (optional \""+optKey+"\" "+optVal+")\n";
    }
    retval+="\t\tratings (";
    Enumeration rList = ratings.keys();
    while (rList.hasMoreElements()) {
      String catname = rList.nextElement().toString();
      Vector rvector = (Vector)ratings.get(catname);
      retval+=catname+" ";
      Enumeration vlist = rvector.elements();
      if (rvector.size()>1) 
	retval+="(";
      while (vlist.hasMoreElements()) {
	String singlerating = vlist.nextElement().toString();
	retval+=singlerating+" ";
      }
      if (rvector.size()>1)
	retval+=") ";
    }
    retval+="))\n";
    return retval;
  }

  private String sortExtensions() {
    String retval = new String("");
    String[] exnames = new String[mextensions.size()+oextensions.size()];
    Enumeration optList = oextensions.keys();
    Enumeration mandList = mextensions.keys();
    int i = 0;
    while (optList.hasMoreElements()) {
      exnames[i]=optList.nextElement().toString();
      i++;
    }
    while (mandList.hasMoreElements()) {
      exnames[i]=mandList.nextElement().toString();
      i++;
    }
    for (int j = exnames.length-1; j>-1; j--) {
      for (int k = 0; k<j; k++) {
	if (exnames[k].compareTo(exnames[k+1])>0) {
	  String temp = exnames[k];
	  exnames[k]=exnames[k+1];
	  exnames[k+1]=temp;
	}
      }
    }
    for (int l = 0; l<exnames.length; l++) {
      if ((oextensions.get(exnames[l]))!=null) {
	retval += "extension ( optional \""+exnames[l]+"\" "+
	  oextensions.get(exnames[l])+") ";
      }
      else {
	retval += "extension ( mandatory \""+exnames[l]+"\" "+
	  mextensions.get(exnames[l])+") ";
      }
    }
    return retval;
  }

  /**
   * Returns a String containing the canonical PICS 1.1 representation of 
   * this Label, suitable for signing.
   * @return A String with a valid canonicalized PICS 1.1 label 
   * representation of this Label object.
   **/

  public String toDsigString() {
    String retval = new String("");
    retval+="( PICS-1.1 \"";
    retval+=serviceURL;
    retval+="\" l ";
    String[] optionnames = new String[options.size()+1];
    Enumeration olist = options.keys();
    int i = 0;
    optionnames[i] = new String("extension");
    i = 1;
    while (olist.hasMoreElements()) {
      optionnames[i]=(String)olist.nextElement();
      i++;
    }
    // optionnames[i]= new String("extension");
    // sort array 
    for (int j = optionnames.length-1; j>-1; j--) {
      for (int k = 0; k<j; k++) {
	// System.out.println("j"+j+" k"+k);
	// System.out.println("k: "+optionnames[k]+" k+1: "+optionnames[k+1]);
	if (optionnames[k].compareTo(optionnames[k+1])>0) {
	  String temp = optionnames[k];
	  optionnames[k]=optionnames[k+1];
	  optionnames[k+1]=temp;
	  /* System.out.println("Switched "+optionnames[k+1]+" with "+
			     optionnames[k]); */
	}
      }
    }
    for (int l = 0; l<optionnames.length; l++) {
      if (!optionnames[l].equals("extension")) {
	if (optionnames[l].equals("generic")) {
	  retval+=optionnames[l]+" "+options.get(optionnames[l]).toString()
	    +" ";
	}
	else {
	  retval+=optionnames[l]+" \""+options.get(optionnames[l]).toString()
	    +"\" ";
	}
      }
      else {
	if ((oextensions.size()!=0) || (mextensions.size()!=0)) {
	  retval += sortExtensions();
	}
      }
    }
    retval+="r ( ";
    Enumeration rlist = ratings.keys();
    String[] ratlist = new String[ratings.size()];
    int j = 0;
    while (rlist.hasMoreElements()) {
      ratlist[j] = (String)rlist.nextElement();
      System.out.println("ratlist"+j+": "+ratlist[j]);
      j++;
    }
    for (int k = ratlist.length-1; k>-1; k--) {
      for (int m = 0; m<k; m++) {
	if (ratlist[m].compareTo(ratlist[m+1])>0) {
	  String temp = ratlist[m];
	  ratlist[m]=ratlist[m+1];
	  ratlist[m+1]=temp;
	}
      }
    }
    for (int n = 0; n<ratlist.length; n++) {
      String catname = ratlist[n];
      Vector rvector = (Vector)ratings.get(catname);
      retval+=catname+" ";
      Enumeration vlist = rvector.elements();
      if (rvector.size()>1)
	retval+="( ";
      while (vlist.hasMoreElements()) {
	String singlerating = ((Rating)vlist.nextElement()).toDsigString();
	retval+=singlerating+" ";
      }
      if (rvector.size()>1) 
	retval+=") ";
    }
    retval+=") )";
    return retval;
  }

  void setRatings(Hashtable ratings)
  {
    this.ratings = ratings;
  }  
  
}
