package W3C.PICS;
import java.util.*;
import java.io.*;
import java.awt.*;

/**
 * Categories are the builiding blocks of Service. Category recursively parses the
 * necessary information from portion of application/pics-service.
 * Category has methods to create user interface for entering label and filter,
 * and a SingleLabel object as well.
 *
 * @author Ching Law
 * @see W3C.PICS.Service
 * @see W3C.PICS.Enum
 */
public class Category
{
     static public final int SMALL=-1;
     static public final int MEDIUM=0;
     static public final int BIG=1;
     static public final int VERYBIG=2;

     public Category()
     {
      enumlist=new Vector();
      categorylist=new Vector();
     }

     /**
      * Constructs a Category from a PICSTokenizer
      * @param cat The parent category with attibutes to be inherited
      */
     public Category(PICSTokenizer PT, Category cat) throws PICSException, IOException
     {

      enumlist=new Vector();
      categorylist=new Vector();

        if (cat.getTransmitas()!="")
           transmitas=cat.getTransmitas() + "/";
        max=cat.getMax();
        min=cat.getMin();
        multivalue=cat.isMultivalue();
        unordered=cat.isUnordered();
        integer=cat.isInteger();
        labelonly=cat.isLabelonly();

            //Get Transmit-as
            //
        int type=PT.nextPair("transmit-as",'"');
        if (type==PICSTokenizer.T_CLOSEPAREN)
            throw new PICSException("Unexpected ) ");
        transmitas+=PT.sval;

     loop: while (true)
     {
        switch (PT.nextCategoryOption())
        {
            case PICSTokenizer.T_CLOSEPAREN:
                CheckInteger();
                return;
            case PICSTokenizer.T_CATEGORY:
                break loop;
            case PICSTokenizer.T_ENUM:
                enumlist.addElement(new Enum(PT));
                break;
            case PICSTokenizer.T_MAX:
                max=PT.nval;
                break;
            case PICSTokenizer.T_MIN:
                min=PT.nval;
                break;
            case PICSTokenizer.T_BOOLOPTION:
                 if (PT.option.equals("integer"))
                        integer=PT.bval;
                 else if (PT.option.equals("multivalue"))
                        multivalue=PT.bval;
                 else if (PT.option.equals("label-only"))
                        labelonly=PT.bval;
                 else if (PT.option.equals("unordered"))
                        unordered=PT.bval;
                 else
                        throw new RuntimeException("Error at category option");
                 break;
            case PICSTokenizer.T_EXTENSION:
                break;
            case PICSTokenizer.T_OPTIONPAIR:
                if (PT.option.equals("icon"))
                        icon=PT.sval;
                else if (PT.option.equals("description"))
                        description=PT.sval;
                else if (PT.option.equals("name"))
                        name=PT.sval;
                else
                        throw new RuntimeException("Error at Category option");
                break;
            default:
                throw new RuntimeException("Error: Unhandled case of Category");
        }
     }

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

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

        CheckInteger();
     }

    /**
        Verify that the values in the Enumlist satisfy the integer restriction
    */

     private void CheckInteger() throws PICSException
     {
        if (integer)
            {for (int i=0;i<enumlist.size();i++)
               {
                 double v=((Enum)enumlist.elementAt(i)).getValue();
                 if (v!=Math.floor(v))
                    throw new PICSException("Integer Error");
               }
           }
     }

    /**
        Returns a description of the Category.
        Note that the description is not according the syntax of application/pics-service
    */
     public String toString()
     {
       String categorystring="";
       for (int i=0; i<categorylist.size();i++)
          categorystring+=categorylist.elementAt(i).toString();

       String enumstring="";
       for (int i=0; i<enumlist.size();i++)
          enumstring+=enumlist.elementAt(i).toString();


      return "\n*** Category ***\n" +
             "transmit-as: " + transmitas + "\n" +
             "description: " + description +"\n" +
             "icon: " + icon+ "\n" +
             "name: " + name+"\n" +
             "integer: "+ integer +"\n"+
             "label-only: " + labelonly + "\n" +
             "max: " + max + "\n"+
             "min: "+  min  +"\n"+
             "multivalue: "+ multivalue +"\n"+
             "unordered: "+ unordered +"\n" +
             (enumlist.size()==0 ? "" : "\nLabels:\n" + enumstring)+
             (categorylist.size()==0 ? "" : "Sub-categories:\n" + categorystring);


     }

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

