package de.hsadmin.mods.cust;

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

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.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.Transient;

import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;

@Entity(name = "Customers")
@Table(name = "business_partner")
public class Customer extends de.hsadmin.core.model.AbstractEntity implements Serializable {

	private static final long serialVersionUID = -7450594652238392616L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "bp_id", columnDefinition = "integer")
	private long id;

	@Column(name = "member_id", columnDefinition = "integer")
	private int memberNo;

	@Column(name = "member_code", columnDefinition = "character varying(20)")
	private String name;
	
	@Transient
	private String password;

	@Column(name = "member_since", columnDefinition = "date", nullable = true)
	private Date memberSince;

	@Column(name = "member_until", columnDefinition = "date", nullable = true)
	@Temporal(javax.persistence.TemporalType.DATE)
	private Date memberUntil;

	@Column(name = "member_role", columnDefinition = "character varying(100)", nullable = true)
	private String memberRole;

	@Column(name = "author_contract", columnDefinition = "date", nullable = true)
	@Temporal(javax.persistence.TemporalType.DATE)
	private Date authorContract;

	@Column(name = "nondisc_contract", columnDefinition = "date", nullable = true)
	@Temporal(javax.persistence.TemporalType.DATE)
	private Date nonDiscContract;

	@Column(name = "shares_updated", columnDefinition = "date", nullable = true)
	@Temporal(javax.persistence.TemporalType.DATE)
	private Date sharesUpdated;

	@Column(name = "shares_signed", columnDefinition = "integer")
	private int sharesSigned;

	@Column(name = "uid_vat", columnDefinition = "character varying(20)", nullable = true)
	private String uidVAT;

	@OneToMany(fetch = EAGER, cascade = ALL, mappedBy = "customer")
	private Set<Contact> contacts;

	@OneToOne(fetch = EAGER, cascade = ALL, mappedBy = "customer")
	private BankAccount bankAccount;

	@OneToOne(fetch = EAGER, cascade = ALL, mappedBy = "customer")
	private CustomersTariff billData;

	@OneToMany(fetch = LAZY, cascade = ALL, mappedBy = "customer")
	@OrderBy("name")
	private Set<Pac> pacs;

	public Customer() {
	}

	public Customer(int memberNo, String memberCode) {
		this.memberNo = memberNo;
		this.name = memberCode;
	}

	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 int getMemberNo() {
		return memberNo;
	}

	public void setMemberNo(int memberNo) {
		this.memberNo = memberNo;
	}

	public String getName() {
		return name;
	}

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

	public Date getMemberSince() {
		return memberSince;
	}

	public void setMemberSince(Date memberSince) {
		this.memberSince = memberSince;
	}

	public Date getMemberUntil() {
		return memberUntil;
	}

	public void setMemberUntil(Date memberUntil) {
		this.memberUntil = memberUntil;
	}

	public String getMemberRole() {
		return memberRole;
	}

	public void setMemberRole(String memberRole) {
		this.memberRole = memberRole;
	}

	public Date getAuthorContract() {
		return authorContract;
	}

	public void setAuthorContract(Date authorContract) {
		this.authorContract = authorContract;
	}

	public Date getNonDiscContract() {
		return nonDiscContract;
	}

	public void setNonDiscContract(Date nonDiscContract) {
		this.nonDiscContract = nonDiscContract;
	}

	public Date getSharesUpdated() {
		return sharesUpdated;
	}

	public void setSharesUpdated(Date sharesUpdated) {
		this.sharesUpdated = sharesUpdated;
	}

	public int getSharesSigned() {
		return sharesSigned;
	}

	public void setSharesSigned(int sharesSigned) {
		this.sharesSigned = sharesSigned;
	}

	public String getUidVAT() {
		return uidVAT;
	}

	public void setUidVAT(String uidVAT) {
		this.uidVAT = uidVAT;
	}

	public Set<Contact> getContacts() {
		if (contacts == null) {
			contacts = new HashSet<Contact>();
			contacts.add(new Contact(this));
		}
		return contacts;
	}

	public void setContacts(Set<Contact> contacts) {
		this.contacts = contacts;
	}

	// virtual attribute contractualContact
	// TODO: currently only a single contact can be managed
	public Contact getContractualContact() {
		return getContacts().iterator().next();
	}

	public void setContractualContact(Contact contact) {
		contacts = new HashSet<Contact>();
		contacts.add(contact);
	}

	public BankAccount getBankAccount() {
		return bankAccount;
	}

	public void setBankAccount(BankAccount bankAccount) {
		this.bankAccount = bankAccount;
	}

	public CustomersTariff getBillData() {
		return billData;
	}

	public void setBillData(CustomersTariff tariff) {
		this.billData = tariff;
	}

	public Set<Pac> getPacs() {
		return pacs;
	}

	public void setPacs(Set<Pac> pacs) {
		this.pacs = pacs;
	}

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

	@Override
	public UnixUser owningUser(EntityManager em) {
		return null; // TODO: no access yet
	}

	/** 
	 * determines whether the given user has full read access on all merged fields of this entity
	 */
	@Override
	public boolean isReadAllowedFor(UnixUser loginUser) {
		return loginUser.hasCustomerRoleFor(this);
	}

	/** 
	 * determines whether the given user has full write access on all merged fields of this entity
	 */
	@Override
	public boolean isWriteAllowedFor(UnixUser loginUser) {
		return loginUser.hasCustomerRoleFor(this);
	}
	
	public static String restriction() {
		return "obj.name=:loginUserName";
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPassword() {
		return password;
	}
}
