/***
 * Excerpted from "Domain-Driven Design Using Naked Objects",
 * published by The Pragmatic Bookshelf.
 * Copyrights apply to this code. It may not be used to create training material, 
 * courses, books, articles, and the like. Contact us if you are in doubt.
 * We make no guarantees that this code is fit for any purpose. 
 * Visit http://www.pragmaticprogrammer.com/titles/dhnako for more book information.
***/
package com.pragprog.dhnako.carserv.dom.application;

import org.nakedobjects.applib.AbstractDomainObject;
import org.nakedobjects.applib.annotation.Disabled;
import org.nakedobjects.applib.annotation.MemberOrder;
import org.nakedobjects.applib.annotation.Named;
import org.nakedobjects.applib.annotation.NotPersistable;
import org.nakedobjects.applib.annotation.Optional;
import org.nakedobjects.applib.annotation.RegEx;

import com.pragprog.dhnako.carserv.dom.customer.Account;
import com.pragprog.dhnako.carserv.dom.customer.Cash;
import com.pragprog.dhnako.carserv.dom.customer.CreditCard;
import com.pragprog.dhnako.carserv.dom.customer.Customer;
import com.pragprog.dhnako.carserv.dom.customer.CustomerRepository;
import com.pragprog.dhnako.carserv.dom.payment.PaymentMethod;
import com.pragprog.dhnako.carserv.dom.payment.PaymentMethodType;
import com.pragprog.dhnako.carserv.dom.payment.PaymentMethodTypeRepository;
import com.pragprog.dhnako.carserv.dom.person.Person;
import com.pragprog.dhnako.carserv.dom.person.Title;
import com.pragprog.dhnako.carserv.dom.vehicle.Model;
import com.pragprog.dhnako.carserv.dom.vehicle.RegistrationNumber;
import com.pragprog.dhnako.carserv.dom.vehicle.Vehicle;

@NotPersistable
public class CustomerTakeOn extends AbstractDomainObject {

	// {{ Identification
	public String title() {
		return "Customer Take On";
	}
	// }}
	
	
	// {{ Title
	private Title title;
	
	@MemberOrder(sequence = "1.1")
	public Title getTitle() {
		return title;
	}
	
	public void setTitle(final Title title) {
		this.title = title;
	}