    /**
        Add Panels to the Vector panellist.
    */
     void putPanels(Vector panellist, TextComponent DText, int type,boolean ListForLabels,boolean SimpleFiltering) //DText -> TextComponent for putting description Text
     {
        if (categorylist.size()>0)
            {for (int i=0;i<categorylist.size();i++)
                ((Category)categorylist.elementAt(i)).putPanels(panellist, DText, type, ListForLabels,SimpleFiltering);}
        else
            panellist.addElement(type==Service.U_LABEL ? newLabelPanel(DText,ListForLabels) : newFilterPanel(DText,SimpleFiltering));
     }

    /**
        Returns a new Panel with the appropriate User Interface for
        creating Ratings. DText is where description should be displayed
     */
     private Panel newFilterPanel(TextComponent DText,boolean SimpleFiltering)
     {
        widgets=new Vector();
        p=new Panel();
        p.setLayout(new BorderLayout());

        Panel TitlePanel=new Panel();
        TitlePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
        TitlePanel.add(new Label(transmitas + " - " + name,Label.LEFT));

        p.add("North",TitlePanel);
        Panel SouthPanel=new Panel();


        //CheckBoxes
        if (enumlist.size()>0)
           {

            SouthPanel.setLayout(new FlowLayout());

/*            if (multivalue)  //Checkbox
               {
                for (int i=0;i<enumlist.size();i++)
                    {
                        widgets.addElement(new DCheckbox(
                            ((Enum)enumlist.elementAt(i)).getName(),
                            ((Enum)enumlist.elementAt(i)).getDescription(),DText));
                        SouthPanel.add((DCheckbox)widgets.elementAt(i));
                    }

               }*/

               if (!multivalue && SimpleFiltering)
               {
                 for (int i=0;i<enumlist.size();i++)
                    {
                        RankedCheckbox RCheckbox=new RankedCheckbox(((Enum)enumlist.elementAt(i)).getName(),
                                                                    ((Enum)enumlist.elementAt(i)).getDescription(),
                                                                    DText,
                                                                    i,
                                                                    widgets);
                        SouthPanel.add(RCheckbox);
                        widgets.addElement(RCheckbox);
                    }
               }
               else
//                 Vector Checkboxes=new Vector();
                {
                  Vector ACheckboxes=new Vector();//checkboxes for allowing
                  Vector BCheckboxes=new Vector();//checkboxes for blocking

                  for (int i=0;i<enumlist.size();i++)
                    {
                        FilterCheckbox AFCheckbox=new FilterCheckbox("",
                                                                    ((Enum)enumlist.elementAt(i)).getDescription(),
                                                                     DText,
                                                                     i,
                                                                     false,
                                                                     ACheckboxes,
                                                                     BCheckboxes);
                        FilterCheckbox BFCheckbox=new FilterCheckbox(((Enum)enumlist.elementAt(i)).getName(),
                                                                    ((Enum)enumlist.elementAt(i)).getDescription(),
                                                                     DText,
                                                                     i,
                                                                     true,
                                                                     BCheckboxes,
                                                                     ACheckboxes);

                        Panel FCPanel=new Panel();
                        FCPanel.setLayout(new FlowLayout());
                        FCPanel.add(AFCheckbox);
                        FCPanel.add(BFCheckbox);
                        SouthPanel.add(FCPanel);
                       // SouthPanel.add(AFCheckbox);
                       // SouthPanel.add(BFCheckbox);
                        ACheckboxes.addElement(AFCheckbox);
                        BCheckboxes.addElement(BFCheckbox);
                    }
                        widgets.addElement(ACheckboxes);
                        widgets.addElement(BCheckboxes);
                }
           }

         //Scrollbars
         else if  ((min!=Double.NEGATIVE_INFINITY) && (max!=Double.POSITIVE_INFINITY))
           {
            double mid= (max + min) /2;
            if (integer)
                mid=Math.floor(mid);

            Panel ScrollsPanel=new Panel();

            List RangeList=new List(4,false);

            //Minimum ScrollPanel
            Panel minScrollPanel=new Panel();
            minScrollPanel.setLayout(new BorderLayout());
            TextField minvalueField=new TextField(mid + "");
            Panel minvaluePanel=new Panel();
            minvaluePanel.setLayout(new FlowLayout());
            minvaluePanel.add(minvalueField);


            minScrollPanel.add("West", new Label(min + ""));
            minScrollPanel.add("East", new Label(max + ""));

            Panel minCenterPanel=new Panel();
            minCenterPanel.add(new Label("Min: "));
            minCenterPanel.add(minvaluePanel);
            minScrollPanel.add("Center", minCenterPanel);

            VScrollbar minsb;
                minsb=new VScrollbar(Scrollbar.HORIZONTAL,(int)mid,0,(int)min,(int)max,minvalueField,integer);
                minsb.setPageIncrement((int)(max-min)/10);
                minsb.setLineIncrement(1);

            minScrollPanel.add("South", minsb);


            //Maximum ScrollPanel
            Panel maxScrollPanel=new Panel();
            maxScrollPanel.setLayout(new BorderLayout());
            TextField maxvalueField=new TextField(mid + "");
            Panel maxvaluePanel=new Panel();
            maxvaluePanel.setLayout(new FlowLayout());
            maxvaluePanel.add(maxvalueField);

            maxScrollPanel.add("West", new Label(min + ""));
            maxScrollPanel.add("East", new Label(max + ""));

            Panel maxCenterPanel=new Panel();
            maxCenterPanel.add(new Label("Max:"));
            maxCenterPanel.add(maxvaluePanel);

            maxScrollPanel.add("Center", maxCenterPanel);

            VScrollbar maxsb;
                maxsb=new VScrollbar(Scrollbar.HORIZONTAL,(int)mid,0,(int)min,(int)max,maxvalueField,integer);
                maxsb.setPageIncrement((int)(max-min)/10);
                maxsb.setLineIncrement(1);

            maxScrollPanel.add("South", maxsb);


            ScrollsPanel.setLayout(new GridLayout(1,2));
            ScrollsPanel.add(minScrollPanel);

            ScrollsPanel.add(maxScrollPanel);

            Panel largeScrollPanel=new Panel();

            //The Add and Remove Buttons
            Panel buttonPanel=new Panel();
            AddButton AButton=new AddButton(RangeList,minvalueField,maxvalueField);
            DelButton RButton=new DelButton(RangeList);

            buttonPanel.setLayout(new GridLayout(2,1));
            buttonPanel.add("North",AButton);
            buttonPanel.add("South",RButton);

            //List Panel
            Panel ListPanel=new Panel();
            ListPanel.setLayout(new BorderLayout());
            ListPanel.add("West",RangeList);
            ListPanel.add("Center",buttonPanel);


            GridBagLayout gbl=new GridBagLayout();
            SouthPanel.setLayout(gbl);
            GridBagConstraints gbc1=new GridBagConstraints();
            gbc1.gridwidth=1;
            gbc1.gridheight=1;
            gbl.setConstraints(RangeList,gbc1);
            SouthPanel.add(RangeList);

            GridBagConstraints gbc2=new GridBagConstraints();
            gbc2.gridwidth=1;
            gbc2.gridheight=1;
            gbl.setConstraints(buttonPanel,gbc2);
            SouthPanel.add(buttonPanel);

            GridBagConstraints gbc3=new GridBagConstraints();

            gbc3.gridwidth=5;
            gbc3.gridheight=1;
            gbl.setConstraints(ScrollsPanel,gbc3);
            SouthPanel.add(ScrollsPanel);

     //       SouthPanel.add("West",ListPanel);
     //       SouthPanel.add("Center",ScrollsPanel);

            widgets.addElement(RangeList);

           }
         p.add("Center",SouthPanel);
         return p;

     }


