//
// CIMQualifier.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 CIMQualifier.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: CIMQualifier.java,v 1.1 2003/07/17 18:32:55 kumpf Exp $
//
// HP Java Client: 1.1  2003/01/09 18:14:30 [ Bapu Patil]
//   - Add support to handle EMPTY XML tags in CIMQualifier 
//      property values
//
// $Log: CIMQualifier.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:35  karl
// import of SNIA 0_7
//
// Revision 1.10  2001/07/07 13:27:24  davidsi
// - Fixed array parsing in XML (from Tim Woodall).
//
// Revision 1.9  2001/01/07 16:43:20  davidsi
// - Made CIM_QUAL_KEY and CIM_QUAL_OVERRIDE public.
//
// Revision 1.8  2000/11/06 18:13:21  davidsi
// - Reconciled error ids.
//
// Revision 1.7  2000/08/16 05:59:52  shawn
// merge P_TOMCAT31 branch
//
// Revision 1.6.8.1  2000/08/10 00:03:27  shawn
// head merge
//
// Revision 1.6  2000/05/11 10:12:20  davidsi
// - Fixed tabs.
//
// Revision 1.5  2000/05/07 13:33:14  davidsi
// - Made the creation of the flavor vector lazy as many of the instances
//   of CIMQualifier don't necessarily set it.
//
// Revision 1.4  2000/05/06 17:04:22  davidsi
// - Modifications to bring classes inline with the SUN WBEM APIs 2.2.
//
// Revision 1.3  2000/04/09 13:19:16  davidsi
// - Switched to StringBuffer (from String) for XML generation.
//
// Revision 1.2  2000/02/13 15:09:07  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.wbem.cim;

import java.util.Vector;
import java.net.MalformedURLException;
import java.io.Serializable;
import org.snia.wbemcmd.xml.XMLNode;
import org.snia.wbemcmd.xml.XMLParameters;
import org.snia.wbemcmd.xml.XMLCIM;

/**
    Creates and instantiates a CIM qualifier, a modifier containing 
    information that describes a class, an instance, a method, a method
    parameter, or a property.  Each CIM qualifier must have a 
    CIMQualifierType.  The CIM qualifier type is a template for creating
    a CIM qualifier.  A CIM qualifier and its CIM qualifier type must
    have the same name.  The default value of this CIM qualifier can
    override the default value of its CIM qualifier type.
 */

public class CIMQualifier extends CIMElement implements Serializable, Cloneable {
    
    static public String CIM_QUAL_KEY="key";		    // NOT SUN
    static public String CIM_QUAL_OVERRIDE="override";     // NOT SUN

    public static final String EMPTY = "";

    //
    // If you add to these, you must fix clone!
    //
    private CIMValue qualifierValue=null;
    private CIMQualifierType qualifierType=null;
    private boolean propagated=false;
    private Vector flavor=null; 	// A vector of CIMFlavor
    
    public CIMQualifier() {
    }

    //
    // CIMQualifier
    //
    // Creates a qualifier with the specified name
    public CIMQualifier(String iname) {
	setName(iname);
    }

