package de.hsadmin.core.qserv;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.EntityManager;
import javax.persistence.FetchType;
import javax.persistence.GenerationType;

import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.mods.qstat.QTaskModuleImpl;
import de.hsadmin.mods.user.UnixUser;

@javax.persistence.Entity(name = "QueueTasks")
@javax.persistence.Table(name = "queue_task")
@javax.persistence.SequenceGenerator(name = "QueueTaskSeqGen", sequenceName = "queue_task_id_seq")
@EntityInfo(name = "Systemauftrag")
@ModuleImpl(QTaskModuleImpl.class)
public class QueueTask extends AbstractEntity implements Serializable {

	private static final long serialVersionUID = 2171870783383767875L;

	@javax.persistence.Id
	@javax.persistence.GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "QueueTaskSeqGen")
	@javax.persistence.Column(name = "task_id", columnDefinition = "integer")
	private long id;

	@javax.persistence.JoinColumn(name="user_id", columnDefinition="integer", nullable=true)
	@javax.persistence.ManyToOne(fetch=FetchType.EAGER)
	private UnixUser user;

	@javax.persistence.Column(name = "started", columnDefinition = "date")
	@javax.persistence.Temporal(javax.persistence.TemporalType.TIMESTAMP)
	private Date started;

	@javax.persistence.Column(name = "finished", columnDefinition = "date", nullable = true)
	@javax.persistence.Temporal(javax.persistence.TemporalType.TIMESTAMP)
	private Date finished;

	@javax.persistence.Column(name = "title", columnDefinition = "character varying(192)")
	private String title;

	@javax.persistence.Column(name = "details", columnDefinition = "text", nullable = true)
	private String details;

	private Processor proc;

	@javax.persistence.Column(name = "exception", columnDefinition = "text", nullable = true)
	private String exception;

	public QueueTask() {
	}

	public QueueTask(UnixUser user, String title, String details, Processor proc) {
		this.user = user;
		this.title = title;
		this.details = details;
		this.started = new Date();
		this.finished = null;
		this.proc = proc;
		this.exception = null;
	}

	@Override
	public UnixUser owningUser(EntityManager em) {
		return user;
	}

	/**
	 *  determines whether the given user has full read access 
	 *  on all merged fields of this entity
	 */
	@Override
	public boolean isReadAllowedFor(UnixUser loginUser) {
		return loginUser.hasPacAdminRoleFor(getUser().getPac())
				|| loginUser.id() == getUser().id();
	}

	/**
	 *  JPA-Query restriction for these entities
	 * @return
	 */
	public static String restriction() {
		return
			// customers can see all entries of all users of their pacs
			"obj.user.pac.customer.name=:loginUserName OR " +
			// packet admins can access all entries of their users
			// TODO: Hostsharing convention
			"obj.user.pac.name=:loginUserName OR " +
			// otherwise only their own tasks
			"obj.user=:loginUser";
	}

	@Override
	public String createStringKey() {
		return Long.toString(id);
	}

	@Override
	public long id() {
		return id;
	}

	public long getId() {
		return id;
	}

	protected void setId(long id) {
		this.id = id;
	}

	public UnixUser getUser() {
		return user;
	}

	public void setUser(UnixUser user) {
		this.user = user;
	}

	public Date getStarted() {
		return started;
	}

	public void setStarted(Date started) {
		this.finished = started;
	}

	public Date getFinished() {
		return finished;
	}

	/**
	 * virtual attribute done
	 * @return
	 */
	@javax.persistence.Transient
	public boolean isDone() {
		return finished != null;
	}

	public void done() {
		finished = new java.util.Date();
	}

	/**
	 * virtual attribute status
	 * @return
	 */
	@javax.persistence.Transient
	public QueueTaskStatus getStatus() {
		return isDone() ? (exception == null ? QueueTaskStatus.DONE
				: QueueTaskStatus.ERROR) : QueueTaskStatus.PENDING;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getDetails() {
		return details;
	}

	public void setDetails(String details) {
		this.details = details;
	}

	public Processor getProcessor() {
		return proc;
	}

	public void setProcessor(Processor proc) {
		this.proc = proc;
	}

	public String getException() {
		return exception;
	};

	public void setException(String exception) {
		this.exception = exception;
	}

	public void setException(Exception exception) {
		this.exception = exception.toString();
		// TODO: stack+cause
	}

	@Override
	public boolean isNew() {
		return id == 0;
	}

	/** 
	 * assigns all data field of qt to this instance, with 
	 * the exception of the id
	 */
	public void assign(QueueTask qt) {
		this.user = qt.user;
		this.title = qt.title;
		this.details = qt.details;
		this.started = qt.started;
		this.finished = qt.finished;
		this.proc = qt.proc;
		this.exception = qt.exception;
	}

	@Override
	public String getHiveName() {
		return null;
	}

	public enum QueueTaskStatus {
		
		PENDING("pending"), ERROR("error"), DONE("done");

		private final String color;
	
		QueueTaskStatus(final String color) {
			this.color = color;
		}
	
		public String toString() {
			return color;
		}
	}
}
