package gov.va.vinci.dart.biz;

import gov.va.vinci.dart.common.ValidationHelper;
import gov.va.vinci.dart.common.exception.ObjectNotFoundException;
import gov.va.vinci.dart.common.exception.ValidationException;
import gov.va.vinci.dart.service.DartObjectFactory;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="participant", schema="hib")
public class Participant implements Comparable {
	
	protected Participant() {}
	
	@Id
	@Column(name="id")
	@GeneratedValue(strategy=GenerationType.IDENTITY) // because of course SQL Server doesn't support sequences.
	private int id;
	
	@ManyToOne
	@JoinColumn(name="personid")
	private Person person;

	@ManyToOne
	@JoinColumn(name="requestid")
	private Request request;

	@ManyToOne
	@JoinColumn(name="locationid")
	private Location location;

	@Column(name="notification", columnDefinition = "BIT", length = 1)
	private Boolean notification;
	
	@Column(name="dataaccess", columnDefinition = "BIT", length = 1)
	private Boolean dataAccess;
	
	@Column(name="capriaccess", columnDefinition = "BIT", length = 1)
	private Boolean capriAccess;
	
	@Column(name="principalinvestigator", columnDefinition = "BIT", length = 1)
	private Boolean principalInvestigator;

	public static Participant findById(final int participantId) {
		return DartObjectFactory.getInstance().getParticipantDAO().findById(participantId);
	}
	
	public static Participant find(final int requestId, final int personId, final int locationId) {
		return DartObjectFactory.getInstance().getParticipantDAO().find(requestId, personId, locationId);
	}
	
	public static Participant findPrincipalInvestigator(final int requestId, final int locationId) throws ObjectNotFoundException {
		return DartObjectFactory.getInstance().getParticipantDAO().findPrincipalInvestigator(requestId, locationId);
	}
	
	
	public static Participant create(final Person person, final Request request, final Location location, boolean notification, boolean dataAccess, boolean capriAccess, boolean principalInvestigator) throws ValidationException {
       Participant result = new Participant();
        result.modify(person, request, location, notification, dataAccess, capriAccess, principalInvestigator);
        
        DartObjectFactory.getInstance().getParticipantDAO().save(result);
        
        return result;
	}
	
	@Deprecated
	public static Participant create(final Person person, final Request request, final Location location, boolean notification, boolean dataAccess, boolean principalInvestigator) throws ValidationException {
		
		Participant result = new Participant();
		result.modify(person, request, location, notification, dataAccess, principalInvestigator);
		
		DartObjectFactory.getInstance().getParticipantDAO().save(result);
		
		return result;
	}

	// create a copy of this participant
	public Participant copy(Request request) throws ValidationException {
		Participant result = new Participant();
		
		result.modify(person, request, location, notification, dataAccess, capriAccess, principalInvestigator);
		
		DartObjectFactory.getInstance().getParticipantDAO().save(result);
		
		return result;
	}
	
	public void delete() {
		DartObjectFactory.getInstance().getParticipantDAO().delete(this);
	}
	
    public void modify(final Person person, final Request request, final Location location, boolean notification, boolean dataAccess, boolean capriAccess, boolean principalInvestigator) throws ValidationException {
        validateModify(person, request, location);
        
        this.person = person;
        this.request = request;
        this.location = location;
        this.notification = notification;
        this.dataAccess = dataAccess;
        this.capriAccess = capriAccess;
        this.principalInvestigator = principalInvestigator;
    }
	
    @Deprecated    
	public void modify(final Person person, final Request request, final Location location, boolean notification, boolean dataAccess, boolean principalInvestigator) throws ValidationException {
		validateModify(person, request, location);
		
		this.person = person;
		this.request = request;
		this.location = location;
		this.notification = notification;
		this.dataAccess = dataAccess;	
		this.principalInvestigator = principalInvestigator;
	}
	
	private void validateModify(final Person person, final Request request, final Location location) throws ValidationException {
		ValidationHelper.required("Participant Person", person);
		ValidationHelper.required("Participant Request", request);
		ValidationHelper.required("Participant Location", location);
	}
	
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
	
	public Request getRequest() {
		return request;
	}
	
	public Person getPerson() {
		return person;
	}

	public Location getLocation() {
		return location;
	}
	
	public Boolean getNotification() {
		return notification;
	}

	public Boolean getDataAccess() {
		return dataAccess;
	}

	public Boolean getPrincipalInvestigator() {
		return principalInvestigator;
	}
	
	public boolean isSamePersonAndLocation(Participant aParticipant){
	    return this.getPerson().equals(aParticipant.getPerson())
	                && this.getLocation().equals(aParticipant.getLocation());
	}

	@Override
	public int hashCode() {
		return this.id;
	}
	
	// necessary to use (List<Participant>).contains()
	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		
		if ((obj instanceof Participant) == false) {
			return false;
		}
		
		Participant rs2 = (Participant)obj;
		return rs2.getId() == this.getId();
//		return rs2.person.equals(this.person) && rs2.request.equals(this.request) && rs2.location.equals(this.location);
	}
	
	@Override
	public int compareTo(Object o) {
		if (o == null) {
			return -1;
		}
		if (Participant.class.isAssignableFrom(o.getClass()) == false) {
			return -1;
		}
		
		Participant part2 = (Participant)o;
		if (getPerson() == null) {
			return part2.getPerson() == null ? 0 : -1;
		}

		return getPerson().compareTo(part2.getPerson());
	}
	
	public String toString(){
	    return getPerson().getFullName() + "@" + getLocation().getName();	    
	}

    public Boolean getCapriAccess() {
        return capriAccess;
    }

    public void setCapriAccess(Boolean capriAccess) {
        this.capriAccess = capriAccess;
    }

}
