/****************************************************************************
  $Archive: /njcl_sample/NJCLApplet/src/Util.java $
  $Revision: 2 $
  $Modtime: 3/18/99 3:30p $

  Copyright (c) 1999 Novell, Inc.  All Rights Reserved.

 THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
 USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
 ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS THIS WORK.
 PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
 ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
 PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
 DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
 PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
 CUSTOMERS WITH RESPECT TO THIS CODE.
 ***************************************************************************/

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

/**
 * This class provides some general purpose utility functions. These functions
 * are not graphical in nature and have no JNDI dependencies.
 */

public class Util
{
   /**
    * Retrieves the properties from the Applet parameters.
    *
    * @return                    Properties as retrieved from the parameters.
    *                            May be empty.
    */
   public static Properties getPropertiesFromParams (
         Applet applet,
         String paramInfo[][])
   {
      Properties props = new Properties ();
      String prop;
      String val;

      try
      {
         for (int i = 0; i < paramInfo.length; i++)
         {
            prop = paramInfo[i][0];
            val = applet.getParameter (prop);
            if (null != val)
               props.put (prop, val);
         }
      }
      catch (Throwable e)
      {
         // If this was loaded as an application then there are no parameters.
      }
      return (props);
   } // getPropertiesFromParams ()

   /**
    * Constructs a property list which is merged from two others.
    *
    * <p>If the preserve parameter is true, then only new parameters will
    * be added to the original properties, not overwritten.
    * </p>
    *
    * @param   origProps         (in) Original property list.
    * @param   newProps          (in) The new property list.
    * @param   preserve          (in) True if origProps should be preserved,
    *                            otherwise false.
    * @return                    A set of Properties representing a merge of
    *                            the origProps and newProps. May be empty.
    */
   public static Properties mergeProperties(
         Properties origProps,
         Properties newProps,
         boolean preserve)
   {
      Properties props = new Properties (origProps);
      Enumeration nameEnum = newProps.propertyNames ();

      String propName;
      try
      {
         while (nameEnum.hasMoreElements ())
         {
            propName = (String) nameEnum.nextElement ();
            if ((false == preserve) ||
                (false == origProps.containsKey (propName)))
            {
               origProps.put (propName, newProps.getProperty (propName));
            }
         }
      }
      catch (Exception e)
      {
         (new MessageBox (
                  "Error",
                  "Unable to merge property lists:\n" +
                  Util.getExceptionTrace (e))).show ();
      }
      return (props);
   } // mergeProperties ()

   /**
    * Convert the recursive Properties object into a flag Hashtable.
    *
    * @param props               The properties to be converted.
    * @return                    A hashtable with all the elements of the
    *                            properties.
    */
   public static Hashtable getHashtableFromProperties (
         Properties props)
   {
      Hashtable hash = new Hashtable ();
      Enumeration nameEnum = props.propertyNames ();
      String propName;
      Object propVal;
      
      while (nameEnum.hasMoreElements ())
      {
         propName = (String) nameEnum.nextElement ();
         propVal = props.getProperty (propName);
         hash.put (propName, propVal);
      }
      return (hash);
   } // getHashtableFromProperties ()

   /**
    * Returns an array of object that implement a given interface.
    *
    * @param comp                The compare object to use against the
    *                            objects found in the directory.
    * @param dir                 The directory through which to search for
    *                            the extensions. No trailing path seperator
    *                            is needed.
    * @return                    An array (possibly empty) of objects
    *                            which implement some particular interface.
    */
   public static Object[] loadExtensions (
         InterfaceCompare comp,
         String dir)
   {
      Vector objVector = new Vector ();
      int i;
      try
      {
         File file = new File (dir);
         String filenameList[] = file.list (new ClassFilenameFilter ());
         if (null == filenameList)
            return (null);
         Class objClass;
         Object objInst;
         for (i = 0; i < filenameList.length; i++)
         {
            try
            {  // Need to strip the '.class' from the file name
               String className = filenameList[i].substring (0, filenameList[i].length () - 6);
               objClass = Class.forName (className);
               if (!objClass.isInterface ())
               {  // Don't bother with interface only classes
                  objInst = objClass.newInstance ();
                  if (comp.implementsInterface (objInst))
                  {
                     System.out.println (
                                    "Extension " +
                                    objInst.getClass ().getName () +
                                    " loaded");
                     objVector.addElement (objInst);
                  }
               }
            } catch (Exception e)
            {  // We'll continue if we get one in this loop
               /*
               System.out.println (
                              "Unable to instantiate class of " +
                              dir + file.pathSeparator + filenameList[i] +
                              ":\n" + e);
               e.printStackTrace ();
               */
            }
         }
      } catch (Exception e)
      {
         (new MessageBox (
                  "Error",
                  "Unable to load extensions:\n" +
                  Util.getExceptionTrace (e))).show ();
      }
      Object [] array = new Object [objVector.size ()];
      for (i = 0; i < array.length; i++)
         array[i] = objVector.elementAt (i);
      return (array);
   } // loadExtensions ()

