package eu.dnetlib.contract.cp;

import org.apache.log4j.Logger;


import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField;

import eu.dnetlib.contract.event.ExceptionContractEvent;
import eu.dnetlib.contract.event.IContractEvent;
import eu.dnetlib.contract.node.EvaluationResult;
import eu.dnetlib.contract.node.EvaluationResult.Status;

/**
 * Exception CheckPoint object.
 * Verifies validity of intercepted exception.
 * @author mhorst
 *
 */
@XStreamAlias("ExceptionCheckPoint")
public class ExceptionCheckPoint extends AbstractCheckPoint implements
		ICheckPoint<IContractEvent> {

	@XStreamOmitField
	private static final Logger log = Logger.getLogger(ExceptionCheckPoint.class);
	
	/**
	 * Exception class name.
	 */
	private String exceptionClassName;
	
	/**
	 * Exception message.
	 */
	private String exceptionMessage;
	
	/**
	 * Exception's class or interface which inspected exception should derive from.
	 */
	private Class<? extends Exception> exceptionDerivedFrom;


	/* (non-Javadoc)
	 * @see eu.dnetlib.contract.cp.ICheckPoint#getSupportedEventClass()
	 */
	public Class<? extends IContractEvent> getSupportedEventClass() {
		return ExceptionContractEvent.class;
	}
	
	/* (non-Javadoc)
	 * @see eu.dnetlib.contract.cp.AbstractCheckPoint#check(eu.dnetlib.contract.event.IContractEvent)
	 */
	@Override
	public EvaluationResult check(IContractEvent event) throws CheckPointEvaluationException {
		EvaluationResult superResult = super.check(event);
		if (superResult.getStatus()==Status.FAIL ||
				superResult.getStatus()==Status.FATAL) {
			return superResult;
		}
		ExceptionContractEvent excContext = (ExceptionContractEvent) event;
		if (this.getExceptionClassName()!=null) {
			if (excContext.getException()==null || 
					!this.getExceptionClassName().equals(excContext.getException().getClass().getName())) {
				String message = "Invalid exception className: " + 
					(excContext.getException()==null?"null exception object!":excContext.getException().getClass().getName()) +
					", expected: "+ this.getExceptionClassName();
				log.info(message);
				return new EvaluationResult(Status.FAIL, this, event, message);
			}
		}
		if (this.getExceptionMessage()!=null) {
			if (excContext.getException()==null ||
				!this.getExceptionMessage().trim().equals(excContext.getException().getMessage()!=null?
						excContext.getException().getMessage().trim():null)) {
				String message = "Invalid exception message: " + 
					(excContext.getException()==null?"null exception object!":excContext.getException().getMessage()) +
				", expected: "+ this.getExceptionMessage();
				log.info(message);
				return new EvaluationResult(Status.FAIL, this, event, message);
			}
		}
		if (this.getExceptionDerivedFrom()!=null) {
			if (excContext.getException()==null ||
					!this.getExceptionDerivedFrom().isInstance(excContext.getException())) {
					String message = "Invalid exception class: " + 
						(excContext.getException()==null?"null exception object!":excContext.getException().getClass().getName()) +
					", expected to be derived from: "+ this.getExceptionDerivedFrom().getName();
					log.info(message);
					return new EvaluationResult(Status.FAIL, this, event, message);
				}
		}
		return new EvaluationResult(Status.OK, this, event);
	}

	/* (non-Javadoc)
	 * @see eu.dnetlib.contract.cp.ICheckPoint#identify()
	 */
	@Override
	public String identify() {
		StringBuffer strBuff = new StringBuffer("class: " + this.getClass().getName());
		String superIdentify = super.identify();
		if (superIdentify!=null && superIdentify.length()>0) {
			strBuff.append(ICheckPoint.IDENTIFY_DELIMITER);
			strBuff.append(superIdentify);
		}
		if (exceptionClassName!=null) {
			strBuff.append(ICheckPoint.IDENTIFY_DELIMITER);
			strBuff.append("exceptionClassName: " + exceptionClassName);
		}
		if (exceptionMessage!=null) {
			strBuff.append(ICheckPoint.IDENTIFY_DELIMITER);
			strBuff.append("exceptionMessage: " + exceptionMessage);
		}
		if (exceptionDerivedFrom!=null) {
			strBuff.append(ICheckPoint.IDENTIFY_DELIMITER);
			strBuff.append("exceptionDerivedFrom: " + exceptionDerivedFrom.getName());
		}
		return strBuff.toString();
	}
	
	/**
	 * Returns exception class name.
	 * @return exception class name
	 */
	public String getExceptionClassName() {
		return exceptionClassName;
	}

	/**
	 * Sets exception class name.
	 * @param exceptionClassName
	 */
	public void setExceptionClassName(String exceptionClassName) {
		this.exceptionClassName = exceptionClassName;
	}

	/**
	 * Returns Exception message.
	 * @return Exception message
	 */
	public String getExceptionMessage() {
		return exceptionMessage;
	}

	/**
	 * Sets Exception message.
	 * @param exceptionMessage
	 */
	public void setExceptionMessage(String exceptionMessage) {
		this.exceptionMessage = exceptionMessage;
	}

	/**
	 * Returns exception's derived class.
	 * @return exception's derived class
	 */
	public Class<? extends Exception> getExceptionDerivedFrom() {
		return exceptionDerivedFrom;
	}

	/**
	 * Sets exception's derived class.
	 * @param exceptionDerivedFrom
	 */
	public void setExceptionDerivedFrom(
			Class<? extends Exception> exceptionDerivedFrom) {
		this.exceptionDerivedFrom = exceptionDerivedFrom;
	}
	
}