	public String disableTitle() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}
	
	// {{ FirstName
	private String firstName;

	@MemberOrder(sequence = "1.2")
	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(final String firstName) {
		this.firstName = firstName;
	}

	public String disableFirstName() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}


	
	// {{ LastName
	private String lastName;

	@MemberOrder(sequence = "1.3")
	public String getLastName() {
		return lastName;
	}

	public void setLastName(final String lastName) {
		this.lastName = lastName;
	}

	public String disableLastName() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}

	
	// {{ Vehicle1Model
	private Model vehicle1Model;

	@Optional
	@MemberOrder(sequence = "2.1")
	public Model getVehicle1Model() {
		return vehicle1Model;
	}

	public void setVehicle1Model(final Model vehicle1Model) {
		this.vehicle1Model = vehicle1Model;
	}

	public String disableVehicle1Model() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}


	// {{ Vehicle1RegistrationNumber
	private RegistrationNumber vehicle1RegistrationNumber;

	@Optional
	@MemberOrder(sequence = "2.2")
	public RegistrationNumber getVehicle1RegistrationNumber() {
		return vehicle1RegistrationNumber;
	}

	public void setVehicle1RegistrationNumber(final RegistrationNumber vehicle1RegistrationNumber) {
		this.vehicle1RegistrationNumber = vehicle1RegistrationNumber;
	}

	public String disableVehicle1RegistrationNumber() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}


	
	// {{ Vehicle2Model
	private Model vehicle2Model;

	@Optional
	@MemberOrder(sequence = "3.1")
	public Model getVehicle2Model() {
		return vehicle2Model;
	}

	public void setVehicle2Model(final Model vehicle2Model) {
		this.vehicle2Model = vehicle2Model;
	}

	public String disableVehicle2Model() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}


	
	// {{ Vehicle2RegistrationNumber
	private RegistrationNumber vehicle2RegistrationNumber;

	@Optional
	@MemberOrder(sequence = "3.2")
	public RegistrationNumber getVehicle2RegistrationNumber() {
		return vehicle2RegistrationNumber;
	}

	public void setVehicle2RegistrationNumber(final RegistrationNumber vehicle2RegistrationNumber) {
		this.vehicle2RegistrationNumber = vehicle2RegistrationNumber;
	}

	public String disableVehicle2RegistrationNumber() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}


	// {{ CreditCardNumber
	private String creditCardNumber;

	@Optional
	@MemberOrder(sequence = "4.1")
	public String getCreditCardNumber() {
		return creditCardNumber;
	}

	public void setCreditCardNumber(final String creditCardNumber) {
		this.creditCardNumber = creditCardNumber;
	}

	public String disableCreditCardNumber() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}

	
	// {{ CreditCardExpiryDate
	private String creditCardExpiryDate;

	@Optional
	@RegEx(validation="[0-9]{2}/[0-9]{4}")
	@MemberOrder(sequence = "4.2")
	public String getCreditCardExpiryDate() {
		return creditCardExpiryDate;
	}

	public void setCreditCardExpiryDate(final String creditCardExpiryDate) {
		this.creditCardExpiryDate = creditCardExpiryDate;
	}

	public String disableCreditCardExpiryDate() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}
	
	
	// {{ AccountLimit
	private Integer accountLimit;

	@Optional
	@MemberOrder(sequence = "5.1")
	public Integer getAccountLimit() {
		return accountLimit;
	}

	public void setAccountLimit(final Integer accountLimit) {
		this.accountLimit = accountLimit;
	}

	public String disableAccountLimit() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}


	
	// {{ SetupCash
	private Boolean setupCash;

	@Optional
	@MemberOrder(sequence = "6.1")
	public Boolean getSetupCash() {
		return setupCash;
	}

	public void setSetupCash(final Boolean setupCash) {
		this.setupCash = setupCash;
	}

	public String disableSetupCash() {
		return getTakenOn()?"Already taken on":null;
	}
	// }}


	
	// {{ TakenOn
	private Boolean takenOn;

	@Disabled
	@MemberOrder(sequence = "9")
	public Boolean getTakenOn() {
		return takenOn;
	}

	public void setTakenOn(final Boolean takenOn) {
		this.takenOn = takenOn;
	}

	public Boolean defaultTakenOn() {
		return false;
	}
	// }}



	// {{
	@Named("OK")
	public Person ok() {
	    Person person = 
	        customerRepository.newCustomer();
	    person.getName().setFirstName(getFirstName());
	    person.getName().setLastName(getLastName());
	    person.getName().setTitle(getTitle());
	    Customer customer = person.getRole(Customer.class);
	    if (enteredAllOf(getVehicle1Model(), getVehicle1RegistrationNumber())) {
	        Vehicle vehicle = customer.newVehicle(getVehicle1Model());
	        vehicle.setRegistrationNumber(getVehicle1RegistrationNumber());
	        customer.addToVehicles(vehicle);
	    }
	    if (enteredAllOf(getVehicle2Model(), getVehicle2RegistrationNumber())) {
	        Vehicle vehicle = customer.newVehicle(getVehicle2Model());
	        vehicle.setRegistrationNumber(getVehicle2RegistrationNumber());
	        customer.addToVehicles(vehicle);
	    }
	    if (enteredAllOf(getCreditCardNumber(), getCreditCardExpiryDate())) {
	    	CreditCard creditCard = (CreditCard) customer.newPaymentMethod(findPaymentMethodType(CreditCard.class));
	    	creditCard.setCardNumber(getCreditCardNumber());
	    	creditCard.setExpiryDate(getCreditCardExpiryDate());
	    	customer.addToPaymentMethods(creditCard);
	    }
	    if (enteredAllOf(getAccountLimit()) && getAccountLimit() > 0) {
	    	Account account = (Account) customer.newPaymentMethod(findPaymentMethodType(Account.class));
	    	account.setLimit(getAccountLimit());
	    	customer.addToPaymentMethods(account);
	    }
	    if (getSetupCash()) {
	    	Cash cash = (Cash) customer.newPaymentMethod(findPaymentMethodType(Cash.class));
	    	customer.addToPaymentMethods(cash);
	    }
	    persist(person);
	    setTakenOn(true);
	    return person;
	}
	public String disableOk() {
		String invalidReason = validate(this);
		if (invalidReason != null) {
			return invalidReason;
		}
		return getTakenOn()?"Already taken on":null;
	}
	// }}

	
	// {{ Helpers
	private PaymentMethodType findPaymentMethodType(final Class<? extends PaymentMethod> paymentMethodClass) {
		return paymentMethodTypeRepository.findByClassName(paymentMethodClass.getName());
	}
	private static boolean enteredAllOf(final Object... objects) {
		for(Object o: objects) {
			if (o == null) return false;
		}
		return true;
	}
	// }}


	// {{ injected dependencies
	// {{ injected: CustomerRepository
	private CustomerRepository customerRepository;

	public void setCustomerRepository(final CustomerRepository customerRepository) {
		this.customerRepository = customerRepository;
	}
	// }}

	// {{ injected: PaymentMethodTypeRepository
	private PaymentMethodTypeRepository paymentMethodTypeRepository;

	public void setPaymentMethodTypeRepository(final PaymentMethodTypeRepository paymentMethodTypeRepository) {
		this.paymentMethodTypeRepository = paymentMethodTypeRepository;
	}
	// }}

	// }}



}
