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

import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AnnModuleImpl;
import de.hsadmin.hostsharing.BasePacType;
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")
@AnnModuleImpl(de.hsadmin.mods.pac.PacModuleImpl.class)
public class Pac extends AbstractEntity implements Serializable {
	
	private static final long serialVersionUID = 1L;

	public static final int UNDEFINED_QUANTITY = -1;
	
	@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 = LAZY)
	private Customer customer;

	@JoinColumn(name = "basepacket_id")
	@ManyToOne(fetch = EAGER)
	private BasePac basePac;

	@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 = "free", nullable = false)
	private boolean free = false;
	
	@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 = EAGER, cascade = ALL, mappedBy="pac")
	private Set<PacComponent> pacComponents;

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

	public void initPacComponents(EntityManager em, BasePac aBasepac, boolean setDefaults) {
		Query qAttachedBasepac = em.createQuery("SELECT b FROM BasePacs b WHERE b.valid = :valid AND b.name = :name");
		qAttachedBasepac.setParameter("valid", Boolean.TRUE);
		qAttachedBasepac.setParameter("name", aBasepac.getName());
		basePac = (BasePac) qAttachedBasepac.getSingleResult();
		pacComponents = new HashSet<PacComponent>();
		Date today = new Date();
		for (Component comp : basePac.getComponents()) {
			PacComponent pacComp = new PacComponent();
			pacComp.setCreated(today);
			pacComp.setBaseComponent(comp.getBaseComponent());
			pacComp.setPac(this);
			if (setDefaults) {
				pacComp.setQuantity(comp.getDefaultQuantity());
			} else {
				pacComp.setQuantity(UNDEFINED_QUANTITY);
			}
			pacComponents.add(pacComp);
		}
	}

	@Override
	public void initialize(EntityManager em, UnixUser loginUser) {
		super.initialize(em, loginUser);
	}

	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 INetAddress getCurINetAddr() {
		return curINetAddr;
	}

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

	public INetAddress getOldINetAddr() {
		if (oldINetAddr == null) {
			return getCurINetAddr();
		}
		return oldINetAddr;
	}

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

	public BasePac 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) {
		if (pacComponents != null) {
			for (PacComponent pc : pacComponents) {
				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";
	}

	public boolean isFree() {
		return free;
	}

	public void setFree(boolean free) {
		this.free = free;
	}

	public int getQuantityByComponentName(String componentName) {
		PacComponent multi = getPacComponent(componentName);
		if (multi == null) {
			return 0;
		} else { 
			return multi.getQuantity();
		}
	}
	
	public boolean isDynamic() {
		String basepacName = getBasepac().getName();
		return BasePacType.PAC_DW.equals(basepacName) || BasePacType.PAC_WEB.equals(basepacName);
	}

	public boolean isManagedServer() {
		String basepacName = getBasepac().getName();
		return BasePacType.PAC_SRV.equals(basepacName);
	}
}
