package W3C.PICS;
import java.util.*;
import java.io.*;
import java.awt.*;
import java.net.URL;
import java.net.MalformedURLException;
/**
 * Service is the data abstraction of a application/pics-service
 * machine readable.
 * @see W3C.PICS.Category
 * @author Ching Law
 */
public class Service
{
  static public final int U_LABEL=1; //User Inferface for Label Creation
  static public final int U_FILTER=2;//      ...          Filter Creation

/**
 *  Constructs the Service object by parsing the input stream
 */
 public Service(InputStream ins) throws PICSException, IOException
 {
  int type;
  int catlevel=0;
  int paramlevel=0;
  boolean bName=false,bDescription=false,bIcon=false;

  PICSTokenizer PT=new PICSTokenizer(ins);

    Category DefaultCategory=new Category();
    PT.firstParen();
    PT.checkVersion();
    categorylist=new Vector();

    //Get Rating system
    type=PT.nextPair("rating-system",'"');
    if (type==PICSTokenizer.T_CLOSEPAREN)
       throw new PICSException("Unexpected ) ");
    ratingsystem=PT.sval;
    try
    {ratingsystemURL=new URL(ratingsystem);}
    catch (MalformedURLException e)
    {throw new PICSException("Malformed URL for ratingsystem");}

    //get rating service
    type=PT.nextPair("rating-service",'"');
    if (type==PICSTokenizer.T_CLOSEPAREN)
       throw new PICSException("Unexpected ) ");
    ratingservice=PT.sval;
    try
    {ratingserviceURL=new URL(ratingservice);}
    catch (MalformedURLException e )
    {throw new PICSException("Malformed URL for ratingservice");}



    //get Options
    while (true)
    {
        type=PT.nextServiceOption();
        if (type==PICSTokenizer.T_CLOSEPAREN)
            throw new PICSException("There must be a least one category");
        else if (type==PICSTokenizer.T_CATEGORY)
            break;
        else if (type==PICSTokenizer.T_DEFAULT)
          { boolean atleastone=false;
            while (true)
            {
              int t=PT.getDefaultableOption();
              if (t==PICSTokenizer.T_CLOSEPAREN)
                 if (!atleastone)
                    throw new PICSException("At least one option in default pair");
                 else break;
              if (PT.option.equals("integer"))
                        DefaultCategory.setInteger(PT.bval);
                 else if (PT.option.equals("multivalue"))
                        DefaultCategory.setMultivalue(PT.bval);
                 else if (PT.option.equals("label-only"))
                        DefaultCategory.setLabelonly(PT.bval);
                 else if (PT.option.equals("unordered"))
                        DefaultCategory.setUnordered(PT.bval);
                 else if (PT.option.equals("min"))
                        DefaultCategory.setMin(PT.nval);
                 else if (PT.option.equals("max"))
                        DefaultCategory.setMin(PT.nval);
                 else throw new PICSException("Invalid Default Option" + PT.option);
              atleastone=true;
            }
          }
        else if (type==PICSTokenizer.T_OPTIONPAIR)
        {
          if (PT.option.equals("name"))
            if (!bName)
                {
                 bName=true;
                 name=PT.sval;
                }
            else throw new PICSException("Duplicated name option");
          else if (PT.option.equals("description"))
            if (!bDescription)
                {
                 bDescription=true;
                 description=PT.sval;
                }
            else throw new PICSException("Duplicated description option");
          else if (PT.option.equals("icon"))
            if (!bIcon)
                {
                 bIcon=true;
                 icon=PT.sval;
                try
                    {iconURL=new URL(ratingserviceURL,icon);}
                catch (MalformedURLException e)
                    {throw new PICSException("Malformed URL for ratingservice icon");}

                }
            else throw new PICSException("Duplicated icon option");
          else throw new PICSException("Option Pair Error!!!");

          }

        else if  (type==PICSTokenizer.T_EXTENSION)
             ; // No extension implemented yet

        else throw new PICSException("Tokenizer return type Error!!!");
    }

    //************
    //Category List

    categorylist.addElement(new Category(PT,DefaultCategory));

    while (true)
    {
     type=PT.nextServiceOption();
     if (type==PICSTokenizer.T_CLOSEPAREN)
        break;
     if (type==PICSTokenizer.T_CATEGORY)
        categorylist.addElement(new Category(PT,DefaultCategory));
     else throw new PICSException("Option comes after the first Category");
    }

 }


/**
    Returns the number of Categories in the service
*/
 int noCategory()
 {
  int s=0;
  for (int i=0; i<categorylist.size();i++)
    s+=( (Category) categorylist.elementAt(i)).noCategory();
  return s;
 }


/**
   Put a set of User Interface widgets on the Container c. These widgets would be used
   to select the values of the categories of the Label to be created.

*/
 public void newInterface(Container c,int type,boolean ListForLabels,boolean SimpleFiltering)
 {
    uType=type;
    int n=noCategory();

    c.setLayout(new BorderLayout());
    //Header for Creating Label
    if (type==U_LABEL)
      {
        HeaderPanel=new LabelHeaderPanel();
        c.add("North",HeaderPanel);
      }

    //The TextArea for displaying descriptions when widgets (mainly checkbox) are selected
    TextArea DescriptionLabel=new TextArea(1,30);
    DescriptionLabel.setEditable(false);



    //The Panel for putting selection widgets
    Panel BodyPanel=new Panel();

    Vector PanelList=new Vector();
    for (int i=0;i<categorylist.size();i++)
    {
        ((Category)categorylist.elementAt(i)).putPanels(PanelList,DescriptionLabel,type,ListForLabels,SimpleFiltering);
    }

    int pagesize=4; //No. of categories per page
    int panelsize=((Category)categorylist.elementAt(0)).panelSize();
    if (panelsize==Category.SMALL)
        pagesize=5;
    else if (panelsize==Category.BIG)
        pagesize=3;
    else if (panelsize==Category.VERYBIG)
        pagesize=2;


    if (noCategory()<=pagesize)
        {
            BodyPanel.setLayout(new GridLayout(0,1));
            for (int i=0;i<noCategory();i++)
            {
               BodyPanel.add((Panel)PanelList.elementAt(i));
            }
        }
      else  //A vertical scrollbar is needed
        {
            Panel WidgetPanel=new Panel();
            BodyPanel.setLayout(new BorderLayout());



            PScrollbar PS=new PScrollbar(WidgetPanel,PanelList,Scrollbar.VERTICAL,pagesize);

            BodyPanel.add("East",PS);
            BodyPanel.add("Center",WidgetPanel);

        }
    c.add("Center",BodyPanel);
    c.add("South",DescriptionLabel);
 }


/**
 * Returns a SingleLabel according to the current selection of the User Interface
 * widgets.
 * @see W3C.PICS.SingleLabel
 */
 public SingleLabel getSingleLabel()
 {
       SingleLabel SL=new SingleLabel();
       SL.setFor(HeaderPanel.getFor());
       SL.setBy(HeaderPanel.getBy());
       SL.setGeneric(HeaderPanel.getGeneric());

       for (int i=0;i<categorylist.size();i++)
       {
         ((Category)categorylist.elementAt(i)).putRating(SL);
       }
    return SL;
 }
/**
 * Returns Filter according to the current selection of the User Interface
 * widgets.
 * @see W3C.PICS.Filter
 */

