/**
 * my-axelor-app
 *
 * Copyright (C) 2018 My Company (<http://my-company.com>).
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.axelor.orders.db;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;

import org.hibernate.annotations.Index;
import org.hibernate.annotations.Type;

import com.axelor.auth.db.AuditableModel;
import com.axelor.db.annotations.HashKey;
import com.axelor.db.annotations.NameColumn;
import com.axelor.db.annotations.Widget;
import com.google.common.base.MoreObjects;

@Entity
@Cacheable
@Table(name = "ORDERS_CUSTOMER")
public class Customer extends AuditableModel {

	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ORDERS_CUSTOMER_SEQ")
	@SequenceGenerator(name = "ORDERS_CUSTOMER_SEQ", sequenceName = "ORDERS_CUSTOMER_SEQ", allocationSize = 1)
	private Long id;

	@HashKey
	@Widget(title = "客户编号")
	@NotNull
	@Column(unique = true)
	private String code;

	@Widget(title = "姓名")
	@NameColumn
	@NotNull
	@Index(name = "ORDERS_CUSTOMER_NAME_IDX")
	private String name;

	@Widget(title = "地址")
	private String address;

	@Widget(title = "备注")
	@Lob
	@Basic(fetch = FetchType.LAZY)
	@Type(type = "org.hibernate.type.TextType")
	private String notes;

	@OneToMany(fetch = FetchType.LAZY, mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true)
	private List<SalesOrder> orders;

	public Customer() {
	}

	public Customer(String code, String name) {
		this.code = code;
		this.name = name;
	}

	@Override
	public Long getId() {
		return id;
	}

	@Override
	public void setId(Long id) {
		this.id = id;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getName() {
		return name;
	}

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

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getNotes() {
		return notes;
	}

	public void setNotes(String notes) {
		this.notes = notes;
	}

	public List<SalesOrder> getOrders() {
		return orders;
	}

	public void setOrders(List<SalesOrder> orders) {
		this.orders = orders;
	}

	/**
	 * Add the given {@link SalesOrder} item to the {@code orders}.
	 *
	 * <p>
	 * It sets {@code item.customer = this} to ensure the proper relationship.
	 * </p>
	 *
	 * @param item
	 *            the item to add
	 */
	public void addOrder(SalesOrder item) {
		if (orders == null) {
			orders = new ArrayList<SalesOrder>();
		}
		orders.add(item);
		item.setCustomer(this);
	}

	/**
	 * Remove the given {@link SalesOrder} item from the {@code orders}.
	 *
 	 * @param item
	 *            the item to remove
	 */
	public void removeOrder(SalesOrder item) {
		if (orders == null) {
			return;
		}
		orders.remove(item);
	}

	/**
	 * Clear the {@code orders} collection.
	 *
	 * <p>
	 * If you have to query {@link SalesOrder} records in same transaction, make
	 * sure to call {@link javax.persistence.EntityManager#flush() } to avoid
	 * unexpected errors.
	 * </p>
	 */
	public void clearOrders() {
		if (orders != null) {
			orders.clear();
		}
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null) return false;
		if (this == obj) return true;
		if (!(obj instanceof Customer)) return false;

		final Customer other = (Customer) obj;
		if (this.getId() != null || other.getId() != null) {
			return Objects.equals(this.getId(), other.getId());
		}

		if (!Objects.equals(getCode(), other.getCode())) return false;

		return true;
	}

	@Override
	public int hashCode() {
		return Objects.hash(670819326, this.getCode());
	}

	@Override
	public String toString() {
		final MoreObjects.ToStringHelper tsh = MoreObjects.toStringHelper(this);

		tsh.add("id", this.getId());
		tsh.add("code", this.getCode());
		tsh.add("name", this.getName());
		tsh.add("address", this.getAddress());

		return tsh.omitNullValues().toString();
	}
}