   /**
    * Returns an array of object that implement a given interface.
    *
    * @param comp                The compare object to use against the
    *                            objects found in the directory.
    * @param props               The properties to search for the plugins.
    * @param paramName           The parameter name with the plugins to load.
    * @return                    An array (possibly empty) of objects
    *                            which implement some particular interface.
    */
   public static Object[] loadExtensions (
         InterfaceCompare comp,
         Properties props,
         String paramName)
   {
      Vector objVector = new Vector ();
      String paramVal = (String) props.getProperty (paramName);
      int index = 0;
      String className;
      Class objClass;
      Object objInst;

      if (null == paramVal)
         return (null);
      do
      {
         index = paramVal.indexOf (';', index);
         if (-1 == index)
         {
            className = paramVal;
            paramVal = null;
         }
         else
         {
            className = paramVal.substring (0, index);
            paramVal = paramVal.substring (index + 1);
         }
         try
         {
            if (0 == className.length ())
               break;
            objClass = Class.forName (className);
            if (!objClass.isInterface ())
            {  // Don't bother with interface only classes
               objInst = objClass.newInstance ();
               if (comp.implementsInterface (objInst))
               {
                  System.out.println (
                                 "Extension " +
                                 objInst.getClass ().getName () +
                                 " loaded");
                  objVector.addElement (objInst);
               }
            }
         }
         catch (Exception e)
         {  // We'll continue if we get one in this loop
         }   
      } while (null != paramVal);
      
      Object [] array = new Object [objVector.size ()];
      for (int i = 0; i < array.length; i++)
         array[i] = objVector.elementAt (i);
      return (array);
   }

   /**
    * This method returns a string which includes an exception's stack trace.
    *
    * @param e                   The exception for which to get the trace.
    * @return                    String with full exception stack trace.
    */
   public static String getExceptionTrace (Throwable e)
   {
      StringWriter strWriter = new StringWriter ();
      PrintWriter prtWriter = new PrintWriter (strWriter);
      e.printStackTrace (prtWriter);
      return (strWriter.toString ());
   } // getExceptionTrace ()

   /**
    * This utility routine sets up the GridBagConstraints for an object
    * and adds it to the Container using a GridBagLayout.
    */
   static void addGridBagComponent (
         Container cont,
         Component comp,
         int gridX,
         int gridY,
         int gridWidth,
         int gridHeight,
         double weightX,
         double weightY)
   {
      GridBagLayout gbl = (GridBagLayout) cont.getLayout ();
      GridBagConstraints c = new GridBagConstraints ();
      c.fill = GridBagConstraints.BOTH;
      c.gridx = gridX;
      c.gridy = gridY;
      c.gridwidth = gridWidth;
      c.gridheight = gridHeight;
      c.weightx = weightX;
      c.weighty = weightY;
      cont.add (comp);
      gbl.setConstraints (comp, c);
   } // addGridBagComponent ()

} // class Util

/**
 * Internal class to accept only ".class" files.
 */
class ClassFilenameFilter
   implements FilenameFilter
{
   /**
    * Method called to determine if file is acceptable for this filter.
    */
   public boolean accept (
         File dir,
         String name)
   {
      return (name.endsWith (".class"));
   }
} // class ClassFilenameFilter
   
