package de.hsadmin.mods.email;

import static javax.persistence.FetchType.EAGER;
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.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.dom.Domain;
import de.hsadmin.mods.user.UnixUser;

/**
 * Entity class for email addresses.
 */
@Entity(name = "EMailAddresses")
@Table(name = "emailaddr")
@SequenceGenerator(name = "EMailAddressesSeqGen", sequenceName = "emailaddr_emailaddr_id_seq")
@EntityInfo(name = "E-Mail-Adresse")
@SearchFilter("domain.user = :loginUser OR "
		+ "domain.user.pac = :loginUserPac OR "
		+ "domain.user.pac.customer.name = :loginUserName")
public class EMailAddress extends AbstractEntity implements Serializable {
	
	private static final long serialVersionUID = -2265500181746604429L;

	@Id
	@GeneratedValue(strategy = SEQUENCE, generator = "EMailAddressesSeqGen")
	@Column(name = "emailaddr_id", columnDefinition = "integer")
	private long id;
	
	@FieldValidation("[A-Za-z0-9\\_\\-\\.\\+]*")
	@Column(name = "localpart", updatable = false, nullable= false)
	private String localpart = "";
	
	@FieldValidation("[a-z0-9\\-\\.]*")
	@Column(name = "subdomain")
	private String subdomain;
	
	@ManyToOne(fetch = EAGER)
	@JoinColumn(name = "domain_id", columnDefinition = "integer", updatable = false)
	private Domain domain;
	
	@FieldValidation("[a-zA-Z0-9\\_\\-\\.\\|\\\"\\/\\@\\,\\+\\ ]*")
	@Column(name = "target", nullable= false)
	private String target;

	public EMailAddress() {
	}

	public EMailAddress(String localpart, String subdomain, Domain domain,
			String target) {
		this.localpart = localpart;
		this.subdomain = subdomain;
		this.domain = domain;
		this.target = target;
	}

	public static String createQueryFromStringKey(String humanKey) throws HSAdminException {
		String[] parts = humanKey.split("@", 2);
		if (parts.length != 2) {
			throw new HSAdminException("error in oid: " + humanKey);
		}
		String[] doms = parts[1].split("\\.");
		StringBuilder query = new StringBuilder("obj.localpart='" + parts[0]
				+ "' AND ( ( (obj.subdomain IS NULL OR obj.subdomain='') AND obj.domain.name='" 
				+ parts[1] + "' )");
		for (int subdomLevel = 1; subdomLevel < doms.length - 1; ++subdomLevel) {
			String subdom = "";
			for (int n = 0; n < subdomLevel; ++n)
				subdom += "." + doms[n];
			String domain = "";
			for (int n = subdomLevel; n < doms.length; ++n)
				domain += "." + doms[n];
			query.append(" OR ( obj.subdomain='" + subdom.substring(1)
					+ "' AND obj.domain.name='" + domain.substring(1) + "' )");
		}
		query.append(" )");
		String queryString = query.toString();
		return queryString;
	}

	@Override
	public String createStringKey() {
		String key = getDomain() != null ? (getLocalpart() + "@" + getFullDomain())
				: "?@?";
		return key;
	}

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

	public long getId() {
		return id;
	}

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

	public String getLocalpart() {
		return localpart == null ? "" : localpart;
	}

	public void setLocalpart(String localpart) {
		this.localpart = trimToEmpty(localpart);
	}

	public String getSubdomain() {
		return subdomain == null || subdomain.length() == 0 ? null : subdomain;
	}

	public void setSubdomain(String subdomain) {
		this.subdomain = trimToNull(subdomain);
	}

	public Domain getDomain() {
		return domain;
	}

	public void setDomain(Domain domain) {
		this.domain = domain;
	}

	public String getTarget() {
		return target;
	}

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

	@Transient
	public String getEMailAddress() {
		return createStringKey();
	}

	/**
	 * returns the full domain (subdomain + domain)
	 */
	@Transient
	public String getFullDomain() {
		return (getSubdomain() == null ? "" : (getSubdomain() + "."))
				+ getDomain().getName();
	}

	public String toString() {
		if (localpart != null && target != null && domain != null) {
			String local = super.toString() + "{ id=" + id + "; address=" + localpart + "@";
			if (subdomain != null) { local += "." + subdomain; }
			return local + domain + "; target=" + target + " }";
		} else {
			return super.toString();
		}
	}

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

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

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

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

	@Override
	public boolean isWriteAllowedFor(UnixUser loginUser) {
		return getDomain().isWriteAllowedFor(loginUser);
	}

	/**
	 * query restriction for this Entity
	 */
	public static String restriction() {
		return "( " +
			// domain-owner?
			"obj.domain.user = :loginUser OR " +
			// pac-admin? (TODO: Hostsharing name convention)
			"obj.domain.user.pac.name = :loginUserName OR " +
			// customer
			"obj.domain.user.pac.customer.name = :loginUserName )";
	}

}