    /**
        Returns a new Panel with the appropriate User Interface for
        creating Ratings. DText is where description should be displayed
     */
     private Panel newLabelPanel(TextComponent DText,boolean ListForLabels)
     {
        widgets=new Vector();
        p=new Panel();
        p.setLayout(new BorderLayout());

        Panel TitlePanel=new Panel();
        TitlePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
        TitlePanel.add(new Label(transmitas + " - " + name,Label.LEFT));

        p.add("North",TitlePanel);
        Panel SouthPanel=new Panel();


        //CheckBoxes
        if (enumlist.size()>0)
           {

            SouthPanel.setLayout(new FlowLayout());

            if (multivalue)  //Checkbox
               {
                for (int i=0;i<enumlist.size();i++)
                    {
                        widgets.addElement(new DCheckbox(((Enum)enumlist.elementAt(i)).getName(),
                        ((Enum)enumlist.elementAt(i)).getDescription(),DText));
                        SouthPanel.add((DCheckbox)widgets.elementAt(i));
                    }

               }
             else     // Choice List
                if (labelonly && ListForLabels)
                    {
                        widgets.addElement(new DChoice(DText,enumlist));
                        SouthPanel.add((DChoice)widgets.elementAt(0));
                    }
                else   //CheckboxGroup
                  {
                    CheckboxGroup g=new CheckboxGroup();
                    for (int i=0;i<enumlist.size();i++)
                      {
                        widgets.addElement(new DCheckbox(((Enum)enumlist.elementAt(i)).getName(),g,
                        i==0 ? true : false,((Enum)enumlist.elementAt(i)).getDescription(),DText ));
                        SouthPanel.add((DCheckbox)widgets.elementAt(i));
                      }

                   //OtherCheckboxPanel
                    if (!labelonly)
                      {
                          Panel OtherCheckboxPanel=new Panel();
                          OtherCheckboxPanel.setLayout(new BorderLayout());
                          TextField OtherField=new TextField(5);
                          OtherCheckboxPanel.add("East",OtherField);
                          OtherCheckbox OCheckbox=new OtherCheckbox(g,false,"Please enter a value from " + min + " to " + max,DText,OtherField);
                          OtherCheckboxPanel.add("West",OCheckbox);
                          SouthPanel.add(OtherCheckboxPanel);
                          widgets.addElement(OCheckbox);
                      }
                  }
           }

         //Scrollbars
         else if  ((min!=Double.NEGATIVE_INFINITY) && (max!=Double.POSITIVE_INFINITY))
           {
            SouthPanel.setLayout(new BorderLayout());
            double mid= (max + min) /2;
            if (integer)
                mid=Math.floor(mid);

            Panel ScrollPanel=new Panel();
            ScrollPanel.setLayout(new BorderLayout());
            TextField valueField=new TextField(mid + "",5);
            Panel valuePanel=new Panel();
            valuePanel.setLayout(new FlowLayout());
            valuePanel.add(valueField);

            ScrollPanel.add("West", new Label(min + ""));
            ScrollPanel.add("East", new Label(max + ""));
            ScrollPanel.add("Center", valuePanel);

            VScrollbar sb;

                sb=new VScrollbar(Scrollbar.HORIZONTAL,(int)mid,0,(int)min,(int)max,valueField,integer);
                sb.setPageIncrement((int)(max-min)/10);
                sb.setLineIncrement(1);

            ScrollPanel.add("South", sb);
            SouthPanel.add("Center",ScrollPanel);

            widgets.addElement(sb);
            widgets.addElement(valueField);

           }
         p.add("Center",SouthPanel);
         return p;

     }


