/*
 * @(#) CustomizerUtil.java 1.0 99/1/18 
 * Copyright (c) 1999 Lawrence Rodrigues
 */
package vis.beans.customizers;
import java.io.*;
import java.beans.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
//import java.util.*;
//import vis.util.*;
import java.lang.reflect.*;
import javax.swing.*;
import javax.swing.event.*;

  /** CustomizerUtil Class
   * @version 1.0  18 Jan 1999
   * @author Lawrence Rodrigues
   **/
  public class CustomizerUtil{ 
       
     /* Does gridbag layout when the JPanel has the same type of components.
      * @param comp an array of components.
      * @param column the number of columns.
      */
     public static JPanel doGridbagLayout(Component[] comp, int column){
         JPanel pan = new JPanel();
         GridBagLayout   gb = new GridBagLayout() ;
         GridBagConstraints c = new GridBagConstraints();
         pan.setLayout(gb);
         c.insets = new Insets(10,10,0,0);
         c.anchor = GridBagConstraints.NORTHEAST;
         c.weighty = 0.0; c.weightx = 0.0;
         c.gridwidth = 1;
         for(int i=0;i<comp.length;i++){
             c.gridwidth =1;
             if(((i%column)-column+1)==0) c.gridwidth=GridBagConstraints.REMAINDER;  
             gb.setConstraints(comp[i],c);
             pan.add(comp[i],c);
         }
         return pan;
      }

     /* Creates an edit field for any primitive type of property. 
      * Uses the relection API to invoke the getter method. Since the 
      * JTextField component's input and output is only text, the 
      * actual type of the property is needed to convert its input and output.
      * @param obj the bean object.
      * @param pc the property change support object.
      * @param name the property name.
      * @param clType the property class type.
      */
      public static JTextField createJTextField(Object obj,
                                                PropertyChangeSupport pc,
                                                String name, 
                                                Class clType){
         final Object bean = obj;
         final PropertyChangeSupport pcs = pc;
         final String propName = name;
         final Class type = clType;
         JTextField jtf = new JTextField(5);
         String str = "get"+propName;
         //Get the current property value as object
         Object probject= getProperty(bean, propName); 
         //Diplay it
         jtf.setText(probject.toString());
         jtf.addActionListener(
              new ActionListener() {
                public void actionPerformed(ActionEvent e){
                  try{
                     //Get the modified property as text string
                     String txt =((JTextField)(e.getSource())).getText();
                     //Convert the text string to actual property value. 
                     Object propValue = convertStringToObject(type,txt);
                     //delegates firing of property change event to pcs
                     setProperty(bean,propName, propValue);
                     String actName = Introspector.decapitalize(propName);
                     pcs.firePropertyChange(propName, null, propValue);
                  }catch(Exception x){  x.printStackTrace(); }
                }
              }
         );
         return jtf;
     }

     /** Create a JPanel with Choice components for integer type of enum property
       * @param propName the property name
       */
     public static JComboBox createChoice(Object obj, 
                                          PropertyChangeSupport pc,
                                          String prName, 
                                          String[] tag, 
                                          int[] value){
        final PropertyChangeSupport pcs = pc;
        final String propName = prName;
        final int[] values = value;
        final String[] tags = tag;
        final Object bean = obj;
        final Class cl = bean.getClass();
        String str = "get"+propName;
        JComboBox  cb = new JComboBox();
        for(int i=0;i <tags.length;i++){
            cb.addItem(tags[i]);
        }
        try{
             Method getM = cl.getMethod(str, null);
             Object args[] = { };
             Object val = getM.invoke(bean, args);
             int index =0;
             int  intval = ((Integer)val).intValue();
             for(int i=0;i <tags.length;i++){
                 if(intval == values[i]){
                    index=i;
                    break;
                 }
             }
             cb.setSelectedIndex(index);
        }catch(Exception e){
            e.printStackTrace();   
            return null;
        }
        cb.addItemListener(
            new ItemListener(){
                  public void itemStateChanged(ItemEvent e){
                  try{
                     int ind =((JComboBox)(e.getSource())).getSelectedIndex();
                     Class[] cla = {int.class};
                     Method setM = cl.getMethod("set"+propName, cla);
                     Integer[] args ={new Integer(values[ind])};
                     setProperty(bean,propName, colors[ind]);
                     pcs.firePropertyChange(propName, null, new  Integer(values[ind]));
                     }catch(Exception x){System.out.println("choice exception"); }
                  }
            }
        );
        return cb;
     }


     public static JComboBox createColorComboBox(Object obj,
                                                 PropertyChangeSupport pc,
                                                 String prName){
        final String propName = prName;
        final PropertyChangeSupport pcs = pc;
        final Object bean = obj;
        JComboBox  ch = new JComboBox();
        for(int i=0;i <colors.length;i++){
            ch.addItem(colorNames[i]);
        }
        final Class cl = bean.getClass();
        if(cl == null) return ch;
        try{
             String str = "get"+propName;
             Method getM = cl.getMethod(str, null);
             Object args[] = { };
             Object clr =  getM.invoke(bean, args);
             int index =0;
             for(int i=0;i <colors.length;i++){
               if(clr == colors[i]){
                  index=i;
                  break;
               }
             }
            ch.setSelectedIndex(index);
        }catch(Exception e){
                System.out.println("Reflection exception");
                return null;
        }
        ch.addItemListener(
              new ItemListener(){
                  public void itemStateChanged(ItemEvent e){
                  try{
                     int ind =((JComboBox)(e.getSource())).getSelectedIndex();
                     Class[] cla = {Color.class};
                     //Method setM = cl.getMethod("set"+propName, cla);
                     Color[] args ={colors[ind]};
                     String actName = Introspector.decapitalize(propName);
                     setProperty(bean,propName, colors[ind]);
                     pcs.firePropertyChange(actName, null, colors[ind]);
                     }catch(Exception x){   System.out.println("choice exception"); }
                  }
               }
        );
        return ch;
     }
     /**
       * Converts an object to a String.
       */
     public static String toString(Object obj, Class type){
        if(type.equals(Integer.TYPE)){
           return obj.toString();
        }
        if(type.equals(String.class)){
           return (String)obj;
        }
        return null;
     }

     public static JPanel createXYIncrPanel(Object target, 
                                           PropertyChangeSupport pc,
                                           String xpr,
                                           String ypr, 
                                           String JLabelStr){
        JButton xincr = new JButton("+");
        IncrButtonAdapter xincrada = new IncrButtonAdapter(target,pc, xpr, 2);
        xincr.addActionListener(xincrada);
      
        JButton yincr = new JButton("+");
        IncrButtonAdapter yincrada = new IncrButtonAdapter(target,pc,ypr, 2);
        yincr.addActionListener(yincrada);

        JButton xdecr = new JButton("-");
        IncrButtonAdapter xdecrada = new IncrButtonAdapter(target,pc,xpr, -2);
        xdecr.addActionListener(xdecrada);
       
        JButton ydecr = new JButton("-");
        IncrButtonAdapter ydecrada = new IncrButtonAdapter(target,pc,ypr, -2);
        ydecr.addActionListener(ydecrada);

        JPanel incrpan = new JPanel();
        incrpan.setLayout(new BorderLayout());
        JLabel cenlab = new JLabel(JLabelStr);
        incrpan.add(BorderLayout.NORTH, yincr);
        incrpan.add(BorderLayout.SOUTH, ydecr);
        incrpan.add(BorderLayout.WEST, xdecr);
        incrpan.add(BorderLayout.EAST, xincr);
        JPanel centpan = new JPanel();
        centpan.add(cenlab);
        centpan.add(incrpan);
        return centpan;
     }

     /**
       * Creates an increment JPanel. This has only "+" and "-" buttons.
       * @param prName the property name.
       * @param JLabelStr the JLabel string.
       */
     public static JPanel createIncrPanel(Object target, 
                                          PropertyChangeSupport pc,
                                          String prName, 
                                          String JLabelStr){
        JButton incr = new JButton("+");
        IncrButtonAdapter incrada = new IncrButtonAdapter(target,pc, prName, 2);
        incr.addActionListener(incrada);

        JButton decr = new JButton("-");
        IncrButtonAdapter decrada = new IncrButtonAdapter(target,pc,prName, -2);
        decr.addActionListener(decrada);

        JLabel inclab = new JLabel(JLabelStr);
        JPanel pan = new JPanel();
        pan.add(inclab);
        pan.add(incr);
        pan.add(decr);
        return pan;
     }

     static class IncrButtonAdapter implements ActionListener{
        int increment;
        String propName;
        Object bean;
        PropertyChangeSupport psc;
        public IncrButtonAdapter(Object target,
                                 PropertyChangeSupport pc,
                                 String pr, 
                                 int incr) {
           bean = target;
           psc = pc;
           increment = incr;
           propName = pr;
        }

        public void actionPerformed(ActionEvent e){
           try{
             Integer num = (Integer)getProperty(bean,propName);
             Object invarg[] = {new Integer(num.intValue()+ increment)};
             String prName = Introspector.decapitalize(propName);
             setProperty(bean,propName,invarg[0]);
             psc.firePropertyChange(propName, null, invarg[0]);
           } catch(Exception  x){
             System.out.println(x);
           }
         }
     }
 


    /** This method fetches the current value of a property.
      * @param bean the target bean.
      * @param propName the prperty name.
      */
    public static Object getProperty(Object bean,
                              String propName){
       try{
             Class bcl = bean.getClass();
             //Assuming the bean follows the design pattern for properties
             String str = "get"+propName;
             //First create the Method object for "getter" method
             //No arguments for getter method 
             Method getM = bcl.getMethod(str, null);
             //Use the Method object to invoke the "getter"method
             Object args[] = { };
             return getM.invoke(bean, args);
        } 
        catch(NoSuchMethodException e){
              System.out.println("Getter:No such method exception");
        }
        catch(IllegalArgumentException e1){
                System.out.println("Getter:Illegal argument exception");
        }  
        catch(IllegalAccessException e2){
                 System.out.println("Getter:Illegal access exception");
        }
        catch(InvocationTargetException e2){
                 System.out.println("Getter:Target invocation exception");
        }
        return null;
    }

    /**
      * This method sets the value of a property
      * @param bean the target object
      * @param propName the property name
      * @param propValue the value of the property as text. 
      * It is convenient to pass the property value as text when 
      * text fields are used.
      */
    public static void setProperty(Object bean,
                            String propName,
                            Object propValue){ //property value as text
       try{
             Class bcl = bean.getClass();
             //Assuming the bean follows the design pattern for properties
             String str = "set"+propName;
             //Create the parameter Class objects
             Class cls = propValue.getClass();
             Class type = getType(propValue);
             Class[] paraobj = {type};
             //Create the "setter" method object
             Method setM = bcl.getMethod(str, paraobj);
             //Construct the argument objects
             Object args[] = {propValue};
             //Invoke the "setter" method in the bean
             setM.invoke(bean, args);
         } catch(NoSuchMethodException e){
                 System.out.println("Setter:No such method exception");
         }
         catch(IllegalArgumentException e1){
                System.out.println("Setter: Illegal argument exception");
         }
         catch(IllegalAccessException e2){
                 System.out.println("Setter:Illegal access exception");
         }
         catch(InvocationTargetException e3){
                 System.out.println("Setter:Target invocation exception");
         }
   }



/*
    public static void setProperty(Object bean,
                            String propName,
                            String propValue, //property value as text
                            Class propType){
         try{
             Class bcl = bean.getClass();
             //Assuming the bean follows the design pattern for properties
             String str = "set"+propName;
             //Create the parameter Class objects
             Class[] paraobj = {propType};
             //Create the "setter" method object
             Method setM = bcl.getMethod(str, paraobj);
             //Construct the argument objects
             Object args[] = getArgs(propValue, propType);
             //Invoke the "setter" method in the bean
             setM.invoke(bean, args);
         } catch(NoSuchMethodException e){
                 System.out.println("Setter:No such method exception");
         }
         catch(IllegalArgumentException e1){
                System.out.println("Setter: Illegal argument exception");
         }
         catch(IllegalAccessException e2){
                 System.out.println("Setter:Illegal access exception");
         }
         catch(InvocationTargetException e3){
                 System.out.println("Setter:Target invocation exception");
         }
      }
*/
     /**
       * Creates array of agruments for the invoke method.
       * @param txt the text value to be converted to the argument array.
       * @param type the type of argument array.
       */
     public static Object[] getArgs(String txt, Class type){
        if(type.equals(String.class)){
           return new String[] {txt};
         }
        if(type.equals(Integer.TYPE)){
           return new Integer[] {Integer.valueOf(txt)};
        }
        if(type.equals(Double.TYPE)){
           Double[] args = {Double.valueOf(txt)};
           return args;
        }
        // Add other types 
         return null;
     }

     public static Class getType(Object obj){
        if(obj instanceof Long){
           return Long.TYPE;
        }
        if(obj instanceof Integer){
           return Integer.TYPE;
        }
        if(obj instanceof Short){
           return Short.TYPE;
        }
        if(obj instanceof Byte){
           return Byte.TYPE;
        }
        if(obj instanceof Float){
           return Float.TYPE;
        }
        if(obj instanceof Double){
           return Double.TYPE;
        }
        return obj.getClass();
    }

    public static Object convertStringToObject(Class type, String txt){
        if(type.equals(Integer.TYPE)){
           return Integer.valueOf(txt);
        }
        if(type.equals(Double.TYPE)){
          return Double.valueOf(txt);
        }
        if(type.equals(Long.TYPE)){
           return Long.valueOf(txt);
        }
        if(type.equals(Float.TYPE)){
          return Float.valueOf(txt);
        }
        if(type.equals(Short.TYPE)){
           return Short.valueOf(txt);
        }
        if(type.equals(Byte.TYPE)){
          return Byte.valueOf(txt);
        }
        return txt;
    }

     //--------------------------------------------------------------
     static Color[] colors = {Color.black, Color.blue, Color.red, Color.green,
                        Color.yellow, Color.cyan, Color.magenta, Color.white};
     static String[] colorNames = {"black", "blue", "red", "green",
                        "yellow", "cyan", "magenta", "white"};
     
   }


