package de.hsadmin.mods.email;

import static javax.persistence.GenerationType.SEQUENCE;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;

/**
 * Entity class for email aliases.
 * 
 */
@javax.persistence.Entity(name = "EMailAliases")
@Table(name = "emailalias")
@SequenceGenerator(name = "EMailAliasesSeqGen", sequenceName = "emailalias_emailalias_id_seq")
@EntityInfo(name = "E-Mail-Alias")
@SearchFilter("obj.pac = :loginUserPac OR obj.pac.customer.name = :loginUserName")
public class EMailAlias extends AbstractEntity implements Serializable {
	
	private static final long serialVersionUID = -4711415079723587161L;

	@Id
	@GeneratedValue(strategy = SEQUENCE, generator = "EMailAliasesSeqGen")
	@Column(name = "emailalias_id", columnDefinition = "integer", insertable=false, updatable=false)
	private long id;

	@ManyToOne()
	@JoinColumn(name = "pac_id", columnDefinition = "integer")
	private Pac pac;

	@FieldValidation("[a-z0-9\\_\\-\\.\\+]*")
	@Column(updatable=false)
	private String name;

	@FieldValidation("[a-zA-Z0-9\\_\\-\\.\\|\\\"\\/\\@\\,\\+\\ ]*")
	@Column
	private String target;

	public EMailAlias() {
	}

	public EMailAlias(Pac pac, String name, String target) {
		this.pac = pac;
		this.name = name;
		this.target = target;
	}

	@Override
	public void initialize(EntityManager em, UnixUser loginUser) {
		pac = loginUser.getPac();
		name = pac.getName() + "-";
		target = "";
	}

	@Override
	public void complete(EntityManager em, UnixUser loginUser) {
		if (pac == null && name != null && name.length() > 0) {
			// TODO: it's ugly having this code here, needs refactoring
			String pacName = name.substring(0, 5);
			try {
				// get the entities name (query part from FROM to WHERE)
				Entity entityAnnot = Pac.class.getAnnotation(Entity.class);
				String queryString = "SELECT obj FROM " + entityAnnot.name() + " obj WHERE " + Pac.createQueryFromStringKey(pacName);

				// set parameters
				Query query = em.createQuery(queryString);
				AbstractModuleImpl.setQueryParameter(query, queryString, "loginUser", loginUser);
				AbstractModuleImpl.setQueryParameter(query, queryString, "loginUserName", loginUser.getName());
				AbstractModuleImpl.setQueryParameter(query, queryString, "loginUserPac", loginUser.getPac());
				pac = (Pac) query.getSingleResult();
			} catch (NoResultException exc) {
				throw new SecurityException("packet '" + pacName + "' not found or access denied");
			}
		}
	}

	public static String createQueryFromStringKey(String humanKey) {
		return "name='" + humanKey + "'";
	}

	@Override
	public String createStringKey() {
		return name;
	}

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

	public long getId() {
		return id;
	}

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

	public Pac getPac() {
		return pac;
	}

	public void setPac(Pac pac) {
		this.pac = pac;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getTarget() {
		return target;
	}

	public void setTarget(String target) {
		this.target = target;
	}

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

	@Override
	public String getHiveName() {
		if (isNew())
			return null;
		else
			return getPac().getHiveName();
	}

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

	public AbstractEntity merge(EntityManager em, UnixUser loginUser) {
		EMailAlias attachedEntity = em.find(getClass(), id());
		Pac attachedPacket = attachedEntity.getPac();
		if (pac.getId() != attachedPacket.getId())
			throw new SecurityException(
					"changing the Packet of an EMailAlias is not allowed");
		if (!name.equals(attachedPacket.getName())
				&& !name.startsWith(attachedPacket.getName() + "-"))
			throw new SecurityException(
					"changing the Packet of an EMailAlias is not allowed");

		attachedEntity.setName(name);
		attachedEntity.setTarget(target);
		return attachedEntity;
	}

	@Override
	public boolean isReadAllowedFor(UnixUser loginUser) {
		return loginUser.hasPacAdminRoleFor(getPac());
	}

	@Override
	public boolean isWriteAllowedFor(UnixUser loginUser) {
		String pacName = pac.getName();
		if (!name.equals(pacName) && !name.startsWith(pacName + "-"))
			return false;

		return loginUser.hasPacAdminRoleFor(getPac());
	}

	public static String restriction() {
		return
			// all aliases of all pacs of customer
			"obj.pac.customer.name=:loginUserName OR " +
			// all aliases of packet admin
			"obj.pac.name=:loginUserName";
	}
	
}