   /**
    * Put Rating(s) on SL according to the current state of user interface widgets.
    */
     public void putRating(SingleLabel SL)
     {
        if (categorylist.size()>0)
           { for (int i=0;i<categorylist.size();i++)
                ((Category)categorylist.elementAt(i)).putRating(SL);
             return;
           }
//        if (widgets.size()==0) return new Rating(transmitas);
        int n=enumlist.size();
        if (n>0)  //with labels
         {
          if (multivalue)
            {Rating r=new Rating(transmitas);
             for (int i=0;i<n;i++)
             {
              if (((Checkbox)widgets.elementAt(i)).getState())
                r.addValue(((Enum)enumlist.elementAt(i)).getValue());
             }
             SL.addRating(r);
             return;
            }
          else     // Choice List
              if (widgets.elementAt(0) instanceof DChoice)
                 {
                   SL.addRating(new Rating(transmitas,
                     ((Enum)enumlist.elementAt(((DChoice)widgets.elementAt(0)).getSelectedIndex())).getValue()       ));
                 }
          else //just changed
             { for (int i=0;i<n;i++)
                if (((Checkbox)widgets.elementAt(i)).getState())
                  { SL.addRating(new Rating(transmitas,((Enum)enumlist.elementAt(i)).getValue()));
                    return;
                  }
                SL.addRating(new Rating(transmitas, ((OtherCheckbox)widgets.elementAt(n)).getValue()));
             }
         }
        else
         if (widgets.elementAt(0) instanceof VScrollbar)
            {
              VScrollbar vs=(VScrollbar)widgets.elementAt(0);
              SL.addRating(new Rating(transmitas,vs.getdValue()));
              return;
            }
     }