    //
    // CIMQualifier
    //
    // Creates a qualifier with the specified name and type
    //
    public CIMQualifier(String iname,
		     CIMQualifierType cgt) {
	setName(iname);
	qualifierType=cgt;
    }




  
    //
    // CIMMethod
    //
    // Create a qualifier using a XML definition
    //
    // @param node The node containing an XML definition of CIMQualifier
    //
    public CIMQualifier(org.w3c.dom.Node node) {
	XMLNode qnode=XMLNode.getXMLNode(node);
	String text;
	CIMDataType dt;
	    
	if (qnode.getToken()!=XMLNode.XML_ELEMENT_QUALIFIER) 
	    throw new java.lang.InstantiationError("Not a qualifier node");
	try {	
	    String qualName=qnode.getAttribute(XMLParameters.paramName);
	    String cimType=qnode.getAttribute(XMLParameters.paramTypeAssign);
	    String propagate=qnode.getAttribute(XMLParameters.paramPropagated);
	    String overridable=qnode.getAttribute(XMLParameters.paramOverridable);
	    String tosubclass=qnode.getAttribute(XMLParameters.paramToSubClass);
	    String toinstance=qnode.getAttribute(XMLParameters.paramToInstance);
	    String translatable=qnode.getAttribute(XMLParameters.paramTranslatable);

	    setName(qualName);
	    //
	    // Build qualifier
	    //
	    if (cimType!=null)		    
		dt=CIMDataType.getDataType(cimType);
	    else
		throw new CIMException(CIMException.CIM_ERR_FAILED,"Qualifer not assigned a type");
				
	    if (dt==null)
		new CIMException(CIMException.CIM_ERR_FAILED,
				    "No type being set on qualifier "+qualName);
		
		
	    if (overridable==null || overridable.equalsIgnoreCase("true"))
		addFlavor(CIMFlavor.getFlavor(CIMFlavor.ENABLEOVERRIDE));
	    //else
	    //	addFlavor(CIMFlavor.getFlavor(CIMFlavor.DISABLEOVERRIDE));
		
	    if (tosubclass==null || tosubclass.equalsIgnoreCase("true"))
		addFlavor(CIMFlavor.getFlavor(CIMFlavor.TOSUBCLASS));
	    //else
	    //	addFlavor(CIMFlavor.getFlavor(CIMFlavor.RESTRICTED));
		    
	    if (translatable!=null && translatable.equalsIgnoreCase("true"))
		addFlavor(CIMFlavor.getFlavor(CIMFlavor.TRANSLATE));

	    if (propagate!=null && propagate.equalsIgnoreCase("true"))
		setPropagated(true);
	    else
		setPropagated(false);
				
	    qnode=qnode.getChild();
	    if (qnode==null)
		return; // no values
	    XMLNode arrayValues=qnode.findElement(XMLNode.XML_ELEMENT_VALUE_ARRAY);
		
	    if (arrayValues!=null) {
		qnode = arrayValues.getChild();
		Vector v=new Vector();
		for(;qnode!=null;qnode=qnode.getNext()) {
		    if (qnode.getToken()!=XMLNode.XML_ELEMENT_VALUE)
			break;
		    text=qnode.getUnescapeText();

		    if ( text == null )
		      v.addElement(EMPTY);
                    else
		      v.addElement(text);
		}
		dt=new CIMDataType(CIMDataType.findArrayType(dt.getType()));
		setValue(new CIMValue(v,dt));
	    } else {
		qnode=qnode.findElement(XMLNode.XML_ELEMENT_VALUE);
		if (qnode!=null) {
		    text=qnode.getUnescapeText();

		    if ( text == null )
			setValue(new CIMValue(EMPTY,dt));
                    else
		        setValue(new CIMValue(text,dt));
		}
	    }
	} catch (CIMException ce) {
	    throw new java.lang.InstantiationError(ce.toString());
	}
    }

    
    // getValue
    // 
    // Returns the value of this qualifier
    //
    public CIMValue getValue() {
	return(qualifierValue);
    }

    // setValue
    //
    public void setValue(CIMValue value) {
	qualifierValue=value;
    }


    // setDefaults
    //
    public void setDefaults(CIMQualifierType cqt) {
	qualifierType=cqt;
    }

    // Returns TRUE if the qualifier has specified flavor
    public boolean hasFlavor(CIMFlavor iflavor) {
	int i;
	
	if (flavor==null)
	    return(false);
	
	int tsize=flavor.size();
	for(i=0;i<tsize;i++)
	    if (((CIMFlavor)flavor.elementAt(i)).getFlavor()==iflavor.getFlavor())
		return(true);
	
	return(false);
    }


    // addFlavor
    //
    // SUNDIFF: SUN's API adds the flavor and verifies no conflict
    // but there is no way of reporting back any conflicts - this version
    // does no verification
    //
    public void addFlavor(CIMFlavor newFlavor) {
	int i;
	//
	// Check the vector has been created
	//
	if (flavor==null)
	    flavor=new Vector();
	//
	// Don't add it if its already present
	//
	int tsize=flavor.size();
	for(i=0;i<tsize;i++)
	    if (((CIMFlavor)flavor.elementAt(i)).getFlavor()==newFlavor.getFlavor())
		return;
	
	flavor.addElement(newFlavor);	
    }

    // toString
    public String toString() {
	return("CIMQualifer("+getName()+")");
    }

    //toMOF
    public String toMOF() {
	String ret;

	ret=new String();
	//TODO
	ret=ret.concat(getName());
	if (qualifierValue!=null) {
	    ret=ret.concat("(");
	    ret=ret.concat(qualifierValue.toMOF());
	    ret=ret.concat(")");
	}
	return(ret);
    }

    // hasValue
    // 
    // Returns TRUE if the qualifier has a value set.
    //
    public boolean hasValue() {
       return(qualifierValue!=null);
    }

    // equals
    //
    // Returns true if this qualifier has the same name 
    // as the passed qualifier
    //
    public boolean equals(Object o) {
	return ( (o instanceof CIMQualifier)  
		&& (((CIMQualifier)o).getName().equals(getName())));
    }

