/**
 *
 */
package org.verapdf.processor;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;

import org.verapdf.component.AuditDuration;
import org.verapdf.component.Components;
import org.verapdf.core.VeraPDFException;

/**
 * @author <a href="mailto:carl@openpreservation.org">Carl Wilson</a>
 *         <a href="https://github.com/carlwilson">carlwilson AT github</a>
 * @version 0.1 Created 30 Oct 2016:14:21:22
 */
@XmlRootElement(name = "taskResult")
class TaskResultImpl implements TaskResult {
	private static final VeraPDFException notExecutedExcept = new VeraPDFException("Not Executed");
	private static final TaskResult defaultInstance = new TaskResultImpl();
	private static final String EXCEPTION = "Exception: ";
	private static final String CAUSED_BY = " caused by exception: ";

    private final VeraPDFException exception;

    @XmlAttribute
	private final TaskType type;
	@XmlAttribute
	private final boolean isExecuted;
	@XmlAttribute
	private final boolean isSuccess;
	@XmlElement
	private final AuditDuration duration;
	@XmlElement
	public String getExceptionMessage() {
		Throwable e = this.exception;
		String res = EXCEPTION + e.getMessage();
		e = e.getCause();
		while (e != null) {
			res += CAUSED_BY + e.getMessage();
			e = e.getCause();
		}
		return res;
	}

	private TaskResultImpl() {
		this(TaskType.NONE, false, false, Components.defaultDuration(), notExecutedExcept);
	}

	private TaskResultImpl(final TaskType type, final AuditDuration duration) {
		this(type, true, true, duration, null);
	}

	private TaskResultImpl(final TaskType type, final AuditDuration duration, final VeraPDFException exception) {
		this(type, true, false, duration, exception);
	}

	private TaskResultImpl(final TaskType type, final boolean isExecuted, final boolean isSuccess, final AuditDuration duration,
			final VeraPDFException exception) {
		super();
		this.type = type;
		this.isExecuted = isExecuted;
		this.isSuccess = isSuccess;
		this.duration = duration;
		this.exception = exception;
	}


	@Override
	public TaskType getType() {
		return type;
	}

	@Override
	public boolean isSuccess() {
		return this.isSuccess;
	}

	@Override
	public VeraPDFException getException() {
		return this.exception;
	}

	@Override
	public boolean isExecuted() {
		return this.isExecuted;
	}

	@Override
	public AuditDuration getDuration() {
		return this.duration;
	}

	/**
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((this.duration == null) ? 0 : this.duration.hashCode());
		result = prime * result + ((this.exception == null) ? 0 : this.exception.hashCode());
		result = prime * result + (this.isExecuted ? 1231 : 1237);
		result = prime * result + (this.isSuccess ? 1231 : 1237);
		return result;
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof TaskResultImpl)) {
			return false;
		}
		TaskResultImpl other = (TaskResultImpl) obj;
		if (this.duration == null) {
			if (other.duration != null) {
				return false;
			}
		} else if (!this.duration.equals(other.duration)) {
			return false;
		}
		if (this.exception == null) {
			if (other.exception != null) {
				return false;
			}
		} else if (!this.exception.equals(other.exception)) {
			return false;
		}
		if (this.isExecuted != other.isExecuted) {
			return false;
		}
		if (this.isSuccess != other.isSuccess) {
			return false;
		}
		return true;
	}

	static TaskResult defaultInstance() {
		return defaultInstance;
	}

	static TaskResult fromValues(final TaskType type, final AuditDuration duration) {
		return new TaskResultImpl(type, duration);
	}

	static TaskResult fromValues(final TaskType type, final AuditDuration duration, VeraPDFException exception) {
		return new TaskResultImpl(type, duration, exception);
	}

	static class Adapter extends XmlAdapter<TaskResultImpl, TaskResult> {
		@Override
		public TaskResult unmarshal(TaskResultImpl procResultImpl) {
			return procResultImpl;
		}

		@Override
		public TaskResultImpl marshal(TaskResult procResult) {
			return (TaskResultImpl) procResult;
		}
	}
}

@@ -935,20 +935,17 @@
 on: %22;%0A%0A
-    
+%09
 private 
@@ -979,20 +979,17 @@
 ption;%0A%0A
-    
+%09
 @XmlAttr
@@ -1175,16 +1175,17 @@
 ration;%0A
+%0A
 %09@XmlEle
@@ -1228,16 +1228,63 @@
 age() %7B%0A
+%09%09if (this.exception == null)%0A%09%09%09return null;%0A%0A
 %09%09Throwa
@@ -1972,17 +1972,20 @@
 Success,
- 
+%0A%09%09%09
 final Au
@@ -2005,20 +2005,17 @@
 uration,
-%0A%09%09%09
+ 
 final Ve
@@ -2197,17 +2197,16 @@
 on;%0A%09%7D%0A%0A
-%0A
 %09@Overri
@@ -2246,16 +2246,21 @@
 %09return 
+this.
 type;%0A%09%7D

FIX - Null Task Exception - handling null exception case for message. Closes #646