//
// XMLInvokeMethod.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 XMLInvokeMethod.java
// 
// The Initial Developer of the Original Code is David Simons.
//
// Contributor(s):Scott Baker, Nag Boranna
// 	
//
package org.snia.wbemcmd.xml;

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.CIMValue;
import org.snia.wbem.cim.CIMMethod;
import org.snia.wbem.cim.CIMParameter;
import org.snia.wbem.cim.CIMInstance;
import org.snia.wbem.cim.CIMProperty;
import org.snia.wbem.cim.CIMClass;
import org.snia.wbem.cim.CIMDataType;
import org.snia.wbem.client.CIMOMHandle;
import org.snia.wbemcmd.cimom.CIMOMCast;
import org.snia.wbemcfg.*;


public class XMLInvokeMethod extends XMLClass {

    //
    // Reads paramters for extrinsinc method calls
    //
    // Paramlist is the list of parameters (in and out) for this method, params will
    // be returned with input parameters in the same order as IN's were found in the
    // paramlist.
    // 
    // paramlist is a vector of CIMParameter
    // params is a vector of CIMValues
    // 
    static private XMLNode getParameters(XMLNode node, Vector paramlist, Vector params) throws CIMException {
	int token;
	
	//
	// Process parameters
	//
	for(;node!=null;node=node.getNext()) {
	    //
	    // Only process PARAMVALUE tags
	    //
	    if (node.getToken()!=XMLNode.XML_ELEMENT_PARAMVALUE)
		continue;
	    String parameterName=node.getAttribute(paramName);
	    if (parameterName==null)
		throw new CIMException("can't find parameterName Name");

	    XMLNode childNode=node.getChild();
	    if (childNode!=null) {
		CIMValue value=new CIMValue(childNode);
		//
		// Now insert into the right position of the params vector
		//
		for(int i=0,cnt=0;i<paramlist.size();i++) {
		    CIMParameter cpa=(CIMParameter)(paramlist.elementAt(i));
		    if (cpa.getName().equalsIgnoreCase(parameterName)) {
			while (cnt>=params.size())
			    params.addElement(null);
	 	 	//
			// Get ready to perform a cast from the string that came
			// over in the xml to the type used by the parameter
			// 
		        CIMValue castValue=CIMOMCast.castDataType(value,
								 cpa.getType());
                        //HP-Nag
			//if (GlobalConfig.callMethodsWithValues)
			//    params.setElementAt(castValue,cnt);
			//else
			    params.setElementAt(new CIMProperty(parameterName,
							castValue),cnt);
			break;
		    } else if (cpa.getQualifier("IN")!=null)  {
			cnt++;
		    }
		}
	    }
 	}
	return(node);
    }
    
    public void execute(HTTPWriter pw,XMLNode node,CIMObjectPath path,CIMOMHandle hdl)
	    throws CIMException, MalformedURLException {
	throw new CIMException(CIMException.CIM_ERR_NOT_SUPPORTED);
    }
    
    
    //
    //
    // Invokes a method over XML/HTTP
    //
    // @param output The HTTP output channel
    // @param path The path of the object on which the method is being invoked
    //		   this can be a class or instance
    // @param inParams A vector of CIMProperty for inbound values
    // @param outParams A vector of CIMProperty for outbound values
    // @throws CIMException
    //
    public static CIMValue invokeMethod(HTTPOutput output,
		    CIMObjectPath path,
		    String methodName,
		    Vector inParams,	
		    Vector outParams) throws CIMException
    {
	XMLNode result;
	String pathText;

	//
	// New 2.2 support
	//
	CIMClass cl = null;
	try {
	    if( (path.getKeys() != null) && (path.getKeys().size() != 0) ) {
		CIMInstance ci=XMLGetInstance.getInstance(output,path,false);

		if (ci==null)
		    throw new CIMException(CIMException.CIM_ERR_NOT_FOUND,
			"Looking for instance "+path);
		pathText="<LOCALINSTANCEPATH>"+
			 path.getFullNameSpace().toXml(true)+
			 instanceNameToKey(path,null)+
			 "</LOCALINSTANCEPATH>";
		// for getOutParameters use
		cl=XMLGetClass.getClass(output,path,false);

		path.setObjectName(ci.getClassName());
	    } else {
		
		//
		// Not an instance, try for a class
		//
		// for getOutParameters usage
		cl=XMLGetClass.getClass(output,path,false);

		pathText="<LOCALCLASSPATH>"+
			 path.getFullNameSpace().toXml(true)+
			 "<CLASSNAME NAME=\""+path.getObjectName()+"\"/>"+
			 "</LOCALCLASSPATH>";
		
	    }	
	} catch (MalformedURLException me) {
	    throw new CIMException("Failed to build request for execution");
	}

	output.setMethod(methodName);

//HP-Nag
/*
    if (GlobalConfig.callMethodsWithValues) {
        if ((inParams != null) && (inParams.size() > 0)) {
            if (inParams.elementAt(0) instanceof CIMValue) {
                CIMClass theClass = XMLGetClass.getClass(output, path, false);
                CIMMethod theMethod = theClass.getMethod(methodName);
                Vector methodParameterDefinitions = theMethod.getParameters();
                if (methodParameterDefinitions != null) {
                    int currentInboundParameterDefinitionIndex = 0;
                
                    for (int currentParameterDefinition = 0; currentParameterDefinition < methodParameterDefinitions.size(); currentParameterDefinition++) {
                        CIMParameter cimParameter = (CIMParameter)methodParameterDefinitions.elementAt(currentParameterDefinition);
                        if (cimParameter.getQualifier("in") != null) {
                            if (currentInboundParameterDefinitionIndex >= inParams.size()) {
                                throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER, "The method did not receive enough parameters");
                            }
                            CIMValue cimValue = (CIMValue)inParams.elementAt(currentInboundParameterDefinitionIndex++);
                            pathText = pathText.concat(inputParameterXml(cimParameter.getName(), cimValue));
                        }
                    }
                    if (currentInboundParameterDefinitionIndex < inParams.size()) {
                        throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER, "The method received too many parameters");
                    }
                }
            }    
            else if (inParams != null) {
                for (int i = 0; i < inParams.size(); i++) {
                    CIMProperty cimProperty = (CIMProperty)inParams.elementAt(i);
                    pathText = pathText.concat(inputParameterXml(cimProperty.getName(), cimProperty.getValue()));
                }
            }
        }
    }
    else 
*/
        {
            if (inParams != null) {
                for (int i = 0; i < inParams.size(); i++) {
                    CIMProperty cimProperty = (CIMProperty)inParams.elementAt(i);
                    pathText = pathText.concat(inputParameterXml(cimProperty.getName(), cimProperty.getValue()));
                }
            }
        }

        // Attn: 09/18/02 - (Jenny) result is now the XML method response
        //
        // process the request
        //
        result=extrinsicMethod(output,path,methodName,pathText);

        //
	// extract the return value from the response
        //
        XMLNode retValueNode;
	CIMValue retVal;
	CIMMethod method=cl.getMethod(methodName);

        retValueNode = getReturnValue(result);
	if (retValueNode != null && 
            retValueNode.getToken() == XMLNode.XML_ELEMENT_VALUE) 
        {
	    retVal = new CIMValue(retValueNode.getUnescapeText(),
                                  method.getType());
        }
	else 
        {
	    throw new CIMException(CIMException.CIM_ERR_FAILED);
	}

        //
	// extracting values return from the outParams
        //
        Vector parameters=method.getParameters();
        getOutParameters(result, parameters, outParams);
	   
        return retVal;
    }	
    
