// MobySecondaryData.java
//
//    senger@ebi.ac.uk
//    May 2003
//

package org.biomoby.shared;

import java.util.Enumeration;
import java.util.Vector;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * A container representing a way how various secondary data types
 * are used in a service.
 *
 *<p>
 * @author <A HREF="mailto:senger@ebi.ac.uk">Martin Senger</A>
 * @version $Id: MobySecondaryData.java,v 1.13 2009/06/09 18:56:27 gordonp Exp $
 */

public class MobySecondaryData
    extends MobyData implements Cloneable{
    public static final String INTEGER_TYPE = "Integer";
    public static final String FLOAT_TYPE = "Float";
    public static final String STRING_TYPE = "String";
    public static final String DATETIME_TYPE = "DateTime";
    public static final String BOOLEAN_TYPE = "Boolean";

    protected String dataType = STRING_TYPE;
    protected String defaultValue = "";
    protected String minimumValue = "";
    protected String maximumValue = "";
    protected Vector<String> allowedValues = new Vector<String>();
    protected String description = "";

    /**************************************************************************
     * Default constructor. Other characteristics are empty - which is usually
     * wrong - therefore use 'set' method to fill them.
     *************************************************************************/
    public MobySecondaryData (String name) {
	super (name);
    }

    /**************************************************************************
     * Construct this instance from a piece of XML.
     * The XML looks like this:
     *
     * &lt;Parameter articleName="NameOfArticle"&gt;
     *   &lt;datatype&gt;INT|FLOAT|STRING&lt;/datatype&gt;
     *   &lt;description&gt;...&lt;/description&gt;
     *   &lt;default&gt;...&lt;/default&gt; &lt;!-- any/all of these --&gt;
     *   &lt;max&gt;...&lt;/max&gt;         &lt;!-- ... --&gt;
     *   &lt;min&gt;...&lt;/min&gt;         &lt;!-- ... --&gt;
     *   &lt;enum&gt;...&lt;/enum&gt;        &lt;!-- ... --&gt;
     *   &lt;enum&gt;...&lt;/enum&gt;        &lt;!-- ... --&gt;
     * &lt;/Parameter&gt;
     *
     *************************************************************************/
    public MobySecondaryData (Element elem){
	super (elem.getAttribute ("articleName"));
	NodeList children = elem.getChildNodes();
	for (int i = 0; i < children.getLength(); i++) {
	    String childName = children.item (i).getNodeName();
	    if (childName.equals ("datatype")) {
		if (children.item (i).getFirstChild() != null)
		    try{
			setDataType (children.item (i).getFirstChild().getNodeValue());
		    } catch(Exception e){
			e.printStackTrace();
		    }
	    } else if (childName.equals ("description")) {
		if (children.item (i).getFirstChild() != null)
		    setDescription (children.item (i).getFirstChild().getNodeValue());
	    } else if (childName.equals ("default")) {
		if (children.item (i).getFirstChild() != null)
		    setDefaultValue (children.item (i).getFirstChild().getNodeValue());
	    } else if (childName.equals ("max")) {
		if (children.item (i).getFirstChild() != null)
		    setMaxValue (children.item (i).getFirstChild().getNodeValue());
	    } else if (childName.equals ("min")) {
		if (children.item (i).getFirstChild() != null)
		    setMinValue (children.item (i).getFirstChild().getNodeValue());
	    } else if (childName.equals ("enum")) {
		if (children.item (i).getFirstChild() != null)
		    addAllowedValue (children.item (i).getFirstChild().getNodeValue());
	    }
	}
    }

    public MobySecondaryData clone(){
	MobySecondaryData clone = new MobySecondaryData(getName());
	clone.dataType = dataType;
	clone.defaultValue = defaultValue;
	clone.minimumValue = minimumValue;
	clone.maximumValue = maximumValue;
	clone.allowedValues = new Vector<String>(allowedValues);
	clone.description = description;
	return clone();
    }

    public String getDataType() {
	return dataType;
    }

    public String getLSID(){
	return "urn:lsid:biomoby.org:secondaryParamClass:"+getDataType();
    }

    public void setDataType (String value) throws Exception{
	if(value.equalsIgnoreCase(INTEGER_TYPE)){
	    dataType = INTEGER_TYPE;
	}
	else if(value.equalsIgnoreCase(FLOAT_TYPE)){
	    dataType = FLOAT_TYPE;
	}
	else if(value.equalsIgnoreCase(STRING_TYPE)){
	    dataType = STRING_TYPE;
	}
	else if(value.equalsIgnoreCase(DATETIME_TYPE)){
	    dataType = DATETIME_TYPE;
	}
	else if(value.equalsIgnoreCase(BOOLEAN_TYPE)){
	    dataType = BOOLEAN_TYPE;
	}
	else{
	    throw new Exception("Data type for secondary parameter '" + getName() +
				"' was not valid (\"" + value + "\"), must be one of " +
				INTEGER_TYPE + ", " + FLOAT_TYPE + ", " + STRING_TYPE + ", " +
				DATETIME_TYPE + ", " + BOOLEAN_TYPE);
	}
    }

    public String getDefaultValue() {
	return defaultValue;
    }
    public void setDefaultValue (String value) {
	defaultValue = (value == null ? "" : value);
    }

    public int getMinimumValue() {
	try {
	    return Integer.valueOf (minimumValue).intValue();
	} catch (Exception e) {
	    //	NumberFormatException or NullPointerException
	    return Integer.MIN_VALUE;
	}
    }

    /**
     * @deprecated Use {@link #setMinValue} instead.
     */
    public void setMinimumValue (int value) {
	minimumValue = value + "";
    }

    public String getMinValue() {
	return minimumValue;
    }
    public void setMinValue (String value) {
	minimumValue = (value == null ? "" : value);
    }

    public int getMaximumValue() {
	try {
	    return Integer.valueOf (maximumValue).intValue();
	} catch (Exception e) {
	    //	NumberFormatException or NullPointerException
	    return Integer.MAX_VALUE;
	}
    }

    /**
     * @deprecated Use {@link #setMaxValue} instead.
     */
    public void setMaximumValue (int value) {
	maximumValue = value + "";
    }

    public String getMaxValue() {
	return maximumValue;
    }
    public void setMaxValue (String value) {
	maximumValue = (value == null ? "" : value);
    }

    public String[] getAllowedValues() {
	String[] result = new String [allowedValues.size()];
	allowedValues.copyInto (result);
	return result;
    }
    public void setAllowedValues (String[] value) {
	if (value == null) {
	    allowedValues.clear();
	} else {
	    for (int i = 0; i < value.length; i++)
		allowedValues.addElement (value[i]);
	}
    }
    public void addAllowedValue (String value) {
	allowedValues.addElement (value);
    }

    public boolean isPrimary() {
	return false;
    }

    /**
     * Return a (usually) human readable description of this
     * parameter.
     */
    public String getDescription() {
	return description;
    }

    /**
     * @see #getDescription
     */
    public void setDescription (String value) {
	description = (value == null ? "" : value);
    }

    /**************************************************************************
     * Convert this instance into XML.
     * The XML will look like this:
     *
     *    &lt;Parameter articleName="NameOfArticle"&gt;
     *       &lt;datatype&gt;INT|FLOAT|STRING&lt;/datatype&gt;
     *       &lt;description&gt;...&lt;/description&gt;
     *       &lt;default&gt;...&lt;/default&gt; &lt;!-- any/all of these --&gt;
     *       &lt;max&gt;...&lt;/max&gt;         &lt;!-- ... --&gt;
     *       &lt;min&gt;...&lt;/min&gt;         &lt;!-- ... --&gt;
     *       &lt;enum&gt;...&lt;/enum&gt;        &lt;!-- ... --&gt;
     *       &lt;enum&gt;...&lt;/enum&gt;        &lt;!-- ... --&gt;
     *    &lt;/Parameter&gt;
     *
     *************************************************************************/
    public String toXML() {
	StringBuffer buf = new StringBuffer();
	buf.append ("<Parameter articleName=\"");
	buf.append (name);
	buf.append ("\">\n");
	buf.append ("<datatype>");
	buf.append (dataType);
	buf.append ("</datatype>\n");
	buf.append ("<description>");
	buf.append (description);
	buf.append ("</description>\n");
	if (!defaultValue.equals(""))
	    buf.append ("<default>" + defaultValue + "</default>\n");
	if (! "".equals (maximumValue))
	    buf.append ("<max>" + maximumValue + "</max>\n");
	if (! "".equals (minimumValue))
	    buf.append ("<min>" + minimumValue + "</min>\n");
	if (allowedValues.size() > 0) {
	    for (Enumeration en = allowedValues.elements(); en.hasMoreElements(); ) {
		buf.append ("<enum>");
		buf.append (en.nextElement());
		buf.append ("</enum>\n");
	    }
	}
	buf.append ("</Parameter>\n");
	return new String (buf);
    }

    public String format (int indent) {
	return Utils.format (this, indent);
    }

    public String toString() {
	StringBuffer buf = new StringBuffer();
	if (name != null && name.length() > 0)
	    buf.append ("Name:      " + name + "\n");
	if (id != null) buf.append ("ID:        " + id + "\n");
	buf.append ("Data Type: " + dataType + "\n");
	if (description != null && description.length() > 0)
	    buf.append ("Desc:      " + description + "\n");
	if (defaultValue != null && defaultValue.length() > 0)
	    buf.append ("Default:   " + defaultValue + "\n");
	if (minimumValue != null && minimumValue.length() > 0)
	    buf.append ("Min:       " + minimumValue + "\n");
	if (maximumValue != null && maximumValue.length() > 0)
	    buf.append ("Max:       " + maximumValue + "\n");
	if (allowedValues.size() > 0) {
	    buf.append ("Allowed values: ");
	    for (Enumeration en = allowedValues.elements(); en.hasMoreElements(); ) {
		buf.append (en.nextElement() + " ");
	    }
	    buf.append ("\n");
	}
	return new String (buf);
    }
}
