//
// CBROWInstance.java
//
// The contents of this file are subject to the SNIA Public License Version 1.0
// (the "License"); you may not use this file except in compliance with the
// License. You may obtain a copy of the License at
//
//	http://www.snia.org/resources/openSource.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is CBROWInstance.java
// 
// The Initial Developer of the Original Code is David Simons.
//
// Contributor(s): Sharad Tripathi (sharad.c.tripathi@intel.com)
//
//
// This source uses the Solaris WBEM APIs version 2.2. 
// Synchronization will be maintained with the Solaris WBEM APIS,
// which are being standardized through the Java Community Process.
//
//
// $Id: CBROWInstance.java,v 1.1 2003/07/17 18:32:55 kumpf Exp $
//
// $Log: CBROWInstance.java,v $
// Revision 1.1  2003/07/17 18:32:55  kumpf
// HP-BAPU: PEP-64 CIM Client and CIM Listener Java Interface
//
// Revision 1.1.1.1  2001/10/31 18:14:58  karl
// import of SNIA 0_7
//
// Revision 1.15  2001/01/02 20:30:22  davidsi
// - Check for null references when converting arrays to strings.
//
// Revision 1.14  2001/01/02 19:44:03  davidsi
// - Added support for deep/shallow instance display.
//
// Revision 1.13  2000/11/21 18:53:19  davidsi
// - Must clear selection on method table otherwise the state for
//   enabling/disabling the execute menu item is incorrectly
//   tracked.
//
// Revision 1.12  2000/11/06 18:21:05  davidsi
// - Support for using native java types
//
// Revision 1.11  2000/09/15 15:56:48  davidsi
// - BUG FIX. From Mahendra Ramachandran, added code to set divider location
//   and removed removeRowSelectionInterval() calls which were causing
//   problems on JDK1.3.
//
// Revision 1.10  2000/08/16 05:59:55  shawn
// merge P_TOMCAT31 branch
//
// Revision 1.9.6.1  2000/08/10 00:03:31  shawn
// head merge
//
// Revision 1.9  2000/08/02 16:31:09  davidsi
// - Added support for getting array based values back from the om.
//
// Revision 1.8  2000/07/19 16:50:50  davidsi
// - Now caches object paths so they don't have to be regenerated from
//   the string representations.
//
// Revision 1.7  2000/07/10 17:22:53  davidsi
// - Added the ability to delete instances.
//
// Revision 1.6  2000/05/11 10:11:55  davidsi
// - Fixed tabs.
//
// Revision 1.5  2000/05/07 13:26:05  davidsi
// - Fixed display of properties.
//
// Revision 1.4  2000/05/06 17:13:50  davidsi
// - Brought in line with SUN WBEM APIs 2.2
//
// Revision 1.3  2000/04/09 13:30:02  davidsi
// - Fixed property display (missing conversion to string).
// - Moved method execution dialog into new file CBROWMethod to allow
//   code reuse.
//
// Revision 1.2  2000/02/13 15:09:40  davidsi
// - Added text to cover re-use of Solaris WBEM APIs.
//
// Revision 1.1.1.1  2000/02/06 16:41:03  davidsi
// Initial version.
//
//
//
package org.snia.wbemcmd.browser;

import java.awt.event.*;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Hashtable;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.JCheckBoxMenuItem;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.tree.*;
import org.snia.wbem.client.*;
import org.snia.wbem.cim.*;
import java.lang.reflect.Array;


//
// Viktor Mihajlovski Fixes: Date - 08/13/02
// Fix for the browser, when non-string properties are being received
//


//
// Provides a dialog that allows instances to be browsed
//
class CBROWInstance extends CBROW  {
    static String STRING_NEW_INSTANCE="New Instance";
    
    CIMClient cc;
    CIMNameSpace cn;
    JFrame mainFrame;
    JTable propKeyTable;	    // instances
    JTable propValueTable;	    // propery values
    JTable methodTable; 	    // methods
    JTable relObjTable; 	    // relatedobjects
    JTable assocTable;		    // associations
    TableModel propKeys;
    TableModel propValues;
    TableModel methods;
    TableModel relatedobjects;
    TableModel associations;
    CBROWNode root;
    CIMClass currentClass;
    CIMObjectPath currentInstancePath;
    CIMInstance currentInstance;
    int currentIndex=-1;		// index into key list for current item
    int currentMethod=-1;		// index for current method
    boolean newInstance=false;
    boolean doDeep = !CIMClient.DEEP;
    JScrollPane scrollKeyPane;
    boolean realInstance=false; 	// TRUE when instance is a real
					// instance (e.g. not in process of
					// being created)
    Hashtable stringToPaths=new Hashtable();	// maps string paths to 
						// real object paths
    //
    // Menus which become enabled/disabled
    //
    JMenuItem menuItemExecute;
    JMenuItem menuItemSave;
    JMenuItem menuItemRefresh;	
    JMenuItem menuItemSetProperty;
    JMenuItem menuItemGetProperty;
    JMenuItem menuItemReference;
    JMenuItem menuItemDelete;
    //
    // Property and method column indexes
    //
    static int PROP_COL_KEY = 0;
    static int PROP_COL_NAME = 2;
    static int PROP_COL_VALUE = 3;
    static int PROP_COL_TYPE = 1;
    static int KEY_COL_NAME = 0;
    static int METHOD_COL_NAME = 0;
    static int METHOD_COL_RETVAL = 1;
    static int METHOD_COL_ARGS = 2;
    static int RELOBJ_COL_PATH = 0;
    static int ASSOC_COL_PATH = 0;	
    //
    // Sizes
    static int KEY_COL_SIZE = 200;
    static int PROP_COL_SIZE = 400;

