//
// XMLClass.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 XMLClass.java
// 
// The Initial Developer of the Original Code is David Simons.
//
// Contributor(s):
//
//
// 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: XMLClass.java,v 1.1 2003/07/17 18:32:55 kumpf Exp $
//
// $Log: XMLClass.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:17:34  karl
// import of SNIA 0_7
//
// Revision 1.8  2001/07/22 13:12:00  davidsi
// - The object pathes in the key-value pairs for association class instances
//   are mistyped. They are of type String but should be of type
//   CIMObjectPath. (from Viktor).
//
// Revision 1.7  2000/11/06 19:10:17  davidsi
// - Reconciled error ids.
//
// Revision 1.6  2000/08/16 05:59:59  shawn
// merge P_TOMCAT31 branch
//
// Revision 1.5.8.1  2000/08/10 00:03:36  shawn
// head merge
//
// Revision 1.5  2000/05/11 10:11:23  davidsi
// - Fixed tabs.
//
// Revision 1.4  2000/05/06 17:20:02  davidsi
// - Brought in line with SUN WBEM APIs 2.2
//
// Revision 1.3  2000/04/09 14:34:39  davidsi
// - Fixed handling of parameters.
//
// Revision 1.2  2000/02/13 15:10:05  davidsi
// - Added text to cover re-use of Solaris WBEM APIs.
//
// Revision 1.1.1.1  2000/02/06 16:41:02  davidsi
// Initial version.
//
//
//
package org.snia.wbemcmd.xml;

import java.util.Enumeration;
import java.util.Vector;
import java.net.MalformedURLException;
import org.snia.wbem.cim.CIMException;
import org.snia.wbem.cim.CIMObjectPath;
import org.snia.wbem.cim.CIMInstance;
import org.snia.wbem.cim.CIMClass;
import org.snia.wbem.cim.CIMQualifier;
import org.snia.wbem.cim.CIMValue;
import org.snia.wbem.cim.CIMDataType;
import org.snia.wbem.cim.CIMProperty;
import org.snia.wbem.cim.CIMNameSpace;
import org.snia.wbem.cim.CIMQualifierType;
import org.snia.wbem.cim.CIMQualifier;
import org.snia.wbem.cim.CIMFlavor;
import org.snia.wbem.cim.CIMParameter;
import org.snia.wbem.cim.CIMMethod;


public abstract class  XMLClass extends XMLOperationGeneric {

    
    //
    // Determines a namespace from multiple <NAMESPACE> elements
    //
    public static String getNameSpace(XMLNode localNameNode) {
	    //
	    // Find NAMESPACE elements
	    //
	    String nameSpace="";
	    boolean firstTime=true;
	    for(;localNameNode!=null;localNameNode=localNameNode.getNext()) {
		
		XMLAttribute nattr;
		Vector nodeattrs;
			    
		if (localNameNode.getToken()==XMLNode.XML_ELEMENT_NAMESPACE) {
		    String pname=localNameNode.getAttribute(
				       XMLEnumerateClassNames.paramName);
		    if (pname!=null && !pname.equals("")) {
			if (firstTime) {
			    firstTime=false;
			    nameSpace=nameSpace.concat(pname);
			} else {
			    nameSpace=nameSpace.concat("/"+pname);
			}
		    }
		}
	    }
	    return(nameSpace);
    }
    
	
    
    //
    // Parses  VALUE.OBJECTWITHPATH and VALUE.OBJECTWITHLOCALPATH
    // Vector is used to return instance or class that was in the XML
    // stream
    //
    static public CIMObjectPath getObjectWithPath(XMLNode node,Vector v) throws CIMException {
	int token=node.getToken();
    
	XMLNode nextNode=node.getChild();
	if (nextNode==null)
		throw new CIMException(CIMException.CIM_ERR_FAILED,
				"Missing element in object with path declaration");
	if (token==XMLNode.XML_ELEMENT_VALUE_OBJECTWITHPATH) {
		CIMObjectPath tmpcop=new CIMObjectPath(nextNode);
			
		token=nextNode.getToken();
		if (token==XMLNode.XML_ELEMENT_CLASSPATH) {
		    nextNode=nextNode.mustNextElement(XMLNode.XML_ELEMENT_CLASS);
		    v.addElement(readClass(nextNode,tmpcop));
		} else if (token==XMLNode.XML_ELEMENT_INSTANCEPATH) {
		    nextNode=nextNode.mustNextElement(XMLNode.XML_ELEMENT_INSTANCE);
		    v.addElement(readInstance(nextNode,tmpcop));
		} else 
		    throw new CIMException(CIMException.CIM_ERR_FAILED,
			"Require instance or class in object with path declaration");
		return(tmpcop);
	} else if (token==XMLNode.XML_ELEMENT_VALUE_OBJECTWITHLOCALPATH) {
	    CIMObjectPath tmpcop=new CIMObjectPath(nextNode);
			
	    token=nextNode.getToken();
	    if (token==XMLNode.XML_ELEMENT_LOCALCLASSPATH) {
		nextNode=nextNode.mustNextElement(XMLNode.XML_ELEMENT_CLASS);
		v.addElement(readClass(nextNode,tmpcop));
	    } else if (token==XMLNode.XML_ELEMENT_LOCALINSTANCEPATH) {
		nextNode=nextNode.mustNextElement(XMLNode.XML_ELEMENT_INSTANCE);
		v.addElement(readInstance(nextNode,tmpcop));
	    } else 
		throw new CIMException(CIMException.CIM_ERR_FAILED,
		    "Require instance or class in object with path declaration");
	    return(tmpcop);
	}
	return(null);
    }
    
	
    static CIMClass readClass(XMLNode childNode,CIMObjectPath path) throws CIMException {
	if (childNode.getToken()==XMLNode.XML_ELEMENT_CLASS) { 
	    CIMClass cimClass=new CIMClass(childNode);
	    //
	    // NOTE: Classes always go in a known location regardless of
	    // the path that might have been passed in!
	    //
	    path.setObjectName(cimClass.getName());
	    return(cimClass);
	}
	throw new CIMException(CIMException.CIM_ERR_FAILED,
		    "Needed <CLASS>, found "+childNode.getToken());
    }

