package de.hsadmin.mods.pac;

import static javax.persistence.CascadeType.ALL;
import static javax.persistence.FetchType.EAGER;
import static javax.persistence.FetchType.LAZY;
import static javax.persistence.GenerationType.SEQUENCE;

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

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.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.mods.cust.Customer;
import de.hsadmin.mods.user.UnixUser;

@Entity(name = "Pacs")
@Table(name = "packet")
@SequenceGenerator(name = "PacsSeqGen", sequenceName = "packet_packet_id_seq")
@EntityInfo(name = "Paket")
public class Pac extends AbstractEntity implements Serializable {
	
	private static final long serialVersionUID = 1201899873300190132L;

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

	@Column(name = "packet_name", unique = true)
	private String name;

	@JoinColumn(name = "bp_id")
	@ManyToOne(fetch = EAGER)
	private Customer customer;

	@JoinColumn(name = "hive_id")
	@ManyToOne(fetch = EAGER)
	private Hive hive;

	@Column(name = "created")
	@Temporal(TemporalType.DATE)
	private Date created;

	@Column(name = "cancelled", nullable = true)
	@Temporal(TemporalType.DATE)
	private Date cancelled;

	@Column(name = "order_number", nullable = true)
	private String orderNo;

	@Column(name = "webserver_group", nullable = true)
	private String webserverGroup;

	@JoinColumn(name = "cur_inet_addr_id", nullable = true)
	@ManyToOne(fetch = EAGER)
	private INetAddress curINetAddr;

	@JoinColumn(name = "old_inet_addr_id", nullable = true)
	@ManyToOne(fetch = EAGER)
	private INetAddress oldINetAddr;

	@OneToMany(fetch = LAZY, cascade = ALL, mappedBy="pac")
	private Set<PacComponent> pacComponents;

	@OneToMany(fetch = LAZY, cascade = ALL, mappedBy="pac")
	private Set<UnixUser> unixUser;

	@Transient
	private BasePac basepac;
	
	public Pac() {
		basepac = new BasePac();
		curINetAddr = new INetAddress();
		hive = new Hive();
	}

	public Pac(String name, Customer cust, BasePac basePac, Hive hive) {
		this.name = name;
		this.customer = cust;
		this.hive = hive;

		this.created = new Date();
		this.webserverGroup = "httpd";
		this.curINetAddr = hive.getInetAddr();

		pacComponents = new HashSet<PacComponent>();
		Date today = new Date();
		for (Component comp : basePac.getComponents()) {
			PacComponent pacComp = new PacComponent(basePac,
					comp.getBaseComponent(), this, comp.getDefaultQuantity(),
					today, null);
			pacComponents.add(pacComp);
			System.err.println("TRACE [Pac]: added pacComp " + pacComp + " to "
					+ getName());
		}
	}

	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;
	}

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

	public String getName() {
		return name;
	}

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

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

	public Hive getHive() {
		return hive;
	}

	public void setHive(Hive hive) {
		this.hive = hive;
	}

	public Date getCreated() {
		return created;
	}

	public void setCreated(Date created) {
		this.created = created;
	}

	public Date getCancelled() {
		return cancelled;
	}

	public void setCancelled(Date cancelled) {
		this.cancelled = cancelled;
	}

	public String getOrderNo() {
		return orderNo;
	}

	public void setOrderNo(String orderNo) {
		this.orderNo = orderNo;
	}

	public String getwebserverGroup() {
		return webserverGroup;
	}

	public void setwebserverGroup(String webserverGroup) {
		this.webserverGroup = webserverGroup;
	}

	public INetAddress getCurINetAddr() {
		return curINetAddr;
	}

	public void setCurINetAddr(INetAddress curINetAddr) {
		this.curINetAddr = curINetAddr;
	}

	public INetAddress getOldINetAddr() {
		return oldINetAddr;
	}

	public void setOldINetAddr(INetAddress oldINetAddr) {
		this.oldINetAddr = oldINetAddr;
	}

	public BasePac getBasepac() {
		if (basepac == null || basepac.getName() == null) {
			Set<PacComponent> pacComps = getPacComponents();
			if (pacComps != null) {
				basepac = pacComps.iterator().next().getBasePac();
			}
		}
		return basepac;
	}

	public void setBasepac(BasePac basepac) {
		this.basepac = basepac;
	}

	public Set<PacComponent> getPacComponents() {
		return pacComponents;
	}

	public void setPacComponents(Set<PacComponent> pacComponents) {
		this.pacComponents = pacComponents;
	}

	public PacComponent getPacComponent(String feature) {
		for (PacComponent pc : getPacComponents())
			if (feature.equals(pc.getBaseComponent().getFeature()))
				return pc;
		return null;
	}

	public Set<UnixUser> getUnixUser() {
		return unixUser;
	}

	public void setUnixUser(Set<UnixUser> unixUser) {
		this.unixUser = unixUser;
	}

	public String toString() {
		return super.toString() + "{ name=" + name + " }";
	}

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

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

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

	public UnixUser getAdminUser(EntityManager em) {
		return null;
	}

	public boolean isReadAllowedFor(UnixUser loginUser) {
		return getName().equals(loginUser.getName())
				|| getCustomer().getName().equals(loginUser.getName())
				|| super.isReadAllowedFor(loginUser);
	}

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