   /**
    * Put Range(s) on the Filter according to the current state of user
    * interface widgets.
    * @see W3C.PICS.Range
    * @see W3C.PICS.Filter
    */
     public void putRange(Filter FL)
     {
        if (categorylist.size()>0)
           { for (int i=0;i<categorylist.size();i++)
                ((Category)categorylist.elementAt(i)).putRange(FL);
             return;
           }
        if (widgets.elementAt(0) instanceof RankedCheckbox)  //with labels
         {
            Range r=new Range(transmitas);
            for (int i=0;i<enumlist.size();i++)
            {
             if (((Checkbox)widgets.elementAt(i)).getState())
                r.addAllowValue(((Enum)enumlist.elementAt(i)).getValue());
             else
                r.addBlockValue(((Enum)enumlist.elementAt(i)).getValue());
            }
            FL.addRange(r);
            return;
         }
       else
         if (widgets.elementAt(0) instanceof Vector)
            {
            Range r=new Range(transmitas);
            Vector ACheckboxes=(Vector)widgets.elementAt(0);
            Vector BCheckboxes=(Vector)widgets.elementAt(1);

            for (int i=0;i<enumlist.size();i++)
            {
             if (((Checkbox)ACheckboxes.elementAt(i)).getState())
                r.addAllowValue(((Enum)enumlist.elementAt(i)).getValue());
             if (((Checkbox)BCheckboxes.elementAt(i)).getState())
                r.addBlockValue(((Enum)enumlist.elementAt(i)).getValue());
            }
            FL.addRange(r);
            return;

            }

/*        else     // Choice List is not allowed
              if (widgets.elementAt(0) instanceof DChoice)
                 {
                   SL.addRating(new Rating(transmitas,
                     ((Enum)enumlist.elementAt(((DChoice)widgets.elementAt(0)).getSelectedIndex())).getValue()       ));
                 }

          else
             { for (int i=0;i<n;i++)
                if (((Checkbox)widgets.elementAt(i)).getState())
                  { FL.addRange(new Range(transmitas,((Enum)enumlist.elementAt(i)).getValue()));
                    return;
                  }
             }*/
       else
         if (widgets.elementAt(0) instanceof List)
            {
              Range r=new Range(transmitas);
              List RangeList=(List)widgets.elementAt(0);
              for (int i=0;i<RangeList.countItems();i++)
                {
                 String s=RangeList.getItem(i);
                 StringTokenizer ST=new StringTokenizer(s," -");
                 double min=Double.valueOf(ST.nextToken()).doubleValue();
                 double max=Double.valueOf(ST.nextToken()).doubleValue();
                 r.addRangeValue(new RangeValue(min,max));
                }
              FL.addRange(r);
              return;
            }
/*       else
         if (widgets.elementAt(0) instanceof VScrollbar)
            {
              VScrollbar vs_min=(VScrollbar)widgets.elementAt(0);
              VScrollbar vs_max=(VScrollbar)widgets.elementAt(1);
              Range r=new Range(transmitas);
              r.addRangeValue(new
              FL.addRange(new Range(transmitas,vs_min.getdValue(),vs_max.getdValue()));
              return;
            }*/
     }

