/**
 * This class corresponds to a MobyException in the MOBY data payload serviceNotes.
 * Instances of this class will be created when a service provider reports an exception
 * in the XML response to a service invocation request, according to the standard 
 * laid out in 
 * <a href="http://biomoby.open-bio.org/CVS_CONTENT/moby-live/Docs/MOBY-S_API/ExceptionReporting.html">RFC 1863</a>.
 * This usually entails a badly formatted XML message (programmer error), a bad server state, or a bad network connection.
 *
 * This class extends ServiceException, essentially to provide the extra functionality of 
 * creating the MobyServiceException from XML directly during parsing
 *
 * A MobyServiceException can in fact be just a warning or information message, so
 * don't always panic: check the "severity" of the exception.
 */

package org.biomoby.shared.data;

import org.w3c.dom.Element;
import org.biomoby.shared.MobyPrefixResolver;
import org.biomoby.shared.data.MobyDataObject;
import org.biomoby.shared.parser.ServiceException;
import org.biomoby.shared.parser.MobyTags;

public class MobyServiceException extends ServiceException{
    /** This will be the error code assigned if none is available from the instatiating XML */
    public static final int ERROR_CODE_UNKNOWN = -35353;
    public static final int SEVERITY_UNKNOWN = 235823;

    public static final String SEVERITY_ERROR_STR = "error";
    public static final String SEVERITY_WARNING_STR = "warning";
    public static final String SEVERITY_INFO_STR = "info";

    /**
     * Builds an instance of an exception from a DOM element. Useful when parsing a MOBY XML file.
     */
    public MobyServiceException(Element e) throws IllegalArgumentException{
	// Fills in ALL fields
	this(severityStringToSeverityInt(MobyPrefixResolver.getAttr(e, MobyTags.SEVERITY)), 
	     codeStringToCodeInt(MobyDataObject.getTextContents(MobyPrefixResolver.getChildElement(e, MobyTags.EXCEPTIONCODE))),
	     MobyPrefixResolver.getAttr(e, MobyTags.REFQUERYID),
	     MobyPrefixResolver.getAttr(e, MobyTags.REFELEMENT),
	     MobyDataObject.getTextContents(MobyPrefixResolver.getChildElement(e, MobyTags.EXCEPTIONMESSAGE)));
    }

    /**
     * Converts an error code string to an integer defined in ServiceException, or ERROR_CODE_UNKNOWN
     * if the code is not a standard one (3 digits and part of RFC 1863).
     */
    public static int severityStringToSeverityInt(String severityString){
	if(severityString == null){
	    return SEVERITY_UNKNOWN;
	}
	if(severityString.equals(SEVERITY_ERROR_STR)){
	    return ServiceException.ERROR;
	}
	if(severityString.equals(SEVERITY_WARNING_STR)){
	    return ServiceException.WARNING;
	}
	if(severityString.equals(SEVERITY_INFO_STR)){
	    return ServiceException.INFO;
	}
	return SEVERITY_UNKNOWN;
    }

    /**
     * Converts an error code string to an integer defined in ServiceException, or ERROR_CODE_UNKNOWN
     * if the code is not a standard one (3 digits and part of RFC 1863).
     */
    public static int codeStringToCodeInt(String codeString){
	if(codeString == null || !codeString.matches("\\d\\d\\d")){
	    return ERROR_CODE_UNKNOWN;
	}
	int code = Integer.parseInt(codeString);
	switch(code){
	    case ServiceException.COMMUNICATION_FAILURE: break;
	    case ServiceException.INPUT_EMPTY_OBJECT: break;
	    case ServiceException.INPUT_INCORRECT_COLLECTION: break;
	    case ServiceException.INPUT_INCORRECT_NAMESPACE: break;
	    case ServiceException.INPUT_INCORRECT_PARAMETER: break;
	    case ServiceException.INPUT_INCORRECT_SIMPLE: break;
	    case ServiceException.INPUT_NOT_ACCEPTED: break;
	    case ServiceException.INPUT_REQUIRED_PARAMETER: break;
	    case ServiceException.INPUT_REQUIRED_PARAMETERS: break;
	    case ServiceException.INPUTS_INVALID: break;
	    case ServiceException.INTERNAL_PROCESSING_ERROR: break;
	    case ServiceException.NO_METADATA_AVAILABLE: break;
	    case ServiceException.NOT_IMPLEMENTED: break;
	    case ServiceException.NOT_RUNNABLE: break;
 	    case ServiceException.NOT_RUNNING: break;
	    case ServiceException.NOT_TERMINATED: break;
	    case ServiceException.OK: break;
	    case ServiceException.PROTOCOLS_UNACCEPTED: break;
	    case ServiceException.UNKNOWN_NAME: break;
	    case ServiceException.UNKNOWN_STATE: break;
	    default: return ERROR_CODE_UNKNOWN;
	}
	// If we got this far, we matched a non-default switch case
	// so it's a valid code.
	return code;
    }

    public MobyServiceException(int severity, int code, java.lang.String message){
	super(severity, code, message);
    }

    public MobyServiceException(int severity, int code, java.lang.String jobId, java.lang.String dataName){
	super(severity, code, jobId, dataName);
    }

    public MobyServiceException(int severity, int code, java.lang.String jobId, java.lang.String dataName, java.lang.String msg){
	super(severity, code, jobId, dataName, msg);
    }
}
