package cutils.gui;

import java.awt.*;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;
import java.lang.reflect.*;
import javax.swing.border.*;


 class editProperties {

    static private Object o;
    protected Class c;
    Vector listOfClasses = new Vector();
    Vector listOfGetMethods = new Vector();
    Vector listOfGetValues = new Vector();
    Vector listOfSetMethods = new Vector();
    Vector namesOfSetMethods = new Vector();
    Vector primitiveSetMethod = new Vector();
    
    editProperties(Object o_) {
        o = o_;
        c = o.getClass();
        loadInstanceMethods();
        //printToConsole();
        printToSwing();
    }
    
    editProperties() {
        o = this;
        c = this.getClass();
        loadInstanceMethods();
        //printToConsole();
        printToSwing();
    }

    private void loadInstanceMethods() {
        do {
            Method allMethods[] = c.getDeclaredMethods();
            for (int x = 0;x<allMethods.length;x++) {
                listOfClasses.addElement(c);
                loadPublicGetters(allMethods[x]);
                loadPublicSetters(allMethods[x]);
            }
            c = c.getSuperclass();
        } while (c != Object.class);
    }
    
    private void loadPublicGetters(Method m) {
        if (m.toString().indexOf("public") != -1 && (m.getName().substring(0,3).compareTo("get")==0 || m.getName().substring(0,2).compareTo("is")==0 )){
            listOfGetMethods.addElement(m.getName());
            loadGetValues(m);
        }
    }
    private void loadPublicSetters(Method m) {
        if (m.toString().indexOf("public") != -1 && m.getName().substring(0,3).compareTo("set")==0) {
            listOfSetMethods.addElement(m);
            namesOfSetMethods.addElement(m.getName());
            primitiveSetMethod.addElement(isPrimitive(m.getParameterTypes()));
        }
    }
    
    private String isPrimitive(Class[] c) {
        String primitiveTest = "true";
        for (int i=0;i<c.length;i++) {
            if (!c[i].isPrimitive() && c[i] != primitiveTest.getClass()) {
                primitiveTest = "false";
            }
        }
        return primitiveTest;
    }
    
    private void loadGetValues(Method m) {
        try {
            Method m1 = c.getMethod(m.getName(),new Class[] {});
            Object result = m1.invoke(o,null);
            if (result == null) {
                listOfGetValues.addElement("null");
            }
            else {
                listOfGetValues.addElement(result);
            }
        }
        catch (Exception e) {
            //the cause of this is most likely that the method requires parameters
            listOfGetValues.addElement("Can't Determine Value");
        }
    }
    
    public void printToSwing() {

        JInternalFrame frame = new JInternalFrame(("Edit Properties"),true, true, true, true);
        frame.setLocation(100, 100);
        frame.setSize(400, 200);
        frame.setBackground(Color.white);
        ComponentEditor.desktop.add(frame);
        frame.moveToFront();
        frame.setVisible(true);


        Container content = frame.getContentPane();
        content.setLayout(new GridLayout());
            
        JPanel p = new JPanel(new BorderLayout());
        JPanel leftp = new JPanel(new GridLayout(0,1));
        JPanel rightp = new JPanel(new GridLayout(0,1));
        p.add(leftp, BorderLayout.WEST);
        p.add(rightp, BorderLayout.CENTER);

        JLabel property[] = new JLabel[1000];
        JTextField value[] = new JTextField[1000];
        String propertyName;
        String propertyFlag;


        for (int x=0;x<listOfGetMethods.size();x++) {
            //test for corresponding setter
            int validSetMethodFromGet = namesOfSetMethods.indexOf("s" + listOfGetMethods.elementAt(x).toString().substring(1,listOfGetMethods.elementAt(x).toString().length()));
            int validSetMethodFromIs = namesOfSetMethods.indexOf("set" + listOfGetMethods.elementAt(x).toString().substring(2,listOfGetMethods.elementAt(x).toString().length()));
            int validSetMethod = (validSetMethodFromGet > validSetMethodFromIs ? validSetMethodFromGet : validSetMethodFromIs);
            
            if (validSetMethod >=0) {
            propertyFlag = listOfGetMethods.elementAt(x).toString().substring(0,1);
            if (propertyFlag.equals("g")) {
                propertyName = listOfGetMethods.elementAt(x).toString().substring(3,listOfGetMethods.elementAt(x).toString().length());
            }
            else {
                propertyName = listOfGetMethods.elementAt(x).toString().substring(2,listOfGetMethods.elementAt(x).toString().length());
            }
            property[x] = new JLabel(propertyName);
            property[x].setBorder (new EtchedBorder());
            property[x].setOpaque(true);
            property[x].setBackground(Color.white);
            leftp.add(property[x]);
            
            
            if (listOfGetValues.elementAt(x).getClass() == Dimension.class) {
                Dimension _d = (Dimension)listOfGetValues.elementAt(x);
                listOfGetValues.setElementAt((int)_d.getWidth() + "," + (int)_d.getHeight(),x);
            }
            else if (listOfGetValues.elementAt(x).getClass() == Point.class) {
                Point _p = (Point)listOfGetValues.elementAt(x);
                listOfGetValues.setElementAt((int)_p.getX() + "," + (int)_p.getY(),x);
            }
            else if (listOfGetValues.elementAt(x).getClass() == Rectangle.class) {
                Rectangle _r = (Rectangle)listOfGetValues.elementAt(x);
                listOfGetValues.setElementAt((int)_r.getX() + "," + (int)_r.getY() + "," + (int)_r.getWidth() + "," + (int)_r.getHeight(),x);
            }
            
            //if the setter has primitive arguments allow it to be changed  
            if (validSetMethod >= 0 && primitiveSetMethod.elementAt(validSetMethod).equals("true")) {
                value[x] = new RunPropertyTextField(listOfGetValues.elementAt(x).toString(),validSetMethod,o.getClass()) {
                public void run() {
                        
                        StringTokenizer st = new StringTokenizer(this.getText(),",");
                        Method t = (Method) listOfSetMethods.elementAt(this.location);
                        Class[] paramTypes = t.getParameterTypes();
                        if (paramTypes.length != st.countTokens()) {
                        JOptionPane.showMessageDialog(null, "Invalid Data. The property was not changed","Error",JOptionPane.ERROR_MESSAGE);
                            return;
                        }
                        int n = 0;
                        
                        Object arg[] = new Object[st.countTokens()];
                        while (st.hasMoreTokens()) {
                            arg[n] = convertArg(st.nextToken(), paramTypes[n]);
                            n++;
                        }           
                        setProperty(this.type,t.getName(),t,arg);
                    
                    }
                };
                value[x].setBorder (new EtchedBorder());
                value[x].setEnabled(true);
            }
            else {
                
                value[x] = new JTextField(listOfGetValues.elementAt(x).toString());
                value[x].setBorder (new EtchedBorder());
                value[x].setEnabled(false);
            }
            rightp.add(value[x]);
            }
        }
        content.setVisible(true);
        p.setVisible(true);

        JScrollPane sp = new JScrollPane(p);
        content.add(sp);
        frame.updateUI();

    }
    
    public static void setProperty(Class c,String setterName, Method t, Object[] args) { 
        int flag = 0;
        do {
            c = c.getSuperclass();
            try {
                Method m1 =  c.getMethod(setterName,t.getParameterTypes());
                m1.invoke(o,args);
                flag = 1;
            }
            catch(Exception e){
                //e.printStackTrace();
            }
        
        } while (c != Object.class); 
        if (flag==0) {
            JOptionPane.showMessageDialog(null, "Invalid Data. The property was not changed","Error",JOptionPane.ERROR_MESSAGE);
        }
    } 
    
    
    protected Object convertArg( String val, Class type )
     {
         if ( val == null )
         {
             return null;
         }
 
         String v = val.trim();
         if ( String.class.isAssignableFrom( type ) )
         {
             return val;
         }
         else if ( Integer.TYPE.isAssignableFrom( type ) )
         {
             return new Integer( v );
         }
         else if ( Long.TYPE.isAssignableFrom( type ) )
         {
             return new Long( v );
         }
         else if ( Boolean.TYPE.isAssignableFrom( type ) )
         {
             if ( "true".equalsIgnoreCase( v ) )
             {
                 return Boolean.TRUE;
             }
             else if ( "false".equalsIgnoreCase( v ) )
             {
                 return Boolean.FALSE;
             }
         }
         return null;
     }



    
    public void printToConsole() {
        for (int x = 0;x<listOfGetMethods.size();x++) {
            System.out.println(listOfGetMethods.elementAt(x) + " = " + listOfGetValues.elementAt(x) + "\n");
        }
        for (int x = 0;x<listOfSetMethods.size();x++) {
            System.out.println(listOfSetMethods.elementAt(x) + " - " + primitiveSetMethod.elementAt(x) + "\n");
        }
    }

    public static void main(String[] args) {
        editProperties e = new editProperties(new Container());     
    }

}