package de.hsadmin.mods.dom;

import static javax.persistence.FetchType.EAGER;
import static javax.persistence.GenerationType.SEQUENCE;

import java.util.Date;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;

import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AnnFieldIO;
import de.hsadmin.core.model.AnnModuleImpl;
import de.hsadmin.core.model.ReadWriteAccess;
import de.hsadmin.mods.user.UnixUser;

@Entity(name = "Domains")
@Table(name = "domain")
@SequenceGenerator(name = "DomainsSeqGen", sequenceName = "domain_domain_id_seq")
@AnnModuleImpl(de.hsadmin.mods.dom.DomainModuleImpl.class)
public class Domain extends AbstractEntity {

	@Id
	@Column(name = "domain_id", columnDefinition = "integer")
	@GeneratedValue(strategy = SEQUENCE, generator = "DomainsSeqGen")
	private long id;

	@AnnFieldIO(validation="([-a-z0-9]+\\.)+[a-z]{2,}", rw=ReadWriteAccess.WRITEONCE)
	@Column(name = "domain_name", columnDefinition = "character varying(256)", nullable = false)
	private String name;

	@AnnFieldIO(validation="[a-z0-9\\_\\-\\.]*", rw=ReadWriteAccess.WRITEONCE)
	@JoinColumn(name = "domain_owner", columnDefinition = "integer", nullable = false)
	@ManyToOne(fetch = EAGER)
	private UnixUser user;

	@AnnFieldIO(validation="[0-9\\.\\/\\-]*", rw=ReadWriteAccess.READONLY)
	@Column(name = "domain_since", columnDefinition = "date")
	@Temporal(javax.persistence.TemporalType.DATE)
	private Date since;

	@AnnFieldIO(validation="[a-z0-9\\-\\.]*", rw=ReadWriteAccess.WRITEONCE)
	@Column(name = "domain_dns_master", columnDefinition = "character varying(64)")
	private String dnsMaster;

	@AnnFieldIO(validation="[a-zA-Z0-9\\-\\.]*", rw=ReadWriteAccess.READWRITE, referTo=DomainOption.class, selectableValues=DomainOptionValues.class)
	@ManyToMany(fetch=FetchType.EAGER, cascade=CascadeType.PERSIST)
	@JoinTable(name="domain__domain_option", 
		joinColumns={@JoinColumn(name="domain_id", referencedColumnName="domain_id")},
		inverseJoinColumns={@JoinColumn(name="domain_option_id", referencedColumnName="domain_option_id")})
	private Set<DomainOption> domainoptions;
	
	public Domain() {
	}

	public Domain(String name, UnixUser user) {
		this.name = name;
		this.user = user;
	}

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

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

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

	public long getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

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

	public UnixUser getUser() {
		return user;
	}

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

	public Date getSince() {
		return since;
	}

	public void setSince(Date since) {
		this.since = since;
	}

	public String getDnsMaster() {
		return dnsMaster;
	}

	public void setDnsMaster(String dnsMaster) {
		this.dnsMaster = dnsMaster;
	}

	public boolean isPacDomain() {
		if (getUser() != null && getUser().getPac() != null) {
			String pacDomName = getUser().getPac().getName() + ".hostsharing.net";
			return pacDomName.equals(getName());
		}
		return false;
	}

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

	public boolean isReadAllowedFor(UnixUser loginUser) {
		return loginUser.hasHostmasterRole() || // hostmaster
				user.getId() == loginUser.getId() || // dom-admin
				user.getPac().getName().equals(loginUser.getName()) || // pac-admin
				user.getPac().getCustomer().getName().equals(loginUser.getName()); // customer
	}

	public boolean isWriteAllowedFor(UnixUser loginUser) {
		return isReadAllowedFor(loginUser);
	}

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

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

	public static String restriction() {
		return
			// all doms of all pacs of customer
			"obj.user.pac.customer.name=:loginUserName OR " +
			// all doms of packet admin
			"obj.user.pac.name=:loginUserName OR " +
			// all domains of the user itself
			"obj.user=:loginUser";
	}

	public Set<DomainOption> getDomainoptions() {
		return domainoptions;
	}

	public void setDomainoptions(Set<DomainOption> domainOptions) {
		this.domainoptions = domainOptions;
	}

}