    // clone
    public Object clone() {
	CIMQualifier cq=new CIMQualifier();

	if (qualifierValue!=null) 
	    cq.qualifierValue=new CIMValue(
		    qualifierValue.getValue(),
		    qualifierValue.getType());

	if (qualifierType!=null)
	    cq.qualifierType=(CIMQualifierType)qualifierType.clone();
	
	cq.propagated=propagated;
	cq.setName(getName());
	if (flavor!=null) {
	    cq.flavor=new Vector();		//CIMFlavor
	    int tsize=flavor.size();
	    for(int i=0;i<tsize;i++)
		cq.flavor.addElement(flavor.elementAt(i));
	}
	return(cq);
    }

    // getFlavor
    public Vector getFlavor() {
	//
	// Check the vector has been created
	//
	if (flavor==null)
	    flavor=new Vector();
	
      return(flavor);
    }
    
    // toXml
    public String toXml() throws MalformedURLException {
	return(toXml(false));
    }

    
    //
    // NOT SUN
    //
    
    // toXml
    public String toXml(boolean localOnly) throws MalformedURLException {
	StringBuffer text=new StringBuffer();
	CIMFlavor fv;
	CIMDataType dt;
	String cimName=getName();
	
	if (cimName==null)
	    throw new MalformedURLException("qualifier must have name");
	//
	// If only local definitions are required and this is a propagated
	// qualifier then nothing to return
	//
	if (localOnly && propagated)
	    return("");
	
	//
	// If type isn't set then the CIMOM has stored a qualifier
	// thats bad and an exception is generated
	//
	if (qualifierValue==null || qualifierValue.getType()==null)
	    throw new MalformedURLException("Qualifier does not have a type set");

	dt=qualifierValue.getType();
	//
	// If the data type is NULL then there is no qualifier to write
	//
	if (dt.getType()==CIMDataType.NULL)
	    return("");
	
	
	text=text.append("<QUALIFIER NAME=\""+cimName+"\" "+
				 "TYPE=\""+dt.toXml()+"\" ");
	if (propagated)
	    text=text.append("PROPAGATED=\"true\" ");
	    
	//
	// Create flavors
	//
	fv=CIMFlavor.getFlavor(CIMFlavor.ENABLEOVERRIDE);
	if (hasFlavor(fv)){
	    //
	    // Not needed, because OVERRIDABLE defaults to true!
	    // text=text.concat(fv.toXml()+"=\"true\" ");
	} else {
	    //fv=CIMFlavor.getFlavor(CIMFlavor.DISABLEOVERRIDE);
	    //if (hasFlavor(fv)) 
		text=text.append(fv.toXml()+"=\"false\" ");
	}
	
	fv=CIMFlavor.getFlavor(CIMFlavor.TOSUBCLASS);
	if (hasFlavor(fv)) {
	    //
	    // Not needed, because TOSUBCLASS defaults to true!
	    // text=text.concat(fv.toXml()+"=\"true\" ");
	    //
	} else {
	     //fv=CIMFlavor.getFlavor(CIMFlavor.RESTRICTED);
	     //if (hasFlavor(fv)) 
		text=text.append(fv.toXml()+"=\"false\" ");
	}
	
	fv=CIMFlavor.getFlavor(CIMFlavor.TRANSLATE);
	if (hasFlavor(fv)) 
	    text=text.append(fv.toXml()+"=\"true\" ");
	else {
	    // 
	    // Not needed, because TRANSLATABLE defaults to false!
	    // text=text.concat(fv.toXml()+"=\"false\" ");
	    //
	}
	
	text=text.append(">");
	

	
	if (qualifierValue!=null) {
	    if (dt.isArrayType()) {
		Vector v=(Vector)qualifierValue.getValue();
		text=text.append("<VALUE.ARRAY>");
		for(int i=0;i<v.size();i++)
			text=text.append("<VALUE>"
					 +XMLCIM.xmlCIMEscape.XMLEscape(v.elementAt(i).toString())
					 +"</VALUE>");
		text=text.append("</VALUE.ARRAY>");
	    } else 
		text=text.append("<VALUE>"+
				 XMLCIM.xmlCIMEscape.XMLEscape(qualifierValue.toString())+
				 "</VALUE>");
	}
	    
	text=text.append("</QUALIFIER>");
	
	return(text.toString());
    }
    
    
    
    
    public void setPropagated(boolean value) {
	propagated=value;
    }
    
    public boolean getPropagated() {
	return(propagated);
    }
}