 public Filter getFilter()
 {
       Filter FL=new Filter(ratingsystem);

       for (int i=0;i<categorylist.size();i++)
       {
         ((Category)categorylist.elementAt(i)).putRange(FL);
       }
    return FL;
 }

/**
 * Set the user interface according to filter fil.
 *
 */
 public void setFilter(Filter fil)
 {
    if (!ratingsystem.equals(fil.getRatingsystem()))
        {
            System.out.println("rating system not match");
            System.out.println(ratingsystem);
            System.out.println(fil.getRatingsystem());
            return;
          }// Not the correct rating system
    if (uType!=U_FILTER)
        return;
    fil.reset();
    for (int i=0;i<categorylist.size();i++)
        {
         ((Category)categorylist.elementAt(i)).setRange(fil);
        }
 }



 public String getVersion()
 {return version;}
// String setVersion(String s)
// {version=s;}

 public String getRatingsystem()
 {return ratingsystem;}
// String setRatingsystem(String s)
// {ratingsystem=s;}


 public String getRatingservice()
 {return ratingservice;}
// String setRatingservice(String s)
// {ratingservice=s;}

 public String getIcon()
 {return icon;}
// String setIcon(String s)
// {icon=s;}

 public String getName()
 {return name;}
// String setName(String s)
// {
//  name=s;
// }
 public String getDescription()
 {return description;}


 public Vector getCategorylist()
 {return categorylist;}

 //For Testing with command line arguments
 public static void main(String[] args)
 {
  if (args.length<1)
  {
    System.out.println("Please supply the filename of the PICS-Service to be parsed.");
    return;
  }
  FileInputStream fis;

  try
  {fis=new FileInputStream(args[0]);
  }
  catch (FileNotFoundException e)
  {
   System.out.println("File not found");
   return;
  }
  catch (IOException e)
  {
    System.out.println("IO Exception");
    return;
  }

  try
  {
   Service ser=new Service(fis);
   System.out.print(ser.toString());

  }
   catch (PICSException e)
  {
    try
    {fis.close();} catch (IOException ei) {System.out.println("Closing error");}

    System.out.println("PICS Service Parsing Error:");
    System.out.println(e);
  }
  catch (IOException e)
  {System.out.println("IO error");
  }
 }

/**
    Returns a string representation of the Service object.

 */
 public String toString()
 {
    String categorystring="";
    for (int i=0;i<categorylist.size();i++)
       categorystring+=categorylist.elementAt(i).toString();

    return "PICS-Version: 1.1\n" +
           "Rating service: " + ratingservice + "\n" +
           "Rating system: " + ratingsystem + "\n" +
           "Icon: " + icon + "\n" +
           "Name: " + name + "\n" +
           "Description: " + description  + "\n" +
           categorystring;
 }

 boolean getListForLabels()
 {
  return ListForLabels;
 }

 void setListForLabels(boolean b)
 {
   ListForLabels=b;
 }

 public int getUType()
 {
  return uType;
 }

 private String version="";
 private String ratingservice="";
 private URL ratingserviceURL=null;
 private String ratingsystem="";
 private URL ratingsystemURL=null;
 private String icon="";
 private URL iconURL=null;
 private String name="";
 private String description=null;
 private Vector categorylist;
 private PICSTokenizer PT;
 private LabelHeaderPanel HeaderPanel=null;
 private boolean ListForLabels=true;

 private int uType=0;
}