    public CBROWInstance(CIMClient icc,CIMNameSpace icn,CIMClass inClass,Point windowPos) {
	currentClass=inClass;
	cc=icc;
	cn=icn;
	
    
	JMenuBar menuBar = constructMenuBar();
		
	propKeys=new TableModel(new String[] {"Instances Available"});
	propKeyTable=new JTable(propKeys);

	
	final ListSelectionModel lsm=propKeyTable.getSelectionModel();
	lsm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
	//
	// Handles instance selections	
	//
	lsm.addListSelectionListener(new ListSelectionListener() {
	    public void valueChanged(ListSelectionEvent e) {
			loadInstanceList(lsm.getMaxSelectionIndex());
	    }
	    });
	
	scrollKeyPane = new JScrollPane(propKeyTable);
	scrollKeyPane.setPreferredSize(new Dimension(KEY_COL_SIZE, 300));
	//
	// Set up tabbed pane
	//
	JTabbedPane tabbedPane = new JTabbedPane();
	
	
	//
	// Create properties tab
	//
	propValues=new TableModel(new String[] {"Key","Type","Name","Value"});
	
	    
	propValueTable=new JTable(propValues);
	JScrollPane scrollpane1 = new JScrollPane(propValueTable);
	tabbedPane.addTab("Properties", null, scrollpane1);
	//
	// Create Methods tab
	//
	
	methods=new TableModel(new String[] {"Name","Return Value","Parameters"});
	methodTable=new JTable(methods);
	JScrollPane scrollpane2 = new JScrollPane(methodTable);
	tabbedPane.addTab("Methods", null, scrollpane2);


	//
	// Handles method selections	
	final ListSelectionModel methodsm=methodTable.getSelectionModel();
	methodsm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
	methodsm.addListSelectionListener(new ListSelectionListener() {
	    public void valueChanged(ListSelectionEvent e) {
		    
		    int newindex=methodsm.getMaxSelectionIndex();
		    
		    if (currentMethod==newindex || newindex==-1)
			return;
		    currentMethod=newindex;
		    menuItemExecute.setEnabled(true);
		    
	    }	
	});
	
	
	//
	// Create related objects tab
	//
	relatedobjects=new TableModel(new String[] {"Paths of related objects"});
	relObjTable=new JTable(relatedobjects);
	JScrollPane scrollpane3 = new JScrollPane(relObjTable);
	tabbedPane.addTab("Related objects", null, scrollpane3);
	
	//
	// Create associations tab
	//
	associations=new TableModel(new String[] {"Associations"});
	assocTable=new JTable(associations);
	JScrollPane scrollpane4 = new JScrollPane(assocTable);
	tabbedPane.addTab("Associations", null, scrollpane4);
    
    
	//
	// Create main splitter window
	//
	JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
				      scrollKeyPane,
			   tabbedPane);
	

	splitPane.setDividerLocation(150);

	mainFrame = new JFrame("Instance Editor");

	mainFrame.getContentPane().add("Center", splitPane);
	mainFrame.setJMenuBar(menuBar);
	mainFrame.setBackground(Color.lightGray);
	mainFrame.setSize(KEY_COL_SIZE+PROP_COL_SIZE, 500);
	mainFrame.setLocation(windowPos.x+30,windowPos.y+30);
	mainFrame.addWindowListener( new WindowAdapter() {
	    public void windowClosing(WindowEvent e) {
		mainFrame.dispose();
	    }
	});