    // use to extract the outParams value from the XMLNode returned
    static private XMLNode getOutParameters(
        XMLNode node, Vector paramlist, Vector params) throws CIMException {

        int token;

        //
        // Process parameters
        //
        for(;node!=null;node=node.getNext()) {
            //
            // Only process PARAMVALUE tags
            //

            if (node.getToken()!=XMLNode.XML_ELEMENT_PARAMVALUE)
                continue;
            String parameterName=node.getAttribute(paramName);
            if (parameterName==null)
                throw new CIMException("can't find parameterName Name");

            XMLNode childNode=node.getChild();
            if (childNode!=null) {
                CIMValue value=new CIMValue(childNode);
                //
                // Now insert into the right position of the params vector
                //
                for(int i=0,cnt=0;i<paramlist.size();i++) {
                    CIMParameter cpa=(CIMParameter)(paramlist.elementAt(i));
                    if (cpa.getName().equalsIgnoreCase(parameterName)) {
                        while (cnt>=params.size())
                            params.addElement(null);
                        //
                        // Get ready to perform a cast from the string that came
                        // over in the xml to the type used by the parameter
                        //
                        CIMValue castValue=CIMOMCast.castDataType(value,cpa.getType());
                        //HP-Nag
                        //if (GlobalConfig.callMethodsWithValues)
                        //    params.setElementAt(castValue,cnt);
                        //else
                            params.setElementAt(new CIMProperty(parameterName,
                                                        castValue),cnt);
                        break;
                    } else if (cpa.getQualifier("OUT")!=null)
                        cnt++;
                }
            }
        }
        return(node);
    }


    // Attn: 09/16/02 - (Jenny)  
    //
    // extract the return value from the extrinsic method response 
    //
    static private XMLNode getReturnValue(XMLNode node) throws CIMException {
	int token;

	//
	// Only process RETURNVALUE tag
	//
	for (; node != null; node = node.getNext()) 
        {
            if (node.getToken() == XMLNode.XML_ELEMENT_RETURNVALUE)
                return(node.childNode);
        }
	return(null);
    }


    // Attn: 09/16/02 - (Jenny) Method name changed from outputParameter()
    //
    // Returns XML representation of an input parameter 
    //
    static private String inputParameterXml(String paramName,CIMValue cv) throws CIMException {
	try {
	/*
	        return("<PARAMVALUE NAME=\""+paramName+"\">"
		       +cv.toXml()
		       +"</PARAMVALUE>");
	*/	       
		return("<PARAMVALUE NAME=\""+paramName+"\" PARAMTYPE=\""+CIMDataType.convertTypeEnumToString(cv.getType().getType())+"\">"+cv.toXml()+"</PARAMVALUE>");
		       
	} catch (MalformedURLException e) {
	    throw new CIMException(CIMException.CIM_ERR_FAILED);
	}
    }
}
