import java.applet.Applet;
import java.awt.*;

import java.util.*;

/** Just a catch-all for handy utility functions... **/

public class Util 
{

  public static String getVersion () { return "$Id: Util.java,v 1.15 1998/10/13 15:38:21 mhirsch Exp $"; }

   public static Dialog getDialog(Component c) 
   {
      if (c instanceof Dialog)
         return (Dialog) c;

      while ((c = c.getParent()) != null) 
      {
         if (c instanceof Dialog)
            return (Dialog) c;
      }
      return null;
   }
   public static Frame getFrame(Component c) 
   {
      if (c instanceof Frame)
         return (Frame) c;

      while ((c = c.getParent()) != null) 
      {
         if (c instanceof Frame)
            return (Frame) c;
      }
      return null;
   }
   public static Applet getApplet(Component c) 
   {
      if (c instanceof Applet)
         return (Applet) c;

      while ((c = c.getParent()) != null) 
      {
         if (c instanceof Applet)
            return (Applet) c;
      }
      return null;
   }

/** Added this one for STOPCL.
 * Given the name of an image file,
 * first try to find it where we keep such files,
 * otherwise try in current user directory,
 * return the image if possible,
 * null if both fail.
 * @param imageName -- the Name of the image (complete with extension)
 * @return the loaded Image or null.
 ** Completely different for Applets,
 * they cannot do System.getProperty,
 * and they cannot read from the local file system,
 * but the Applet instance (this) has a getImage () method.
 * They do this if fname is in same place as the html page --
 * Image img = getImage (getDocumentBase (), fname);
 * or this if fname is in same place as the class files --
 * Image img = getImage (getCodeBase (), fname);
 *
 */

  public static Image find_image (String imageName) {

      String iconDir;
      String file_sep = System.getProperty("file.separator");

      if (null == System.getProperty("STOPCL_HOME"))
         iconDir = System.getProperty("user.dir");
      else 
      {
         String homedir = System.getProperty("STOPCL_HOME");
         iconDir = homedir + file_sep + "data" + file_sep + "Icons";
      }

      return Toolkit.getDefaultToolkit ().getImage(iconDir + file_sep + imageName);
  }

/** More capable version of Graphics.draw3DRect () method,
 * this allows line thickness other than one pixel,
 * and draws either inside or outside the stated boundaries.
 * @param g -- Graphics context for the draw operations.
 * @param BC -- Border Color, will be shifted brighter and darker.
 * @param x -- x coordinate of top left corner.
 * @param y -- y coordinate of top left corner.
 * @param width -- width of rectangle.
 * @param height -- height of rectangle.
 * @param Thickness -- Thickness  of rectangle.
 * @param Outside -- true for rectangle Outside stated boundaries.
 * @param Raised -- true for Raised rectangle.
 */

    public static void paint3DRect (Graphics g, Color BC, int x, int y, int width, int height, int Thickness, boolean Outside, boolean Raised) {

	if (Outside) {
	    x -= Thickness;
	    y -= Thickness;
	    width += (2*Thickness);
	    height += (2*Thickness);
	}

// Top and Left

        if (Raised)
            g.setColor (BC.brighter ());
	else
            g.setColor (BC.darker ());

        for(int ii=0; ii < Thickness; ++ii) {
            g.drawLine (x+ii, y+ii, x+width-ii, y+ii);
            g.drawLine (x+ii, y+ii, x+ii, y+height-ii);
        }
        
// Bottom and Right

	x--;
	y--;

	if (Raised)
            g.setColor (BC.darker ());
	else
            g.setColor (BC.brighter ());

        for(int ii=0; ii < Thickness; ++ii) {
	    g.drawLine (x+ii, y+height-ii, x+width-ii, y+height-ii);
	    g.drawLine (x+width-ii, y+ii, x+width-ii, y+height-ii);
        }
    }

   public static void waitForImage(Component component, Image image) 
   {
      MediaTracker tracker = new MediaTracker(component);
      try 
      {
         tracker.addImage(image, 0);
         tracker.waitForID(0);
      }
      catch(InterruptedException e) { e.printStackTrace(); }
   }
   public static void stretchImage(Component component, Graphics g, Image image)
   {
      Dimension sz = component.getSize();
      waitForImage(component, image);
      g.drawImage(image, 0, 0, sz.width, sz.height, component);
   }
   public static void setCursor(int cursor, Component component) 
   {
      component.setCursor(Cursor.getPredefinedCursor(cursor));
   }

/** Add the given string to the list in alphabetical ascending order.
 */
    public static void addToListSorted(List list, String str)
    {
        addToListSorted(list, str, false);
    }

/** Add the given string to the list in alphabetical ascending order.
 * Make it selected if so specified.
 */
    public static void addToListSorted(List list, String str, boolean sel)
    {
        int index;

        for (index = 0; index < list.getItemCount(); index++)
        {
            if (str.compareTo(list.getItem(index)) < 0)
            {
                list.addItem(str, index);
                if (sel)
		   list.select(index);
                list.makeVisible(index);

                return;
            }
        }

        // If we get this far, just add the item at the end of the list.

        index = list.getItemCount() - 1;
        list.addItem(str, -1);
        if (sel)
	   list.select(index);
        list.makeVisible(index);
    }

/** Move the SelectedItem up or down in the List.
 * Cannot move up if the SelectedItem is first,
 * or down if the SelectedItem is last.
 * Make this Item again the SelectedItem at new location.
 * @param list -- the List to modify.
 * @param direction -- positive for down, negative for up. */