	updateTable();
	updateInstanceList();
	mainFrame.show();
    }

    private final void loadInstanceList(int newindex) {
	boolean forceinstanceupdate=false;
	if (newindex>propKeys.getRowCount())
	    newindex=propKeys.getRowCount();
	if (propKeys.getRowCount()==0)
 	    return;		
	if (currentIndex==newindex || newindex==-1)
	    return;
    
 	currentIndex=newindex;
	//
	// If we are moving onto STRING_NEW_INSTANCE then this is
	// a callback during the creation of a newinstance and
	// is spurious (e.g. its been generated
	// because we changed the list of instances to show
	//  STRING_NEW_INSTANCE.
	//
	if ( ((String)(propKeys.getValueAt(currentIndex,KEY_COL_NAME))).equalsIgnoreCase(STRING_NEW_INSTANCE))
	    return;
		    
	//
	// If there is a new instance being created, give the
	// choice of saving it, aborting the instance selection
	// or cancelling its creation.
	//
	if (newInstance) {
		Object[] options = {"Save Instance","Cancel","Ignore Creation"};
		int ret=JOptionPane.showOptionDialog(mainFrame,
		     "Do you wish to save the instance that is being created?",
		     "Save new instance",
		     JOptionPane.YES_NO_OPTION,
		     JOptionPane.ERROR_MESSAGE,
		     null,options,options[1]);
		switch (ret) {
		case 0:
		    if (saveInstance()!=0) {
			//
			// We have to update the instance list because we've
			// taken a call back that's moving the cursor off the
			// STRING_NEW_INSTANCE entry - this will put it back
			// in the right place.
			//
			updateInstanceList();
			return;
		    }
		    break;
		case 1:
		    //
		    // Don't switch instances
		    //				    
		    //
		    // We have to update the instance list because we've
		    // taken a call back that's moving the cursor off the
		    // STRING_NEW_INSTANCE entry - this will put it back
		    // in the right place.
		    //
		    updateInstanceList();
		    return;
		case 2:
		    //
		    // Trash the creation so far performed
		    //
		    newInstance=false;
		    forceinstanceupdate=true;
		    break;
		} 
	}
	    	
	try {
	    currentInstancePath=(CIMObjectPath)(stringToPaths.get(
						(String)(propKeys.getValueAt(currentIndex,KEY_COL_NAME))));
	    if (currentInstancePath==null)
		throw new CIMException(CIMException.CIM_ERR_FAILED,
					"Could not locate object");
	    currentInstance=cc.getInstance(currentInstancePath,false);
	} catch (CIMException ce) {
	    cimErrorMsg(mainFrame,"Failed to load instance "+currentInstancePath.toString(),ce);
	}
	realInstance=true;
	propValues.setColumnEditable(PROP_COL_VALUE,true);
		
	//
	// If the instance changes then previous method selections
	// are lost. Also reset currentMethod so we spot the
	// user selecting a method.
	//
	currentMethod=-1;
	methodTable.clearSelection();    
	updateTable();
	menuItemSave.setEnabled(true);
	instanceNowValid(true);
	//
	// No methods can be executed until a method is first
	// selected on this new instance
	//
	menuItemExecute.setEnabled(false);
	if (forceinstanceupdate)
	    updateInstanceList();

    }
	   

    public void updateInstanceList() {
	Enumeration elist;
	int length=0;

	if (currentClass==null) 
	    return;
	try {
	    stringToPaths=new Hashtable();
	    elist=cc.enumInstances( new CIMObjectPath(currentClass.getName(),
				    cn.getNameSpace()),
				    doDeep);
	    
	    propKeys.clearColumn(KEY_COL_NAME);
	    if (elist!=null) {
		while (elist.hasMoreElements()) {
		    Object obj=elist.nextElement();
		    if (obj instanceof CIMObjectPath) {
			String objName=((CIMObjectPath)obj).toString();
			stringToPaths.put(objName,obj);
			propKeys.addValue(0,objName);
			length++;
		    } 
		}
	    }
	} catch (CIMException ce) {
	    cimErrorMsg(mainFrame,"Failed to fetch enumeration of instances",ce);
	}
	if (newInstance) {
	    propKeys.addValue(0,STRING_NEW_INSTANCE);
	    propKeyTable.addRowSelectionInterval(length,length);
	}
	propKeyTable.revalidate();
	propKeyTable.repaint();
    }

    //
    // Updates property table
    //
    public void updateTable() {
	Vector properties;  // CIMProperties
	Vector instanceMethods;
	
	
	properties=currentClass.getAllProperties();
	propValues.clearColumn(PROP_COL_TYPE);
	propValues.clearColumn(PROP_COL_NAME);
	propValues.clearColumn(PROP_COL_VALUE);
	propValues.clearColumn(PROP_COL_KEY);
	
	for(int i=0;i<properties.size();i++) {
	    CIMProperty cp=(CIMProperty)(properties.elementAt(i));  
	    String propName=cp.getName();
	    if (cp.isKey()) {
		//
		// Property is used as a key
		//
		propValues.addValue(PROP_COL_KEY,"KEY");
	    } else
		propValues.addValue(PROP_COL_KEY,"");
	    propValues.addValue(PROP_COL_NAME,propName);
	    propValues.addValue(PROP_COL_TYPE,cp.getType().toString());
	    if (currentInstance!=null) {
		CIMProperty prop=currentInstance.getProperty(propName);
		if (prop!=null) {
		    CIMValue val=prop.getValue();
		    
		    if (val!=null && val.getValue()!=null ) {
			CIMDataType dt=val.getType();

			// System.err.println("java type is:"+val.getValue().getClass().getName());
			
			String ret="";
			if (dt.isArrayType()) {
			    Object obj=(val.getValue());
			    if (obj.getClass().isArray()) {
				int size=Array.getLength(obj);
				for(int j=0;j<size;j++) {
				String str=(String)(Array.get(obj,j).toString());
				if (j==0)
				    ret=str;
				else
				    ret=ret.concat(","+str);
				}
			    } else {
				Vector v=(Vector)(val.getValue());
				for(int j=0;j<v.size();j++) {
				    String str;
				    Object o=v.elementAt(j);

				    if (o!=null)
				    	str=o.toString();
				    else
					str="null";

				    if (j==0)
					ret=str;
				    else
					ret=ret.concat(","+str);
				}
			    }
			    propValues.addValue(PROP_COL_VALUE,ret);
			} else if (dt.isReferenceType()) {
			    CIMObjectPath cop=(CIMObjectPath)(val.getValue());
			    propValues.addValue(PROP_COL_VALUE,cop.toString());
			} else {
			    propValues.addValue(PROP_COL_VALUE,val.getValue().toString());
			}
		    } else
			propValues.addValue(PROP_COL_VALUE,"");
		} else {
		    propValues.addValue(PROP_COL_VALUE,"");
		}
	    } else
		propValues.addValue(PROP_COL_VALUE,"");
	}
	
	propValueTable.revalidate();
	propValueTable.repaint();
	
	//
	// Now update methods table
	//
	instanceMethods=currentClass.getAllMethods();
	methods.clearColumn(METHOD_COL_NAME);
	methods.clearColumn(METHOD_COL_RETVAL);
	methods.clearColumn(METHOD_COL_ARGS);
	
	if (realInstance)
	    for(int i=0;i<instanceMethods.size();i++) {
		Vector params;
		String args;
		CIMMethod cp=(CIMMethod)(instanceMethods.elementAt(i));  
		methods.addValue(METHOD_COL_NAME,cp.getName());
		methods.addValue(METHOD_COL_RETVAL,cp.getType().toString());
		params=cp.getParameters();
		args=new String();
		for(int j=0;j<params.size();j++) {
		    CIMParameter nq=((CIMParameter)(params.elementAt(j)));
		    if (j>0)
			args=args.concat(",");
		    args=args.concat(nq.getType().toMOF()+" "+nq.getName());
		}
		methods.addValue(METHOD_COL_ARGS,args);
	    }
	
	methodTable.revalidate();
	methodTable.repaint();

	//
	// Now update relatedobjects
	//
	relatedobjects.clearColumn(RELOBJ_COL_PATH);
	try {
	    if (realInstance && currentInstance!=null) {
		CIMObjectPath cop= new CIMObjectPath(currentInstance.getClassName(),
						currentInstance.getKeyValuePairs());
		cop.setNameSpace(cn.getNameSpace());
		Enumeration enum=cc.associatorNames(cop,null,null,null,null);
		// test only:Enumeration enum=cc.associators(cop,null,null,null,null,true,true,null);
		if (enum!=null) {
		    while (enum.hasMoreElements()) {
			CIMObjectPath aCOP=(CIMObjectPath)(enum.nextElement());
			// test only: Object aCOP=(enum.nextElement());
			relatedobjects.addValue(RELOBJ_COL_PATH,aCOP.toString());
		    }
		}
		relObjTable.revalidate();
		relObjTable.repaint();
	    }
	} catch (CIMException ce) {
	    cimErrorMsg(mainFrame,"Failed to get related objects",ce);
	}
	
	
	//
	// Now update relatedobjects
	//
	associations.clearColumn(ASSOC_COL_PATH);
	try {
	    if (realInstance && currentInstance!=null) {
		CIMObjectPath cop=new CIMObjectPath(currentInstance.getClassName(),
						currentInstance.getKeyValuePairs());
		cop.setNameSpace(cn.getNameSpace());
		Enumeration enum=cc.referenceNames(cop,null,null);
		// test only: Enumeration enum=cc.references(cop,null,null,true,true,null);
		if (enum!=null) {
		    while (enum.hasMoreElements()) {
			CIMObjectPath aCOP=(CIMObjectPath)(enum.nextElement());
			// test only: Object aCOP=(enum.nextElement());
			associations.addValue(RELOBJ_COL_PATH,aCOP.toString());
		    }
		}
		assocTable.revalidate();
		assocTable.repaint();
	    }
	} catch (CIMException ce) {
	    cimErrorMsg(mainFrame,"Failed to get associations",ce);
	}
    }
   


    //
    // Constructs the menu bar
    //
    private JMenuBar constructMenuBar() {
	JMenu		 menu;
	JMenuBar	 menuBar = new JMenuBar();
	JMenuItem	 menuItem;

	// 
	// File menu
	//
	menu = new JMenu("File");
	menuBar.add(menu);

	menuItem = menu.add(new JMenuItem("Exit"));
	menuItem.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	    mainFrame.dispose();
	    }});
	
	// 
	// File menu
	//
	menu = new JMenu("Object");
	menuBar.add(menu);

	menuItemSave = menu.add(new JMenuItem("Save Instance"));
	menuItemSave.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	    saveInstance();
	    }});
	menuItemSave.setEnabled(false);
	
	//
	// Instances can only be created in the class is keyed
	//
	menuItem = menu.add(new JMenuItem("Create New Instance"));
	menuItem.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	    newInstance();
	    }});
	
	menuItem = menu.add(new JMenuItem("Refresh List"));
	menuItem.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	    refreshInstanceList();
	    }});
	
	menuItemRefresh = menu.add(new JMenuItem("Refresh Instance"));
	menuItemRefresh.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	    refreshInstance();
	    }});
	menuItemRefresh.setEnabled(false);
	menuItemDelete = menu.add(new JMenuItem("Delete Instance"));
	menuItemDelete.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	    deleteInstance();
	    }});
	menuItemDelete.setEnabled(false);
	
	menuItemGetProperty = menu.add(new JMenuItem("Get Property Value"));
	menuItemGetProperty.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	    getProperty();
	    }});
	menuItemGetProperty.setEnabled(false);
	
	menuItemSetProperty = menu.add(new JMenuItem("Set Property Value"));
	menuItemSetProperty.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	    setProperty();
	    }});
	menuItemSetProperty.setEnabled(false);
	
	
	menuItemExecute = menu.add(new JMenuItem("Execute method"));
	menuItemExecute.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	    executeMethod();
	    }});
	menuItemExecute.setEnabled(false);
	
	
	menuItemReference = menu.add(new JMenuItem("Reference Browser"));
	menuItemReference.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	    browseReferences();
	    }});
	menuItemReference.setEnabled(false);

	// 
	// Display options
	//
	menu = new JMenu("Display Options");
	menuBar.add(menu);
	final JRadioButtonMenuItem shallowItem=new JRadioButtonMenuItem("Shallow (class only)");
	final JRadioButtonMenuItem deepItem=new JRadioButtonMenuItem("Deep (include children)");
	shallowItem.setSelected(true);
	menuItemReference = menu.add(shallowItem);
	menuItemReference.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
		if (doDeep != !CIMClient.DEEP) {
		    doDeep= !CIMClient.DEEP;
			refreshInstanceList();
		}
		deepItem.setSelected(false);
		shallowItem.setSelected(true);
	    }});
	menuItemReference = menu.add(deepItem);
	menuItemReference.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
		if (doDeep != CIMClient.DEEP) {
		    doDeep = CIMClient.DEEP;
			refreshInstanceList();
		}
		doDeep=CIMClient.DEEP;
		shallowItem.setSelected(false);
		deepItem.setSelected(true);
	    }});
	
	
	return menuBar;
    }
    
    private void instanceNowValid(boolean flag) {
	menuItemReference.setEnabled(flag);
	menuItemRefresh.setEnabled(flag);
	menuItemGetProperty.setEnabled(flag);
	menuItemSetProperty.setEnabled(flag);
	menuItemDelete.setEnabled(flag);
    }
    
    //
    //////////////////////////////////////////////////////////////
    //
    // MENU ACTIONS
    //
    ///////////////////////////////////////////////////////////////
    //
    
    private CIMValue processValue(Object obj,  CIMDataType type) {

	if (type.isReferenceType()) {
	    try {
		CIMObjectPath path=new CIMObjectPath();
		path.parse((String)obj);
		path.setNameSpace(cn.getNameSpace());
		return( new CIMValue(path,CIMDataType.getPredefinedType(
						CIMDataType.REFERENCE)));
	    } catch (CIMException ce) {
		cimErrorMsg(mainFrame,"Failed to create reference value",ce);
		return(null);
	    }
	} else if (!type.isArrayType()) {
	    //
	    // Non array types are straightforward - simply create the
	    // cim value..
	    //
	    return( new CIMValue(obj,type));
	}
	
	//
	// Is an array type, so construct an array
	//
	Vector vector=new Vector();
	char[] values;
	boolean escape=false;
	values=obj.toString().toCharArray();
	int startpos=0;
	int i;
	for(i=0;i<values.length;i++) {
	    if (escape) {
		escape=false;
		continue;
	    }
	    char in=values[i];
	    if (in=='\\')
		escape=true;
	    else if (in==',') {
		String val=new String(values,startpos,i-startpos);
		vector.addElement(val);
		startpos=i+1;
	    }
	}
	String val=new String(values,startpos,i-startpos);
	vector.addElement(val);
	return(new CIMValue(vector,type));			      
    }
    
    
    //
    // Saves the current instance
    //
    private int saveInstance() {
	int row,col;
    
	if (currentInstance==null)
	    return(-1);
	
	for(row=0;row<propValues.getRowCount();row++) {
	    String propertyName=(String)propValues.getValueAt(row,PROP_COL_NAME);
	    Object value;
	    CIMProperty property;
	    
	    value=propValues.getValueAt(row,PROP_COL_VALUE);
	    if (value!=null) {
		property=currentClass.getProperty(propertyName);
		    
		if (property==null)
		    return(-1);
		//
		// Create the cim property for this value
		//
		CIMValue cimValue=processValue(value,property.getType());
		currentInstance.setProperty(propertyName,cimValue);
	    }
	}
    
	//
	// Create new instance
	//
	if (newInstance) {
	    try {
		Vector keys=currentInstance.getKeyValuePairs();
		Vector dupKeys=new Vector();	// we duplicate the keys because the values
						// may get modified once they are being used
						// in the object path
		for(int i=0;i<keys.size();i++) {
		    CIMProperty cp=(CIMProperty)(keys.elementAt(i));
		    dupKeys.addElement((CIMProperty)(cp.clone()));
		}
		currentInstancePath=new CIMObjectPath(currentInstance.getClassName(),
						      dupKeys);
		currentInstancePath.setNameSpace(cn.getNameSpace());
		cc.createInstance(currentInstancePath,currentInstance);
	    } catch (CIMException ce) {
		JOptionPane.showMessageDialog(mainFrame,
			    ce.toString(),
			    "Instance not created",
			    JOptionPane.ERROR_MESSAGE);
		return(-1);
	    }
	    newInstance=false;
	    realInstance=true;
	    //
	    // Refresh is now possible (it might have been a create which
	    // doesn't allow a refresh until the object is committed).
	    //
	    instanceNowValid(true);
	    updateInstanceList();
	    updateTable();
	    return(0);
	}
	//
	// Else update old instance
	try {
	    cc.setInstance(currentInstancePath,currentInstance);
	} catch (CIMException ce) {
	    cimErrorMsg(mainFrame,"Failed to update instance",ce);
	    return(-1);
	}
	realInstance=true;
	return(0);
    }

    
    //
    // Creates a new instance
    //
    private void newInstance() {
	CIMInstance ce; // =new CIMInstance();
	CIMProperty cp=new CIMProperty();

	//
	// Is a new instance already being created?
	//
	if (newInstance) {
	    Object[] options = {"Save Instance","Cancel","Ignore Creation"};
		int ret=JOptionPane.showOptionDialog(mainFrame,
			    "Do you wish to save the instance that is being created?",
			    "Save new instance",
			    JOptionPane.YES_NO_OPTION,
			    JOptionPane.ERROR_MESSAGE,
			    null,options,options[1]);
		switch (ret) {
		case 0:
		    if (saveInstance()!=0)
			return;
		    break;
		case 1:
		    return;
		case 2:
		    //
		    // Trash the creation so far performed
		    //
		    newInstance=false;
		    break;
		} 
	}
	ce=currentClass.newInstance();

	currentInstance=ce;
	    
	newInstance=true;
	realInstance=false;	// this isn't a real instance until
				// its saved..
	propValues.setColumnEditable(PROP_COL_VALUE,true);
	//
	// For a new instance previous method selections
	// are lost. Also reset currentMethod so we spot the
	// user selecting a method.
	//
	currentMethod=-1;
	methodTable.clearSelection();    
	menuItemExecute.setEnabled(false);
		
	updateInstanceList();
	updateTable();
	instanceNowValid(false);
	menuItemSave.setEnabled(true);
	menuItemReference.setEnabled(true);
    }

    //
    // Refreshes display
    //
    private void refreshInstanceList() {
	updateInstanceList();
    }
    
    //
    // Refreshes display for this instance
    //
    private void refreshInstance() {
	try {
	    currentInstance=cc.getInstance(currentInstancePath,false);
	} catch (CIMException ce) {
	    JOptionPane.showMessageDialog(mainFrame,
			"Failed to retrieve the instance:\n"+currentInstancePath,
			"Error",
			JOptionPane.ERROR_MESSAGE);
	}
	updateTable();
    }


    
    
    //
    // Executes a method
    //
    private void executeMethod() {
	String name=methods.getValueAt(currentMethod,0).toString();
	new CBROWMethod(mainFrame,currentClass,cc,currentInstancePath,name);
    }

     
    /**
     * Deletes an instance
     * 
     */
    private void deleteInstance() {
	try {
	    cc.deleteInstance( currentInstancePath );
	} catch (CIMException ce) {
	    JOptionPane.showMessageDialog(mainFrame,
			"Failed to delete the instance:\n"+currentInstancePath,
			"Error",
			JOptionPane.ERROR_MESSAGE);
	}
	int oldIndex=currentIndex;	
	currentIndex=-1;
	currentMethod=-1;
	updateInstanceList();
	instanceNowValid(false);
	loadInstanceList(oldIndex);
	propKeyTable.addRowSelectionInterval(oldIndex,oldIndex);
	updateTable(); 
   }
   
    
    
    
    
    
    
    
    
    
    
    
    class PropertyDisplay {
	CIMObjectPath objPath;
	String methodName;
	JDialog argFrame;
	int PROPVAL_COL_WIDTH = 300;	    // width
	int PROPVAL_COL_MARGIN = 20;	    // margin for dialog
	int PROPVAL_COL_HEIGHT = 300;	    // height	      
	int PROPVAL_COL_BHEIGHT = 100;	    // button height
	
	Vector in = new Vector();
	Vector out = new Vector();
	
	PropertyDisplay(CIMObjectPath iobjPath,boolean setflag) {
	    String title;
	    
	    objPath=iobjPath;
	    if (setflag)	    
		title = "Set Property Value";
	    else
		title = "Get Property Value";
	    
	    argFrame = new JDialog(mainFrame,title,true);
	    
	    //
	    // Now position the window
	    //
	    Point windowPos=mainFrame.getLocationOnScreen();
	    argFrame.setLocation(windowPos.x+30,windowPos.y+30);
	    
	    JPanel jp=new JPanel();
	    GridBagLayout gridbag=new GridBagLayout();
	    GridBagConstraints cons=new GridBagConstraints();
	    jp.setLayout(gridbag);
	    
	    Vector properties=currentClass.getAllProperties();
	    String[] propNames=new String[properties.size()];
	    for(int i=0;i<properties.size();i++) {
		CIMProperty cp=(CIMProperty)(properties.elementAt(i));
		propNames[i]=cp.getName();
	    }
	    final JComboBox propList=new JComboBox(propNames);

	    final JTextField propValue=new JTextField(15);
	    propValue.setEditable(setflag);

	    // Add listener to drop down list
	    //
	    propList.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent e) {
		    JComboBox jc=(JComboBox)(e.getSource());
		    String propNamel=(String)jc.getSelectedItem();
		    propValue.setText(getPropertyValue(propNamel));
		}
	    });
	    
	    //
	    // Add listener to input field
	    propValue.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent e) {
		    JTextField jc=(JTextField)(e.getSource());
		    String propNamel=(String)propList.getSelectedItem();
		    setPropertyValue(propNamel,(String)jc.getText());
		}
	    });
	
	    //
	    // Set value up, on basis of currently selected item
	    //
	    String propName=(String)propList.getSelectedItem();
	    propValue.setText(getPropertyValue(propName));
	    
	    JButton rbutton=new JButton(" Refresh ");
	    rbutton.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent e) {
		    //
		    // Set value up, on basis of currently selected item
		    //
		    String propName1=(String)propList.getSelectedItem();
		    propValue.setText(getPropertyValue(propName1));
	    }});

	    JButton jb=new JButton("OK");
	    jb.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent e) {
		    argFrame.dispose();
	    }});
	    cons.insets=new Insets(10,10,10,10);
	    cons.weightx=0.5;
	    cons.weighty=0.2;
	    cons.fill=GridBagConstraints.HORIZONTAL;
	    cons.gridx=0;
	    cons.gridy=0; 
	    gridbag.setConstraints(propList,cons);
	    
	    jp.add(propList);
	    
	    
	    cons.gridx=1;
	    cons.gridy=0;
	    gridbag.setConstraints(propValue,cons);
	    jp.add(propValue);
	    
	    cons.gridx=0;
	    cons.gridy=1;
	    cons.fill=0;
	    cons.anchor=GridBagConstraints.WEST;
	    gridbag.setConstraints(rbutton,cons);
	    jp.add(rbutton);
	    
	    cons.gridx=1;
	    cons.gridy=2; 
	    cons.anchor=GridBagConstraints.SOUTHEAST;
	    gridbag.setConstraints(jb,cons);
	    jp.add(jb);
	
	    Container jp2=argFrame.getContentPane();
	    jp2.add(jp);
	
	    argFrame.pack();
	    argFrame.addWindowListener( new WindowAdapter() {
	    public void windowClosing(WindowEvent e) {
		    argFrame.dispose();
		}
	    });
	    updateTable();
	    argFrame.show();
	}
	

        //
        // Viktor Mihajlovski Fixes: Date - 08/13/02
        // Fix for the browser, when non-string properties are being received
        //
	private String getPropertyValue(String propName) {
	    CIMValue retValue;
	    CIMDataType dT;
		
	    try {
		retValue=cc.getProperty(currentInstancePath,propName);
	    } catch (CIMException ce) {
		cimErrorMsg(argFrame,"Failed to fetch property "+propName,ce);
		return("");
	    }
	    if (retValue==null) {
		return("");
	    }

	    dT = retValue.getType();
	    if (dT.equals(new CIMDataType(CIMDataType.SINT8)) || 
		dT.equals(new CIMDataType(CIMDataType.SINT16)) ||
		dT.equals(new CIMDataType(CIMDataType.SINT32)) ||
		dT.equals(new CIMDataType(CIMDataType.UINT8)) ||
		dT.equals(new CIMDataType(CIMDataType.UINT16)) ||
		dT.equals(new CIMDataType(CIMDataType.UINT32)) )
		return((String)(retValue.getValue().toString()));
	    else 
	    return((String)retValue.getValue());
	}
	
        //
        // Viktor Mihajlovski Fixes: Date - 08/13/02
        // Fix for the browser, when non-string properties are being received
        //
	private void setPropertyValue(String propName,String propValue) {
	    CIMDataType dT;
	    CIMValue val;
	
	    try {
		val = cc.getProperty(currentInstancePath, propName);
		dT = val.getType();
		if (dT.equals(new CIMDataType(CIMDataType.SINT8)) ||
	                dT.equals(new CIMDataType(CIMDataType.SINT16)) ||
			dT.equals(new CIMDataType(CIMDataType.SINT32)) ||
			dT.equals(new CIMDataType(CIMDataType.UINT8)) ||
			dT.equals(new CIMDataType(CIMDataType.UINT16)) ||
			dT.equals(new CIMDataType(CIMDataType.UINT32)) )
		cc.setProperty(currentInstancePath,propName,
			new CIMValue((Object)(new Integer(propValue)), dT));
		else
		cc.setProperty(currentInstancePath,propName,
			new CIMValue(
			    propValue,CIMDataType.getPredefinedType(CIMDataType.STRING)));
	    } catch (CIMException ce) {
		cimErrorMsg(argFrame,"Failed to set property "+propName,ce);
		return;
	    }
	}
    }

    
    
    
    
    private void getProperty() {
	PropertyDisplay pd=new PropertyDisplay(currentInstancePath,false);
    }
    
    private void setProperty() {
	PropertyDisplay pd=new PropertyDisplay(currentInstancePath,true);
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    class ReferenceDisplay {
	CIMObjectPath objPath;
	JDialog argFrame;
	final JComboBox RefValList;
	final int PROPVAL_COL_WIDTH = 300;	// width
	final int PROPVAL_COL_MARGIN = 20;	// margin for dialog
	final int PROPVAL_COL_HEIGHT = 300;	// height	  
	final int PROPVAL_COL_BHEIGHT = 100;	    // button height
	final int VERT_MARGIN=10;	// marging around vertical
	final int HORIZ_MARGIN=10;	// marging around vertical
	final int VERT_SPACER=10;	// spacing vertically between items
	final int HORIZ_SPACER=40;	// spacing vertically between items
	
	Vector in = new Vector();
	Vector out = new Vector();
	Hashtable refsToPaths=new Hashtable();
	
	ReferenceDisplay(CIMObjectPath iobjPath) {
	    final Vector properties=currentInstance.getProperties();
	    int maxSize=0;	
	    for(maxSize=0;maxSize<properties.size();maxSize++) {
		CIMProperty cp=(CIMProperty)(properties.elementAt(maxSize));
		if (cp.getType().isReferenceType())
		    maxSize++;
	    }
	    if (maxSize==0) {
		//
		// No references to modify
		//
		throw new InstantiationError();
	    }		
	    objPath=iobjPath;
	    argFrame = new JDialog(mainFrame,"Edit References",true);

	    //
	    // Now position the window
	    //
	    Point windowPos=mainFrame.getLocationOnScreen();
	    argFrame.setLocation(windowPos.x+30,windowPos.y+30);

	    JPanel jpWidth=new JPanel();
	    
	    JPanel jp=new JPanel();
	    jp.setLayout(new BoxLayout(jp,BoxLayout.Y_AXIS));	    
	    jp.setAlignmentX(Component.LEFT_ALIGNMENT);
	    
	    JPanel jpRefName=new JPanel();
	    jpRefName.setLayout(new BoxLayout(jpRefName,BoxLayout.X_AXIS));
	    jpRefName.setAlignmentX(Component.LEFT_ALIGNMENT);
	    
	    String[] propNames=new String[maxSize];	
	    maxSize=0;
	    for(int i=0;i<properties.size();i++) {
			CIMProperty cp=(CIMProperty)(properties.elementAt(i));
			if (cp.getType().isReferenceType()) {
			    propNames[maxSize++]=cp.getName();
			}
		}
		
	    final JComboBox propList=new JComboBox(propNames);
	    jpRefName.add(propList);
	    jpRefName.add(new JLabel("="));
	    jpRefName.add(Box.createHorizontalGlue());
	    jpRefName.setMaximumSize(jpRefName.getPreferredSize());
	    jpRefName.setMinimumSize(jpRefName.getPreferredSize());
	    
	    JPanel jpValue=new JPanel();
	    jpValue.setLayout(new BoxLayout(jpValue,BoxLayout.X_AXIS));
	    jpValue.setAlignmentX(Component.LEFT_ALIGNMENT);
	    String[] values=new String[1];
	    values[0]="null";
	    RefValList=new JComboBox(values);
	    //
	    // Add listener to drop down list
	    //
	    propList.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent e) {
		    JComboBox jc=(JComboBox)(e.getSource());
		    String propName1=(String)jc.getSelectedItem();
		    for(int j=0;j<properties.size();j++) {
			CIMProperty  cp=(CIMProperty)(properties.elementAt(j));
			if (propName1.equalsIgnoreCase(cp.getName())) {
			    CIMDataType dt=cp.getType();
			    setInstanceList(dt.getRefClassName());
			}
		    }
		}
	    });
	    
	    jpValue.add(RefValList);
	    
	    
	    propList.setSelectedIndex(0);
	    
	    JPanel jpButton=new JPanel();
	    jpButton.setLayout(new BoxLayout(jpButton,BoxLayout.X_AXIS));
	    jpButton.setAlignmentX(Component.CENTER_ALIGNMENT);
	    JButton jbOk=new JButton("OK");
	    jbOk.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent e) {
		    String selPropName=(String)propList.getSelectedItem();
		    String selRefName=(String)RefValList.getSelectedItem();

		    try {
			CIMObjectPath cop=(CIMObjectPath)(refsToPaths.get(selRefName));
			if (cop==null)
			    throw new CIMException(CIMException.CIM_ERR_FAILED,
					"Could not locate reference object");
			for(int j=0;j<properties.size();j++) {
			    CIMProperty  cp=(CIMProperty)(properties.elementAt(j));
			    if (selPropName.equalsIgnoreCase(cp.getName())) {
				cp.setValue(new CIMValue(cop,CIMDataType.getPredefinedType(
							    CIMDataType.REFERENCE)));
				break;
			    }
			}
		    } catch (CIMException ce) {
			cimErrorMsg(argFrame,"Failed to set REF property",ce);
		    }
		    propValueTable.revalidate();
		    propValueTable.repaint();
		    argFrame.dispose();
		    updateTable();
	    }});
	    JButton jbCancel=new JButton("CANCEL");
	    jbCancel.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent e) {
		    argFrame.dispose();
	    }});
	    jpButton.add(Box.createHorizontalGlue());
	    jpButton.add(jbOk);
	    jpButton.add(Box.createRigidArea(new Dimension(HORIZ_SPACER,0)));
	    jpButton.add(jbCancel);
	    jpButton.setBorder(BorderFactory.createEmptyBorder(
				    0,VERT_SPACER,HORIZ_MARGIN,VERT_MARGIN));
	    
	    jp.add(jpRefName);
	    jp.add(Box.createRigidArea(new Dimension(0,VERT_SPACER)));
	    jp.add(jpValue);

	    jp.setBorder(BorderFactory.createEmptyBorder(
				    HORIZ_MARGIN,VERT_MARGIN,VERT_SPACER,HORIZ_MARGIN));
	    Container jp2=argFrame.getContentPane();
	    jp2.add(jp,BorderLayout.NORTH);
	    jp2.add(jpButton,BorderLayout.SOUTH);
	    argFrame.pack();
	    
	    argFrame.addWindowListener( new WindowAdapter() {
	    public void windowClosing(WindowEvent e) {
		    argFrame.dispose();
		}
	    });
	    argFrame.show();
	}

	private void setInstanceList(String className) {
	    RefValList.removeAllItems();
	    Enumeration elist;
	    
	    try {
		Hashtable refsToPaths=new Hashtable();
		elist=cc.enumInstances(new CIMObjectPath(className,
					cn.getNameSpace()),
					doDeep);
		while (elist.hasMoreElements()) {
		    Object obj=elist.nextElement();
		    if (obj instanceof CIMObjectPath) {
			String refName=((CIMObjectPath)obj).toString();
			RefValList.addItem(((CIMObjectPath)obj).toString());
			refsToPaths.put(refName,obj);
		    } 
		}
	    } catch (CIMException ce) {
		cimErrorMsg(argFrame,"Failed to get instances",ce);
	    }
	}
    }

    
    private void browseReferences() {
	try {
	    ReferenceDisplay pd=new ReferenceDisplay(currentInstancePath);
	} catch (Exception e) {
	    JOptionPane.showMessageDialog(mainFrame,
			"No references are defined on this instance",
			"Error",
			JOptionPane.ERROR_MESSAGE);
	}
    }
}