    static CIMInstance readInstance(XMLNode childNode,CIMObjectPath path) throws CIMException {
	if (childNode.getToken()==XMLNode.XML_ELEMENT_INSTANCE) { 
	    CIMInstance cimInstance=new CIMInstance(childNode);
	    return(cimInstance);
	}
	throw new CIMException(CIMException.CIM_ERR_FAILED,
		    "Needed <INSTANCE>, found "+childNode.getToken());
    }
    
    
    

    
    
    
    
    
// Now find XML_ELEMENT_INSTANCENAME element
    //
    // encType should XMLNode.XML_ELEMENT_INSTANCENAME or XMLNode.XML_PARAM_INSTANCENAME
    //
    // Either hdl should be set (on the server side) or hto/nameSpace (on the
    // client side) since this function may need to retrieve class information
    // so as to determine which properties are keyed - This only required
    // when a <KEYVALUE> is provided without a <KEYBINDING>
    //
    // This implementation avoids returning <KEYVALUE> without
    // keybinding because it creates additional work - rather than saving
    // overheads.
    //
    //
    public static void getInstanceName( 
		    XMLNode result, CIMObjectPath cimPath) throws CIMException {
	    Vector keyVect=new Vector();
	    CIMProperty cp;
	    result=result.mustFindElement(XMLNode.XML_ELEMENT_INSTANCENAME);
	    String thisClassName=result.getAttribute(XMLP_CLASSNAME);
	    cimPath.setObjectName(thisClassName);
	    
	    XMLNode sub=result.getChild();
	    int token=sub.getToken();
	    if (token==XMLNode.XML_ELEMENT_KEYBINDING) {
		for(;sub!=null;sub=sub.getNext()) {
		    CIMValue val;
		    String name;
		    XMLNode keyval;
		    
		    sub.mustElement(XMLNode.XML_ELEMENT_KEYBINDING);
		    name=sub.getAttribute(paramName);
		    keyval=sub.getChild();
		    token=keyval.getToken();
		    if (token==XMLNode.XML_ELEMENT_KEYVALUE ||
			token==XMLNode.XML_ELEMENT_VALUE_REFERENCE) {
			// mihajlov: No need? to transform refs to string
			val=new CIMValue(keyval);
		    } else {
			throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
			    "Not a valid instance declaration");
		    }
		    cp=new CIMProperty();
		    cp.setName(name);
		    cp.setType(val.getType());
		    cp.setValue(val);
		    keyVect.addElement(cp);
		}
	    } else if (token==XMLNode.XML_ELEMENT_KEYVALUE || 
		       token==XMLNode.XML_ELEMENT_VALUE_REFERENCE) {
		CIMClass cimClass;
		String value;
		CIMObjectPath cop=new CIMObjectPath(thisClassName,
						    cimPath.getNameSpace());
		
		if (token==XMLNode.XML_ELEMENT_VALUE_REFERENCE) {
		    //
		    // calling getPropertyValue() will get is the
		    // value of reference
		    //
		    CIMValue val=new CIMValue(sub);
		    value=val.getValue().toString();
		} else {
		    value=sub.getUnescapeText();
		} 
		/*
		    //
		    // Painful! If we don't get a property name back, then we must
		    // issue a request to get the class so we can determine what the
		    // one and only property name is..
		    //
		    if (hdl!=null)
			cimClass=hdl.getClass(cop,false);
		    else
			throw new CIMException(CIMException.CIM_ERR_FAILED,
					    "Cannot decode name of property with key");
		    Vector v=cimClass.getKeys();
		    if (v.size()>1) 
			throw new CIMException(CIMException.CIM_ERR_FAILED,
					    "Only a single key was expected with KEYVALUE");
		    String propertyName=((CIMProperty)(v.elementAt(0))).getName();
		    cp=new CIMProperty();
		    cp.setName(propertyName);
		*/
		cp=new CIMProperty();
		cp.setType( CIMDataType.getPredefinedType(CIMDataType.STRING));
		cp.setValue(new CIMValue(value,
				 CIMDataType.getPredefinedType(CIMDataType.STRING)));
		keyVect.addElement(cp); 	
	    } else {
		throw new CIMException(CIMException.CIM_ERR_FAILED,
					"not a valid instance declaration");
	    }
	cimPath.setKeys(keyVect);

    }
    

    
    
    protected static String instanceNameToKey(CIMObjectPath path,
					    String parameterName)
		    throws CIMException {
	String text;
	
	if (parameterName!=null)
	    text="<IPARAMVALUE NAME=\""+parameterName+"\">";
	else
	    text="";
	
	try {
	    text=text.concat(path.toXml()); 
	} catch (MalformedURLException me) {
	    throw new CIMException(CIMException.CIM_ERR_FAILED,me);
	}
	if (parameterName!=null)
	    text=text.concat("</IPARAMVALUE>");
	return(text);
    }
    
    
    
    

}