    public static void moveSelected(List list, int direction)
    {
	int cic = list.getItemCount();

	if (0 == cic)
	    return;

        int cix = list.getSelectedIndex();

        if (((direction < 0) && (0 < cix))
	 || ((direction > 0) && (-1 < cix) && (cix+1 < cic))) {

            String hold = list.getItem(cix);
            list.delItem(cix);

            if (direction < 0) {
                list.addItem(hold, cix-1);
                list.select(cix-1);
	    }
	    else {
                list.addItem(hold, cix+1);
                list.select(cix+1);
	    }
        }
    }

    public static int findItem (List list, String item)
    {
	String [] items = list.getItems ();
	for (int ii = 0; ii < items.length; ii++)
	    if (items [ii].equals (item))
		return ii;
	return -1;
    }

/*  This method will center the given dialog on the given parent. */

    public static void centerDialog(Component parent, Component dialog)
    {
        if ((parent != null) && (dialog != null))
        {
            Dimension myDim = dialog.getSize();
            Dimension pDim = parent.getSize();
            Dimension ss = parent.getToolkit().getScreenSize();

            //Point loc = parent.getLocation();
            Point loc = parent.location();

            loc.translate((pDim.width-myDim.width)/2,
                          (pDim.height-myDim.height)/2);

            loc.x = Math.max(0, Math.min(loc.x, 
                                         ss.width - dialog.getSize().width));
            loc.y = Math.max(0, Math.min(loc.y, 
                                         ss.height - dialog.getSize().height));

            dialog.setLocation(loc.x, loc.y);
        }
    }

/** This **always** gives a newFont with getSize as requested,
 *  but they may be displayed as the same size anyway.
 *  and NOT change size on our Unix box,
 *  although fine on a Windows/NT box. */

    public static void changeFont (Component comp, int delta) {
      if (null == comp)
	  return;

      Component pcomp = comp.getParent ();

      Font oldFont = comp.getFont ();

      if ((null == oldFont)
       && (null != pcomp))
	   oldFont = pcomp.getFont ();

      if (null == oldFont)
	  return;

      Font newFont = new Font
	  (oldFont.getName (),
	   oldFont.getStyle (),
	   oldFont.getSize () + delta);

 // System.out.println (comp.toString ()+" old "+oldFont+" new "+newFont);

      comp.setFont (newFont);

      comp.invalidate ();

      if (null != pcomp)
	  pcomp.validate ();
    }

/** This **always** gives a newFont with getSize as requested,
 *  but they may be displayed as the same size anyway.
 *  and NOT change size on our Unix box,
 *  although fine on a Windows/NT box. */

    public static void sizeFont (Component comp, int points) {
      if (null == comp)
	  return;

      Component pcomp = comp.getParent ();

      Font oldFont = comp.getFont ();

      if ((null == oldFont)
       && (null != pcomp))
	   oldFont = pcomp.getFont ();

      if (null == oldFont)
	  return;

      Font newFont = new Font
	  (oldFont.getName (),
	   oldFont.getStyle (),
	   points);

 // System.out.println (comp.toString ()+" old "+oldFont+" new "+newFont);

      comp.setFont (newFont);

/** If this is a Container,
 * propagate the sizeFont to the contained components. */

      if (comp instanceof Container) {
        Component [] ccs = ((Container)comp).getComponents ();
        for (int nxc = 0; nxc < ccs.length; nxc++)
	    sizeFont (ccs [nxc], points);
      }

      comp.invalidate ();

      if (null != pcomp)
	  pcomp.validate ();
    }

/* Helper for doPaint */