     public void setRange(Filter fil)
     {
        if (categorylist.size()>0)
           { for (int i=0;i<categorylist.size();i++)
                ((Category)categorylist.elementAt(i)).setRange(fil);
             return;
           }
        Range r=fil.nextRange();
        Vector allowValuelist=r.getAllowValuelist();
        Vector blockValuelist=r.getBlockValuelist();
        Vector rangeValuelist=r.getRangeValuelist();

        System.out.println(allowValuelist.size());
        if (widgets.elementAt(0) instanceof RankedCheckbox)  //with labels
         {
            //Offset: Assuming values in an Enumlist are in increasing sequential order
            int offset=-(int)((Enum)enumlist.elementAt(0)).getValue();
            for (int i=0;i<allowValuelist.size();i++)
                ((Checkbox)widgets.elementAt(((Double)allowValuelist.elementAt(i)).intValue()+offset )).setState(true);
            for (int i=0;i<blockValuelist.size();i++)
                ((Checkbox)widgets.elementAt(((Double)blockValuelist.elementAt(i)).intValue()+offset )).setState(false);
            return;
         }
       else
         if (widgets.elementAt(0) instanceof Vector)
            {
            int offset=-(int)((Enum)enumlist.elementAt(0)).getValue();
            Vector ACheckboxes=(Vector)widgets.elementAt(0);
            Vector BCheckboxes=(Vector)widgets.elementAt(1);

            for (int i=0;i<allowValuelist.size();i++)
                ((Checkbox)ACheckboxes.elementAt(((Double)allowValuelist.elementAt(i)).intValue()+offset )).setState(true);
            for (int i=0;i<blockValuelist.size();i++)
                ((Checkbox)BCheckboxes.elementAt(((Double)blockValuelist.elementAt(i)).intValue()+offset )).setState(true);

            return;

            }

/*        else     // Choice List is not allowed
              if (widgets.elementAt(0) instanceof DChoice)
                 {
                   SL.addRating(new Rating(transmitas,
                     ((Enum)enumlist.elementAt(((DChoice)widgets.elementAt(0)).getSelectedIndex())).getValue()       ));
                 }

          else
             { for (int i=0;i<n;i++)
                if (((Checkbox)widgets.elementAt(i)).getState())
                  { FL.addRange(new Range(transmitas,((Enum)enumlist.elementAt(i)).getValue()));
                    return;
                  }
             }*/
       else
         if (widgets.elementAt(0) instanceof List)
            {
              List RangeList=(List)widgets.elementAt(0);
              RangeList.clear();
              for (int i=0;i<rangeValuelist.size();i++)
                {
                    RangeValue rv=(RangeValue)rangeValuelist.elementAt(i);
                    RangeList.addItem(rv.getMin() + " - " + rv.getMax());
                }
              return;
            }
     }

    /**
     * Return the estimation of the size of the panel (user interface area)
     * required to contain the widgets.
     */
     public int panelSize()
     {
      if (enumlist.size()==0) return SMALL;
      if (enumlist.size()<=5) return MEDIUM;
      if (enumlist.size()>5 && enumlist.size()<8) return BIG;
      return VERYBIG;
     }


     public String getIcon()
     {return icon;}
     public String getDescription()
     {return description;}
     public String getTransmitas()
     {return transmitas;}
     public String getName()
     {return name;}


     public double getMax()
     {return max;}
     void setMax(double n)
     {max=n;}

     public double getMin()
     {return min;}
     void setMin(double n)
     {min=n;}

     public boolean isMultivalue()
     {return multivalue;}
     void setMultivalue(boolean b)
     {multivalue=b;}

     public boolean isUnordered()
     {return unordered;}
     void setUnordered(boolean b)
     {unordered=b;}


     public boolean isLabelonly()
     {return labelonly;}
     void setLabelonly(boolean b)
     {labelonly=b;}


     public boolean isInteger()
     {return integer;}
     void setInteger(boolean b)
     {integer=b;}


     public Vector getEnumlist()
     {return enumlist;}
     private String icon="";
     private String description="";
     private String transmitas="";
     private String name="";