    protected static void myBasicPaint (Graphics g, Component comp, boolean edge) {
        Dimension tb = comp.getSize ();

        if (null != comp.getFont ())
            g.setFont (comp.getFont ());

        Color BG = comp.getBackground ();
        if (null != BG) {
	    g.setColor (BG);
            g.fillRect (0, 0, tb.width, tb.height);
        }

        Color FG = comp.getForeground ();
        if (null != FG)
            g.setColor (FG);
        else
            g.setColor (Color.black);

        if (edge)
	    g.drawRect (0, 0, tb.width-1, tb.height-1);
    }

/** Avoid buggy printAll by doing it ourselves.
 * Instead of saying myTopComponent.printAll (Graphics g),
 * say Util.doPaint (Graphics g, Component myTopComponent);
 * it is not beautiful but it does work. */

    public static void doPaint (Graphics g, Component aComp) {

        if (!aComp.isShowing ())
            return;

        Dimension tb = aComp.getSize ();

/* Our own Container expansion,
 * again to keep control for the peer-based children.
 * Recursively call doPaint () for each child,
 * each with a separate Graphics.
 *
 * Not sure if we are safe calling update for the Container,
 * any extension of Container that does some custom painting,
 * and then calls super.paint for painting the children,
 * will escape our control (as will the children)
 *
 * If not we can just use myBasicPaint instead.
 * This means we omit any custom painting by subclasses,
 * which is probably why they are a subclass,
 * so nice if we don't have to do that. */

        if (aComp instanceof Container) {

            //myBasicPaint (g, aComp, false);
	    aComp.update (g);

            Component [] children = ((Container)aComp).getComponents ();
            for (int kk = 0; kk < children.length; kk++) {
                if (children [kk].isShowing ()) {

                    //Point cp = children [kk].getLocation ();
                    Point cp = children [kk].location ();
                    //Dimension ctb = children [kk].getSize ();
                    Dimension ctb = children [kk].size ();

	            Graphics cg = g.create (cp.x, cp.y, ctb.width, ctb.height);
                    doPaint (cg, children [kk]);
                    cg.dispose ();
                }
            }
        }

/* Simulate the peer-based classes,
 * because they don't "really" paint to g,
 * they just use g to know what the peer should do,
 * so nothing would show up for them.
 * These are all pretty sloppy... */

        else if (aComp instanceof Label) {
            myBasicPaint (g, aComp, false);
            String s = ((Label)aComp).getText ();
            if (null != s)
                g.drawString (s, 2, tb.height/2);
        }

        else if (aComp instanceof Button) {
            myBasicPaint (g, aComp, true);
            String s = ((Button)aComp).getLabel ();
            if (null != s)
                g.drawString (s, 2, tb.height/2);
        }

        else if (aComp instanceof Checkbox) {
            myBasicPaint (g, aComp, false);
            if (((Checkbox)aComp).getState ())
                g.fillOval (2, tb.height/3,
                  tb.height/2, tb.height/2);
            else
                g.drawOval (2, tb.height/3,
                  tb.height/2, tb.height/2);
            String s = ((Checkbox)aComp).getLabel ();
            if (null != s)
                g.drawString (s, tb.height, tb.height/2);
        }

        else if (aComp instanceof Choice) {
            myBasicPaint (g, aComp, true);
            String s = ((Choice)aComp).getSelectedItem ();
            if (null != s)
                g.drawString (s, 2, tb.height/2);
        }

        else if (aComp instanceof TextField) {
            myBasicPaint (g, aComp, true);
            String s = ((TextField)aComp).getText ();
            if (null != s)
                g.drawString (s, 2, tb.height/2);
        }

        else if (aComp instanceof TextArea) {
            myBasicPaint (g, aComp, true);
            StringTokenizer spec = new StringTokenizer
              (((TextArea)aComp).getText (), "\n");

            for (int nn = 0;
              0 < spec.countTokens ();
              nn++)
                g.drawString (spec.nextToken (), 2, (1+nn) * 12);
        }

/* Here we should test else if (null != aComp.getPeer ())
 * and just do myBasicPaint (g, aComp, true) as better than nothing,
 * but "getPeer () is deprecated" so not doing this test... */

/* Don't know how so hope it does alright for itself.
 * Anything purely Java should be fine. */

        else
            aComp.update (g);
    }


    public static int readInteger(String string) throws IllegalArgumentException
    {
        Integer iVal;
        int retVal = 0;

        if ((string != null) && (!string.equals("")))
        {
            iVal = new Integer(string);
            retVal = iVal.intValue();
        }
        else throw new IllegalArgumentException();

        return retVal;
    }

    public static boolean hasItem(List aList, String aString)
    {
        String[] contents = aList.getItems();

        if ((contents == null) || (contents.length == 0))
            return false;

        for (int i = 0; i < contents.length; i++)
            if (aString.equals(contents[i])) return true;

        return false;
    }
}

/* <IMG SRC="/cgi-bin/counter">*/