     //Defaultable options with default values
     private double max=Double.POSITIVE_INFINITY;
     private double min=Double.NEGATIVE_INFINITY;
     private boolean multivalue=false;
     private boolean integer=false;
     private boolean labelonly=false;
     private boolean unordered=false;

     private Vector enumlist;
     private Vector categorylist;
     private Vector widgets;

     private Panel p;
}


/**
    Choice List with automatic description updates (at DText)
*/
class DChoice extends Choice
{
 public DChoice(TextComponent DText,Vector enumlist)
 {
    for (int i=0;i<enumlist.size();i++)
    {
     addItem(((Enum)enumlist.elementAt(i)).getName());
    }
    this.enumlist=enumlist;
    DescriptionText=DText;
 }

 public boolean handleEvent(Event evt)
 {
  DescriptionText.setText(((Enum)enumlist.elementAt(getSelectedIndex())).getDescription());
  return super.handleEvent(evt);

 }

 private Vector enumlist;
 private TextComponent DescriptionText;

}

/**
DCheckbox is a check box with a private field TextComponent and a private field of description.
It setTexts the the TextComponent with the description when it receives an event.
*/
class DCheckbox extends Checkbox
{
 public DCheckbox(String label,String description,TextComponent DText)
 {
    super(label);
    this.description=description;
    DescriptionText=DText;
 }

 public DCheckbox(String label, CheckboxGroup group, boolean state, String description,TextComponent DText)
 {
    super(label,group,state);
    this.description=description;
    DescriptionText=DText;
 }
 public boolean handleEvent(Event evt)
 {
  DescriptionText.setText(description);
  return super.handleEvent(evt);

 }

 private String description;
 private TextComponent DescriptionText;
}


/**
Vscrollbar is a Scrollbar with a private Label. It will set the Label with the Vscrollbar's value when that's
changed.
Integer: true if the value is an integer.
         false if one decimal point at the label is required.
         Note that getValue() is multiplied by 10 if Integer is false.
*/
class VScrollbar extends Scrollbar
{
 public VScrollbar(int orientation, int  value,int  visible, int  minimum, int  maximum, TextComponent l, boolean integer)
   {
     super(orientation);
     if (!integer)
        {value*=10;
         minimum*=10;
         maximum*=10;
        }
     setValues(value,visible,minimum,maximum);

     valueText=l;
     this.integer=integer;
   }

  public boolean handleEvent(Event evt)
  {
   if (evt.id== Event.SCROLL_ABSOLUTE || evt.id == Event.SCROLL_LINE_DOWN ||
       evt.id==Event.SCROLL_LINE_UP || evt.id==Event.SCROLL_PAGE_DOWN ||
       evt.id==Event.SCROLL_PAGE_UP )
       {
        valueText.setText(/*(integer? getValue() : getValue()/10.0)*/ getdValue()  +"");
       }
    return super.handleEvent(evt);
  }
  public boolean isInteger()
  {return integer;}

  public double getdValue()
  {
   if (integer) return getValue();
   else return getValue()/10.0;
  }

  private boolean integer;
  private TextComponent valueText;

}

/**
 *  OtherCheckbox is a DCheckbox containing a TextField. When it's selected, the user
 *  can enter a value in the TextField.
 */
class OtherCheckbox extends DCheckbox
{
    public OtherCheckbox(String Description,TextComponent DText,TextField TF)
    {
      super("Other:",Description,DText);
      OtherField=TF;
      OtherField.setEditable(false);
    }

    public OtherCheckbox(CheckboxGroup g,boolean state ,String Description,TextComponent DText,TextField TF)
    {
      super("Other:",g,state, Description,DText);
      OtherField=TF;
      OtherField.setEditable(false);
    }

    public void setState(boolean state)
    {
        super.setState(state);
        if (getState())
            OtherField.setEditable(true);
        else OtherField.setEditable(false);
    }
    /**
     * @return The value of the associated text field in double
     */
    public double getValue()
    {
        try
        {
        return Double.valueOf(OtherField.getText()).doubleValue();
        }
        catch (Exception e)
        {return 0;}

    }

    TextField OtherField;
}
