// Generated by: hibernate/SpringHibernateDaoImpl.vsl in andromda-spring-cartridge.
// license-header java merge-point
/**
 * This is only generated once! It will never be overwritten.
 * You can (and have to!) safely modify it by hand.
 */
package org.phoenixctms.ctsms.domain;

import java.awt.Dimension;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.phoenixctms.ctsms.enumeration.DBModule;
import org.phoenixctms.ctsms.enumeration.FileModule;
import org.phoenixctms.ctsms.enumeration.PaymentMethod;
import org.phoenixctms.ctsms.enumeration.VariablePeriod;
import org.phoenixctms.ctsms.query.CategoryCriterion;
import org.phoenixctms.ctsms.query.CategoryCriterion.EmptyPrefixModes;
import org.phoenixctms.ctsms.query.CriteriaUtil;
import org.phoenixctms.ctsms.query.QueryUtil;
import org.phoenixctms.ctsms.query.SubCriteriaMap;
import org.phoenixctms.ctsms.security.CipherText;
import org.phoenixctms.ctsms.security.CryptoUtil;
import org.phoenixctms.ctsms.util.CommonUtil;
import org.phoenixctms.ctsms.util.CoreUtil;
import org.phoenixctms.ctsms.util.DefaultSettings;
import org.phoenixctms.ctsms.util.SettingCodes;
import org.phoenixctms.ctsms.util.Settings;
import org.phoenixctms.ctsms.util.Settings.Bundle;
import org.phoenixctms.ctsms.vo.CriteriaInstantVO;
import org.phoenixctms.ctsms.vo.DepartmentVO;
import org.phoenixctms.ctsms.vo.PSFVO;
import org.phoenixctms.ctsms.vo.PrivacyConsentStatusTypeVO;
import org.phoenixctms.ctsms.vo.ProbandCategoryVO;
import org.phoenixctms.ctsms.vo.ProbandImageInVO;
import org.phoenixctms.ctsms.vo.ProbandImageOutVO;
import org.phoenixctms.ctsms.vo.ProbandInVO;
import org.phoenixctms.ctsms.vo.ProbandOutVO;
import org.phoenixctms.ctsms.vo.StaffOutVO;
import org.phoenixctms.ctsms.vo.UserOutVO;
import org.phoenixctms.ctsms.vocycle.ProbandReflexionGraph;

/**
 * @see Proband
 */
public class ProbandDaoImpl
extends ProbandDaoBase
{



	private org.hibernate.Criteria createProbandCriteria(String alias) {
		org.hibernate.Criteria probandCriteria;
		if (alias != null && alias.length() > 0) {
			probandCriteria = this.getSession().createCriteria(Proband.class, alias);
		} else {
			probandCriteria = this.getSession().createCriteria(Proband.class);
		}
		return probandCriteria;
	}

	@Override
	protected Collection<Proband> handleFindByCriteria(
			CriteriaInstantVO criteria, PSFVO psf) throws Exception {
		Query query = QueryUtil.createSearchQuery(
				criteria,
				DBModule.PROBAND_DB,
				psf,
				this.getSessionFactory(),
				this.getCriterionTieDao(),
				this.getCriterionPropertyDao(),
				this.getCriterionRestrictionDao());
		return query.list();
	}

	@Override
	protected Collection<Proband> handleFindByIdDepartment(Long probandId,
			Long departmentId, PSFVO psf) throws Exception {
		org.hibernate.Criteria probandCriteria = createProbandCriteria(null);
		SubCriteriaMap criteriaMap = new SubCriteriaMap(Proband.class, probandCriteria);
		CriteriaUtil.applyIdDepartmentCriterion(probandCriteria, probandId, departmentId);
		CriteriaUtil.applyPSFVO(criteriaMap, psf);
		return probandCriteria.list();
	}

	@Override
	protected Collection<Proband> handleFindByMoneyTransferNoParticipation(Long trialId,
			PaymentMethod method, String costType, Boolean paid, boolean total,
			Boolean person, PSFVO psf)
					throws Exception {
		org.hibernate.Criteria probandCriteria = createProbandCriteria("proband0");
		if (person != null) {
			probandCriteria.add(Restrictions.eq("person", person.booleanValue()));
		}
		SubCriteriaMap criteriaMap = new SubCriteriaMap(Proband.class, probandCriteria);
		Criteria moneyTransferCriteria = criteriaMap.createCriteria("moneyTransfers");
		moneyTransferCriteria.add(Restrictions.eq("trial.id", trialId.longValue()));
		if (method != null) {
			moneyTransferCriteria.add(Restrictions.eq("method", method));
		}
		if (paid != null) {
			moneyTransferCriteria.add(Restrictions.eq("paid", paid.booleanValue()));
		}
		CategoryCriterion.apply(moneyTransferCriteria, new CategoryCriterion(costType, "costType", MatchMode.EXACT, EmptyPrefixModes.ALL_ROWS));
		DetachedCriteria subQuery = DetachedCriteria.forClass(ProbandListEntryImpl.class, "probandListEntry"); // IMPL!!!!
		subQuery.setProjection(Projections.rowCount());
		subQuery.add(Restrictions.eqProperty("proband.id", "proband0.id"));
		subQuery.add(Restrictions.eq("trial.id", trialId.longValue()));
		if (!total) {
			subQuery.createCriteria("lastStatus", CriteriaSpecification.INNER_JOIN).createCriteria("status", CriteriaSpecification.INNER_JOIN)
			.add(Restrictions.eq("count", true));
		}
		probandCriteria.add(Subqueries.eq(0l, subQuery));
		return CriteriaUtil.listDistinctRootPSFVO(criteriaMap, psf, this);
		// return probandCriteria.list();
	}

	@Override
	protected Collection<Staff> handleFindByPhysician(Long staffId, PSFVO psf) throws Exception {
		org.hibernate.Criteria probandCriteria = createProbandCriteria(null);
		SubCriteriaMap criteriaMap = new SubCriteriaMap(Proband.class, probandCriteria);
		if (staffId != null) {
			probandCriteria.add(Restrictions.eq("physician.id", staffId.longValue()));
		}
		CriteriaUtil.applyPSFVO(criteriaMap, psf);
		return probandCriteria.list();
	}

	@Override
	protected Collection<Proband> handleFindToBeAutoDeleted(Date today, Long departmentId, Long categoryId, VariablePeriod reminderPeriod, Long reminderPeriodDays, Boolean delete,
			PSFVO psf)
					throws Exception {
		org.hibernate.Criteria probandCriteria = createProbandCriteria(null);
		// probandCriteria.add(Restrictions.eq("person", true));
		// probandCriteria.add(Restrictions.eq("blinded", false));
		// probandCriteria.add(Restrictions.isNotNull("autoDeleteDeadline"));
		SubCriteriaMap criteriaMap = new SubCriteriaMap(Proband.class, probandCriteria);
		if (departmentId != null) {
			probandCriteria.add(Restrictions.eq("department.id", departmentId.longValue()));
		}
		org.hibernate.Criteria categoryCriteria = criteriaMap.createCriteria("category");
		if (categoryId != null) {
			categoryCriteria.add(Restrictions.eq("id", categoryId.longValue()));
		}
		categoryCriteria.add(Restrictions.eq("privacyConsentControl", true)); // performance only...
		if (delete != null) {
			categoryCriteria.add(Restrictions.eq("delete", delete.booleanValue()));
		}
		criteriaMap.createCriteria("privacyConsentStatus").add(Restrictions.eq("autoDelete", true)); // performance only...
		if (psf != null) {
			PSFVO sorterFilter = new PSFVO();
			sorterFilter.setFilters(psf.getFilters());
			sorterFilter.setSortField(psf.getSortField());
			sorterFilter.setSortOrder(psf.getSortOrder());
			CriteriaUtil.applyPSFVO(criteriaMap, sorterFilter);
		}
		ArrayList<Proband> resultSet = CriteriaUtil.listExpirations(probandCriteria, today, null, null, null, reminderPeriod, reminderPeriodDays);
		return (Collection<Proband>) CriteriaUtil.applyPVO(resultSet, psf, false); // no dupes by default
	}

	@Override
	protected long handleGetChildrenCount(Long probandId) throws Exception {
		org.hibernate.Criteria probandCriteria = createProbandCriteria(null);
		probandCriteria.add(Restrictions.idEq(probandId.longValue()));
		org.hibernate.Criteria parentsCriteria = probandCriteria.createCriteria("parents", CriteriaSpecification.INNER_JOIN);
		return (Long) parentsCriteria.setProjection(Projections.rowCount()).uniqueResult();
	}

	@Override
	protected long handleGetCountByCriteria(CriteriaInstantVO criteria, PSFVO psf) throws Exception {
		return QueryUtil.getSearchQueryResultCount(
				criteria,
				DBModule.PROBAND_DB,
				psf,
				this.getSessionFactory(),
				this.getCriterionTieDao(),
				this.getCriterionPropertyDao(),
				this.getCriterionRestrictionDao());
	}

	@Override
	protected long handleGetParentsCount(Long probandId) throws Exception {
		org.hibernate.Criteria probandCriteria = createProbandCriteria(null);
		probandCriteria.add(Restrictions.idEq(probandId.longValue()));
		org.hibernate.Criteria childrenCriteria = probandCriteria.createCriteria("children", CriteriaSpecification.INNER_JOIN);
		return (Long) childrenCriteria.setProjection(Projections.rowCount()).uniqueResult();
	}

	/**
	 * Retrieves the entity object that is associated with the specified value object
	 * from the object store. If no such entity object exists in the object store,
	 * a new, blank entity is created
	 */
	private Proband loadProbandFromProbandImageInVO(ProbandImageInVO probandImageInVO)
	{
		Long id = probandImageInVO.getId();
		Proband proband = null;
		if (id != null) {
			proband = this.load(id);
		}
		if (proband == null)
		{
			proband = Proband.Factory.newInstance();
		}
		return proband;
	}

	/**
	 * Retrieves the entity object that is associated with the specified value object
	 * from the object store. If no such entity object exists in the object store,
	 * a new, blank entity is created
	 */
	private Proband loadProbandFromProbandImageOutVO(ProbandImageOutVO probandImageOutVO)
	{
		// TODO implement loadProbandFromProbandImageOutVO
		throw new UnsupportedOperationException("org.phoenixctms.ctsms.domain.loadProbandFromProbandImageOutVO(ProbandImageOutVO) not yet implemented.");
		/* A typical implementation looks like this: Proband proband = this.load(probandImageOutVO.getId()); if (proband == null) { proband = Proband.Factory.newInstance(); }
		 * return proband; */
	}

	/**
	 * Retrieves the entity object that is associated with the specified value object
	 * from the object store. If no such entity object exists in the object store,
	 * a new, blank entity is created
	 */
	private Proband loadProbandFromProbandInVO(ProbandInVO probandInVO)
	{
		Proband proband = null;
		Long id = probandInVO.getId();
		if (id != null) {
			proband = this.load(id);
		}
		if (proband == null)
		{
			proband = Proband.Factory.newInstance();
		}
		return proband;
	}

	/**
	 * Retrieves the entity object that is associated with the specified value object
	 * from the object store. If no such entity object exists in the object store,
	 * a new, blank entity is created
	 */
	private Proband loadProbandFromProbandOutVO(ProbandOutVO probandOutVO)
	{
		// TODO implement loadProbandFromProbandOutVO
		// throw new UnsupportedOperationException("org.phoenixctms.ctsms.domain.loadProbandFromProbandOutVO(ProbandOutVO) not yet implemented.");
		Proband proband = this.load(probandOutVO.getId());
		if (proband == null)
		{
			proband = Proband.Factory.newInstance();
		}
		return proband;
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public Proband probandImageInVOToEntity(ProbandImageInVO probandImageInVO)
	{
		Proband entity = this.loadProbandFromProbandImageInVO(probandImageInVO);
		this.probandImageInVOToEntity(probandImageInVO, entity, true);
		return entity;
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void probandImageInVOToEntity(
			ProbandImageInVO source,
			Proband target,
			boolean copyIfNull)
	{
		super.probandImageInVOToEntity(source, target, copyIfNull);
		ProbandContactParticulars personParticulars = null;
		if (target.isPerson()) {
			personParticulars = target.getPersonParticulars();
			if (personParticulars == null) {
				personParticulars = ProbandContactParticulars.Factory.newInstance();
				target.setPersonParticulars(personParticulars);
			}
		} else if (copyIfNull) {
			target.setPersonParticulars(null);
		}
		if (personParticulars != null) {
			try {
				if (copyIfNull || source.getFileName() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getFileName());
					personParticulars.setFileNameIv(cipherText.getIv());
					personParticulars.setEncryptedFileName(cipherText.getCipherText());
				}
				if (copyIfNull || source.getFileTimestamp() != null) {
					personParticulars.setFileTimestamp((source.getFileTimestamp() == null ? null : new Timestamp(source.getFileTimestamp().getTime())));
				}
				if (source.getDatas() != null && source.getDatas().length > 0) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getDatas());
					personParticulars.setDataIv(cipherText.getIv());
					personParticulars.setEncryptedData(cipherText.getCipherText());
					personParticulars.setFileSize((long) source.getDatas().length);
					personParticulars.setContentType(this.getMimeTypeDao().findByMimeTypeModule(source.getMimeType(), FileModule.PROBAND_IMAGE).iterator().next());
					Dimension imageDimension = CoreUtil.getImageDimension(source.getDatas());
					if (imageDimension != null) {
						personParticulars.setWidth((long) imageDimension.width);
						personParticulars.setHeight((long) imageDimension.height);
					}
				} else if (copyIfNull) {
					CipherText cipherText = CryptoUtil.encryptValue(null);
					personParticulars.setDataIv(cipherText.getIv());
					personParticulars.setEncryptedData(cipherText.getCipherText());
					personParticulars.setFileSize(0l);
					personParticulars.setContentType(null);
					personParticulars.setWidth(null);
					personParticulars.setHeight(null);
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		AnimalContactParticulars animalParticulars = null;
		if (!target.isPerson()) {
			animalParticulars = target.getAnimalParticulars();
			if (animalParticulars == null) {
				animalParticulars = AnimalContactParticulars.Factory.newInstance();
				target.setAnimalParticulars(animalParticulars);
			}
		} else if (copyIfNull) {
			target.setAnimalParticulars(null);
		}
		if (animalParticulars != null) {
			if (copyIfNull || source.getFileName() != null) {
				animalParticulars.setFileName(source.getFileName());
			}
			// if (copyIfNull || source.getShowCv() != false) {
			// personParticulars.setShowCv(source.getShowCv());
			// }
			if (copyIfNull || source.getFileTimestamp() != null) {
				animalParticulars.setFileTimestamp((source.getFileTimestamp() == null ? null : new Timestamp(source.getFileTimestamp().getTime())));
			}
			if (source.getDatas() != null && source.getDatas().length > 0) {
				animalParticulars.setData(source.getDatas());
				animalParticulars.setFileSize((long) source.getDatas().length);
				animalParticulars.setContentType(this.getMimeTypeDao().findByMimeTypeModule(source.getMimeType(), FileModule.PROBAND_IMAGE).iterator().next());
				Dimension imageDimension = CoreUtil.getImageDimension(source.getDatas());
				if (imageDimension != null) {
					animalParticulars.setWidth((long) imageDimension.width);
					animalParticulars.setHeight((long) imageDimension.height);
				}
			} else if (copyIfNull) {
				animalParticulars.setData(null);
				animalParticulars.setFileSize(0l);
				animalParticulars.setContentType(null);
				animalParticulars.setWidth(null);
				animalParticulars.setHeight(null);
			}
		}

	}

	/**
	 * @inheritDoc
	 */
	@Override
	public Proband probandImageOutVOToEntity(ProbandImageOutVO probandImageOutVO)
	{
		// TODO verify behavior of probandImageOutVOToEntity
		Proband entity = this.loadProbandFromProbandImageOutVO(probandImageOutVO);
		this.probandImageOutVOToEntity(probandImageOutVO, entity, true);
		return entity;
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void probandImageOutVOToEntity(
			ProbandImageOutVO source,
			Proband target,
			boolean copyIfNull)
	{
		// TODO verify behavior of probandImageOutVOToEntity
		super.probandImageOutVOToEntity(source, target, copyIfNull);
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public Proband probandInVOToEntity(ProbandInVO probandInVO)
	{
		Proband entity = this.loadProbandFromProbandInVO(probandInVO);
		this.probandInVOToEntity(probandInVO, entity, true);
		return entity;
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void probandInVOToEntity(
			ProbandInVO source,
			Proband target,
			boolean copyIfNull)
	{
		super.probandInVOToEntity(source, target, copyIfNull);
		Long departmentId = source.getDepartmentId();
		Long physicianId = source.getPhysicianId();
		Long categoryId = source.getCategoryId();
		if (departmentId != null) {
			target.setDepartment(this.getDepartmentDao().load(departmentId));
		} else if (copyIfNull) {
			target.setDepartment(null);
		}
		if (categoryId != null) {
			target.setCategory(this.getProbandCategoryDao().load(categoryId));
		} else if (copyIfNull) {
			target.setCategory(null);
		}
		if (physicianId != null) {
			Staff physician = this.getStaffDao().load(physicianId);
			target.setPhysician(physician);
			physician.addPatients(target);
		} else if (copyIfNull) {
			Staff physician = target.getPhysician();
			target.setPhysician(null);
			if (physician != null) {
				physician.removePatients(target);
			}
		}

		if (copyIfNull || source.getChildIds().size() > 0)
		{
			target.setChildren(toProbandSet(source.getChildIds()));
		}

		ProbandContactParticulars personParticulars = target.getPersonParticulars();
		if (source.isPerson()) {
			if (personParticulars == null) {
				personParticulars = ProbandContactParticulars.Factory.newInstance();
				target.setPersonParticulars(personParticulars);
			}
		} else if (copyIfNull) {
			target.setPersonParticulars(null);
		}
		if (personParticulars != null) {
			try {
				CipherText cipherText = CryptoUtil.encryptValue(null);
				personParticulars.setFileNameIv(cipherText.getIv());
				personParticulars.setEncryptedFileName(cipherText.getCipherText());
				cipherText = CryptoUtil.encryptValue(null);
				personParticulars.setDataIv(cipherText.getIv());
				personParticulars.setEncryptedData(cipherText.getCipherText());
			} catch (Exception e) {
				throw new RuntimeException(e);
			}

			if (copyIfNull || source.getGender() != null) {
				personParticulars.setGender(source.getGender());
			}
			if (source.getDateOfBirth() != null) {
				// GregorianCalendar dateOfBirth = new GregorianCalendar();
				// dateOfBirth.setTime(source.getDateOfBirth());
				// particulars.setYearOfBirth(dateOfBirth.get(GregorianCalendar.YEAR));
				personParticulars.setYearOfBirth(new Long(CommonUtil.getYearOfBirth(source.getDateOfBirth())));
			} else if (copyIfNull) {
				personParticulars.setYearOfBirth(null); // 0L);
			}
			if (source.getLastName() != null) {
				int probandLastNameIndexLength = Settings.getInt(SettingCodes.PROBAND_LAST_NAME_INDEX_LENGTH, Bundle.SETTINGS, DefaultSettings.PROBAND_LAST_NAME_INDEX_LENGTH);
				personParticulars.setLastNameIndex(source.getLastName().substring(0, probandLastNameIndexLength < 0 ? 0 : probandLastNameIndexLength));
			} else if (copyIfNull) {
				personParticulars.setLastNameIndex(null);
			}

			if (copyIfNull || source.getAlias() != null) {
				personParticulars.setAlias(source.getAlias());
			}
			try {
				if (copyIfNull || source.getPrefixedTitle1() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPrefixedTitle1());
					personParticulars.setPrefixedTitle1Iv(cipherText.getIv());
					personParticulars.setEncryptedPrefixedTitle1(cipherText.getCipherText());
				}
				if (copyIfNull || source.getPrefixedTitle2() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPrefixedTitle2());
					personParticulars.setPrefixedTitle2Iv(cipherText.getIv());
					personParticulars.setEncryptedPrefixedTitle2(cipherText.getCipherText());
				}
				if (copyIfNull || source.getPrefixedTitle3() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPrefixedTitle3());
					personParticulars.setPrefixedTitle3Iv(cipherText.getIv());
					personParticulars.setEncryptedPrefixedTitle3(cipherText.getCipherText());
				}
				if (copyIfNull || source.getFirstName() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getFirstName());
					personParticulars.setFirstNameIv(cipherText.getIv());
					personParticulars.setEncryptedFirstName(cipherText.getCipherText());
					personParticulars.setFirstNameHash(CryptoUtil.hashForSearch(source.getFirstName()));
				}
				if (copyIfNull || source.getLastName() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getLastName());
					personParticulars.setLastNameIv(cipherText.getIv());
					personParticulars.setEncryptedLastName(cipherText.getCipherText());
					personParticulars.setLastNameHash(CryptoUtil.hashForSearch(source.getLastName()));
				}
				if (copyIfNull || source.getPostpositionedTitle1() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPostpositionedTitle1());
					personParticulars.setPostpositionedTitle1Iv(cipherText.getIv());
					personParticulars.setEncryptedPostpositionedTitle1(cipherText.getCipherText());
				}
				if (copyIfNull || source.getPostpositionedTitle2() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPostpositionedTitle2());
					personParticulars.setPostpositionedTitle2Iv(cipherText.getIv());
					personParticulars.setEncryptedPostpositionedTitle2(cipherText.getCipherText());
				}
				if (copyIfNull || source.getPostpositionedTitle3() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPostpositionedTitle3());
					personParticulars.setPostpositionedTitle3Iv(cipherText.getIv());
					personParticulars.setEncryptedPostpositionedTitle3(cipherText.getCipherText());
				}
				if (copyIfNull || source.getDateOfBirth() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getDateOfBirth());
					personParticulars.setDateOfBirthIv(cipherText.getIv());
					personParticulars.setEncryptedDateOfBirth(cipherText.getCipherText());
					personParticulars.setDateOfBirthHash(CryptoUtil.hashForSearch(source.getDateOfBirth()));
				}
				if (copyIfNull || source.getCitizenship() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getCitizenship());
					personParticulars.setCitizenshipIv(cipherText.getIv());
					personParticulars.setEncryptedCitizenship(cipherText.getCipherText());
					personParticulars.setCitizenshipHash(CryptoUtil.hashForSearch(source.getCitizenship()));
				}
				if (copyIfNull || source.getComment() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getComment());
					personParticulars.setCommentIv(cipherText.getIv());
					personParticulars.setEncryptedComment(cipherText.getCipherText());
					personParticulars.setCommentHash(CryptoUtil.hashForSearch(source.getComment()));
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}

		}

		AnimalContactParticulars animalParticulars = target.getAnimalParticulars();
		if (!source.isPerson()) {
			if (animalParticulars == null) {
				animalParticulars = AnimalContactParticulars.Factory.newInstance();
				target.setAnimalParticulars(animalParticulars);
			}
		} else if (copyIfNull) {
			target.setAnimalParticulars(null);
		}
		if (animalParticulars != null) {
			if (copyIfNull || source.getAnimalName() != null) {
				animalParticulars.setAnimalName(source.getAnimalName());
			}
			if (copyIfNull || source.getDateOfBirth() != null) {
				animalParticulars.setDateOfBirth(source.getDateOfBirth());
			}
			if (copyIfNull || source.getGender() != null) {
				animalParticulars.setGender(source.getGender());
			}
			if (copyIfNull || source.getComment() != null) {
				animalParticulars.setComment(source.getComment());
			}
			if (copyIfNull || source.getAlias() != null) {
				animalParticulars.setAlias(source.getAlias());
			}
		}

		//		if (copyIfNull || source.getChildIds().size() > 0)
		//		{
		//			target.setChildren(toProbandSet(source.getChildIds()));
		//		}

	}

	/**
	 * @inheritDoc
	 */
	@Override
	public Proband probandOutVOToEntity(ProbandOutVO probandOutVO)
	{
		//		Proband entity = this.loadProbandFromProbandOutVO(probandOutVO);
		//		this.probandOutVOToEntity(probandOutVO, entity, true);
		//		return entity;
		throw new UnsupportedOperationException("out value object to recursive entity not supported");
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void probandOutVOToEntity(
			ProbandOutVO source,
			Proband target,
			boolean copyIfNull)
	{
		super.probandOutVOToEntity(source, target, copyIfNull);
		DepartmentVO departmentVO = source.getDepartment();
		ProbandCategoryVO categoryVO = source.getCategory();
		StaffOutVO physicianVO = source.getPhysician();
		UserOutVO modifiedUserVO = source.getModifiedUser();
		PrivacyConsentStatusTypeVO privacyConsentStatusVO = source.getPrivacyConsentStatus();
		if (departmentVO != null) {
			target.setDepartment(this.getDepartmentDao().departmentVOToEntity(departmentVO));
		} else if (copyIfNull) {
			target.setDepartment(null);
		}
		if (categoryVO != null) {
			target.setCategory(this.getProbandCategoryDao().probandCategoryVOToEntity(categoryVO));
		} else if (copyIfNull) {
			target.setCategory(null);
		}
		if (modifiedUserVO != null) {
			target.setModifiedUser(this.getUserDao().userOutVOToEntity(modifiedUserVO));
		} else if (copyIfNull) {
			target.setModifiedUser(null);
		}
		if (privacyConsentStatusVO != null) {
			target.setPrivacyConsentStatus(this.getPrivacyConsentStatusTypeDao().privacyConsentStatusTypeVOToEntity(privacyConsentStatusVO));
		} else if (copyIfNull) {
			target.setPrivacyConsentStatus(null);
		}
		if (physicianVO != null) {
			Staff physician = this.getStaffDao().staffOutVOToEntity(physicianVO);
			target.setPhysician(physician);
			physician.addPatients(target);
		} else if (copyIfNull) {
			Staff physician = target.getPhysician();
			target.setPhysician(null);
			if (physician != null) {
				physician.removePatients(target);
			}
		}

		ProbandContactParticulars personParticulars = null;
		if (source.isPerson()) {
			personParticulars = target.getPersonParticulars();
			if (personParticulars == null) {
				personParticulars = ProbandContactParticulars.Factory.newInstance();
				target.setPersonParticulars(personParticulars);
			}
		} else if (copyIfNull) {
			target.setPersonParticulars(null);
		}
		if (personParticulars != null) {

			if (copyIfNull || source.getGender() != null) {
				personParticulars.setGender(source.getGender().getSex());
			}
			if (source.getDateOfBirth() != null) {
				// GregorianCalendar dateOfBirth = new GregorianCalendar();
				// dateOfBirth.setTime(source.getDateOfBirth());
				// particulars.setYearOfBirth(dateOfBirth.get(GregorianCalendar.YEAR));
				personParticulars.setYearOfBirth(new Long(CommonUtil.getYearOfBirth(source.getDateOfBirth())));
			} else if (copyIfNull) {
				personParticulars.setYearOfBirth(null); // 0L);
			}
			if (source.getLastName() != null) {
				int probandLastNameIndexLength = Settings.getInt(SettingCodes.PROBAND_LAST_NAME_INDEX_LENGTH, Bundle.SETTINGS, DefaultSettings.PROBAND_LAST_NAME_INDEX_LENGTH);
				personParticulars.setLastNameIndex(source.getLastName().substring(0, probandLastNameIndexLength < 0 ? 0 : probandLastNameIndexLength));
			} else if (copyIfNull) {
				personParticulars.setLastNameIndex(null);
			}
			if (copyIfNull || source.getAlias() != null) {
				personParticulars.setAlias(source.getAlias());
			}
			try {
				if (copyIfNull || source.getPrefixedTitle1() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPrefixedTitle1());
					personParticulars.setPrefixedTitle1Iv(cipherText.getIv());
					personParticulars.setEncryptedPrefixedTitle1(cipherText.getCipherText());
				}
				if (copyIfNull || source.getPrefixedTitle2() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPrefixedTitle2());
					personParticulars.setPrefixedTitle2Iv(cipherText.getIv());
					personParticulars.setEncryptedPrefixedTitle2(cipherText.getCipherText());
				}
				if (copyIfNull || source.getPrefixedTitle3() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPrefixedTitle3());
					personParticulars.setPrefixedTitle3Iv(cipherText.getIv());
					personParticulars.setEncryptedPrefixedTitle3(cipherText.getCipherText());
				}
				if (copyIfNull || source.getFirstName() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getFirstName());
					personParticulars.setFirstNameIv(cipherText.getIv());
					personParticulars.setEncryptedFirstName(cipherText.getCipherText());
					personParticulars.setFirstNameHash(CryptoUtil.hashForSearch(source.getFirstName()));
				}
				if (copyIfNull || source.getLastName() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getLastName());
					personParticulars.setLastNameIv(cipherText.getIv());
					personParticulars.setEncryptedLastName(cipherText.getCipherText());
					personParticulars.setLastNameHash(CryptoUtil.hashForSearch(source.getLastName()));
				}
				if (copyIfNull || source.getPostpositionedTitle1() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPostpositionedTitle1());
					personParticulars.setPostpositionedTitle1Iv(cipherText.getIv());
					personParticulars.setEncryptedPostpositionedTitle1(cipherText.getCipherText());
				}
				if (copyIfNull || source.getPostpositionedTitle2() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPostpositionedTitle2());
					personParticulars.setPostpositionedTitle2Iv(cipherText.getIv());
					personParticulars.setEncryptedPostpositionedTitle2(cipherText.getCipherText());
				}
				if (copyIfNull || source.getPostpositionedTitle3() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getPostpositionedTitle3());
					personParticulars.setPostpositionedTitle3Iv(cipherText.getIv());
					personParticulars.setEncryptedPostpositionedTitle3(cipherText.getCipherText());
				}
				if (copyIfNull || source.getDateOfBirth() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getDateOfBirth());
					personParticulars.setDateOfBirthIv(cipherText.getIv());
					personParticulars.setEncryptedDateOfBirth(cipherText.getCipherText());
					personParticulars.setDateOfBirthHash(CryptoUtil.hashForSearch(source.getDateOfBirth()));
				}
				if (copyIfNull || source.getCitizenship() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getCitizenship());
					personParticulars.setCitizenshipIv(cipherText.getIv());
					personParticulars.setEncryptedCitizenship(cipherText.getCipherText());
					personParticulars.setCitizenshipHash(CryptoUtil.hashForSearch(source.getCitizenship()));
				}
				if (copyIfNull || source.getComment() != null) {
					CipherText cipherText = CryptoUtil.encryptValue(source.getComment());
					personParticulars.setCommentIv(cipherText.getIv());
					personParticulars.setEncryptedComment(cipherText.getCipherText());
					personParticulars.setCommentHash(CryptoUtil.hashForSearch(source.getComment()));
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		AnimalContactParticulars animalParticulars = null;
		if (!source.isPerson()) {
			animalParticulars = target.getAnimalParticulars();
			if (animalParticulars == null) {
				animalParticulars = AnimalContactParticulars.Factory.newInstance();
				target.setAnimalParticulars(animalParticulars);
			}
		} else if (copyIfNull) {
			target.setAnimalParticulars(null);
		}
		if (animalParticulars != null) {
			if (copyIfNull || source.getAnimalName() != null) {
				animalParticulars.setAnimalName(source.getAnimalName());
			}
			if (copyIfNull || source.getDateOfBirth() != null) {
				animalParticulars.setDateOfBirth(source.getDateOfBirth());
			}
			if (copyIfNull || source.getGender() != null) {
				animalParticulars.setGender(source.getGender().getSex());
			}
			if (copyIfNull || source.getComment() != null) {
				animalParticulars.setComment(source.getComment());
			}
			if (copyIfNull || source.getAlias() != null) {
				animalParticulars.setAlias(source.getAlias());
			}
		}
	}

	private ArrayList<Long> toProbandIdCollection(Collection<Proband> probands) { // lazyload persistentset prevention
		// ArrayList<Long> result;
		// if (courses != null && courses.size() > 0) {
		// result = new ArrayList<Long>(courses.size());
		// Iterator<Course> it = courses.iterator();
		// while (it.hasNext()) {
		// result.add(it.next().getId());
		// }
		// } else {
		// result = new ArrayList<Long>();
		// }
		// return result;
		ArrayList<Long> result = new ArrayList<Long>(probands.size());
		Iterator<Proband> it = probands.iterator();
		while (it.hasNext()) {
			result.add(it.next().getId());
		}
		Collections.sort(result); // InVO ID sorting
		return result;
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public ProbandImageInVO toProbandImageInVO(final Proband entity)
	{
		return super.toProbandImageInVO(entity);
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void toProbandImageInVO(
			Proband source,
			ProbandImageInVO target)
	{
		super.toProbandImageInVO(source, target);
		if (source.isPerson()) {
			ProbandContactParticulars personParticulars = source.getPersonParticulars();
			if (personParticulars != null) {
				MimeType contentType = personParticulars.getContentType();
				target.setFileTimestamp(personParticulars.getFileTimestamp());
				if (contentType != null) {
					target.setMimeType(contentType.getMimeType());
				}
				try {
					target.setFileName((String) CryptoUtil.decryptValue(personParticulars.getFileNameIv(), personParticulars.getEncryptedFileName()));
					target.setDatas((byte[]) CryptoUtil.decryptValue(personParticulars.getDataIv(), personParticulars.getEncryptedData()));
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		} else {
			AnimalContactParticulars animalParticulars = source.getAnimalParticulars();
			if (animalParticulars != null) {
				MimeType contentType = animalParticulars.getContentType();
				target.setFileName(animalParticulars.getFileName());
				target.setFileTimestamp(animalParticulars.getFileTimestamp());
				target.setDatas(animalParticulars.getData());
				if (contentType != null) {
					target.setMimeType(contentType.getMimeType());
				}
			}
		}
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public ProbandImageOutVO toProbandImageOutVO(final Proband entity)
	{
		return super.toProbandImageOutVO(entity);
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void toProbandImageOutVO(
			Proband source,
			ProbandImageOutVO target)
	{
		super.toProbandImageOutVO(source, target);
		User modifiedUser = source.getModifiedUser();
		if (modifiedUser != null) {
			target.setModifiedUser(this.getUserDao().toUserOutVO(modifiedUser));
		}
		if (source.isPerson()) {
			ProbandContactParticulars personParticulars = source.getPersonParticulars();
			if (personParticulars != null) {
				MimeType contentType = personParticulars.getContentType();
				target.setFileSize(personParticulars.getFileSize());
				target.setFileTimestamp(personParticulars.getFileTimestamp());
				target.setHeight(personParticulars.getHeight());
				target.setWidth(personParticulars.getWidth());
				target.setHasImage(personParticulars.getFileSize() != null && personParticulars.getFileSize() > 0l);
				if (contentType != null) {
					target.setContentType(this.getMimeTypeDao().toMimeTypeVO(contentType));
				}
				try {
					if (!CoreUtil.isPassDecryption()) {
						throw new Exception();
					}
					target.setFileName((String) CryptoUtil.decryptValue(personParticulars.getFileNameIv(), personParticulars.getEncryptedFileName()));
					target.setDatas((byte[]) CryptoUtil.decryptValue(personParticulars.getDataIv(), personParticulars.getEncryptedData()));
					target.setDecrypted(true);
				} catch (Exception e) {
					target.setFileName(null);
					target.setDatas(null);
					target.setDecrypted(false);
				}
			} else {
				target.setDecrypted(true);
			}
		} else {
			AnimalContactParticulars animalParticulars = source.getAnimalParticulars();
			if (animalParticulars != null) {
				MimeType contentType = animalParticulars.getContentType();
				target.setFileName(animalParticulars.getFileName());
				target.setFileSize(animalParticulars.getFileSize());
				target.setFileTimestamp(animalParticulars.getFileTimestamp());
				target.setHeight(animalParticulars.getHeight());
				target.setWidth(animalParticulars.getWidth());
				// target.setShowCv(animalParticulars.getShowCv() == null ? false : animalParticulars.getShowCv().booleanValue());
				target.setHasImage(animalParticulars.getFileSize() != null && animalParticulars.getFileSize() > 0l);
				if (contentType != null) {
					target.setContentType(this.getMimeTypeDao().toMimeTypeVO(contentType));
				}
				target.setDatas(animalParticulars.getData());
				target.setDecrypted(true);
			} else {
				target.setDecrypted(true);
			}
		}
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public ProbandInVO toProbandInVO(final Proband entity)
	{
		return super.toProbandInVO(entity);
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void toProbandInVO(
			Proband source,
			ProbandInVO target)
	{
		super.toProbandInVO(source, target);
		Department department = source.getDepartment();
		Staff physician = source.getPhysician();
		ProbandCategory category = source.getCategory();
		if (department != null) {
			target.setDepartmentId(department.getId());
		}
		if (category != null) {
			target.setCategoryId(category.getId());
		}
		if (physician != null) {
			target.setPhysicianId(physician.getId());
		}
		target.setChildIds(toProbandIdCollection(source.getChildren()));
		if (source.isPerson()) {
			ProbandContactParticulars personParticulars = source.getPersonParticulars();
			if (personParticulars != null) {
				target.setGender(personParticulars.getGender());
				target.setAlias(personParticulars.getAlias());
				try {
					target.setPrefixedTitle1((String) CryptoUtil.decryptValue(personParticulars.getPrefixedTitle1Iv(), personParticulars.getEncryptedPrefixedTitle1()));
					target.setPrefixedTitle2((String) CryptoUtil.decryptValue(personParticulars.getPrefixedTitle2Iv(), personParticulars.getEncryptedPrefixedTitle2()));
					target.setPrefixedTitle3((String) CryptoUtil.decryptValue(personParticulars.getPrefixedTitle3Iv(), personParticulars.getEncryptedPrefixedTitle3()));
					target.setFirstName((String) CryptoUtil.decryptValue(personParticulars.getFirstNameIv(), personParticulars.getEncryptedFirstName()));
					target.setLastName((String) CryptoUtil.decryptValue(personParticulars.getLastNameIv(), personParticulars.getEncryptedLastName()));
					target.setPostpositionedTitle1((String) CryptoUtil.decryptValue(personParticulars.getPostpositionedTitle1Iv(),
							personParticulars.getEncryptedPostpositionedTitle1()));
					target.setPostpositionedTitle2((String) CryptoUtil.decryptValue(personParticulars.getPostpositionedTitle2Iv(),
							personParticulars.getEncryptedPostpositionedTitle2()));
					target.setPostpositionedTitle3((String) CryptoUtil.decryptValue(personParticulars.getPostpositionedTitle3Iv(),
							personParticulars.getEncryptedPostpositionedTitle3()));
					target.setDateOfBirth((Date) CryptoUtil.decryptValue(personParticulars.getDateOfBirthIv(), personParticulars.getEncryptedDateOfBirth()));
					target.setCitizenship((String) CryptoUtil.decryptValue(personParticulars.getCitizenshipIv(), personParticulars.getEncryptedCitizenship()));
					target.setComment((String) CryptoUtil.decryptValue(personParticulars.getCommentIv(), personParticulars.getEncryptedComment()));
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		} else {
			AnimalContactParticulars animalParticulars = source.getAnimalParticulars();
			if (animalParticulars != null) {
				target.setAnimalName(animalParticulars.getAnimalName());
				target.setAlias(animalParticulars.getAlias());
				target.setDateOfBirth(animalParticulars.getDateOfBirth());
				target.setGender(animalParticulars.getGender());
				target.setComment(animalParticulars.getComment());
			}
		}
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public ProbandOutVO toProbandOutVO(final Proband entity)
	{
		return super.toProbandOutVO(entity);
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void toProbandOutVO(
			Proband source,
			ProbandOutVO target)
	{
		(new ProbandReflexionGraph(this, this.getProbandCategoryDao(), this.getDepartmentDao(), this.getStaffDao(), this.getPrivacyConsentStatusTypeDao(), this.getUserDao()))
		.toVOHelper(source, target, new HashMap<Class, HashMap<Long, Object>>());

		//		super.toProbandOutVO(source, target);
		//		Department department = source.getDepartment();
		//		ProbandCategory category = source.getCategory();
		//		User modifiedUser = source.getModifiedUser();
		//		PrivacyConsentStatusType privacyConsentStatus = source.getPrivacyConsentStatus();
		//		if (department != null) {
		//			target.setDepartment(this.getDepartmentDao().toDepartmentVO(department));
		//		}
		//		if (category != null) {
		//			target.setCategory(this.getProbandCategoryDao().toProbandCategoryVO(category));
		//		}
		//		if (modifiedUser != null) {
		//			target.setModifiedUser(this.getUserDao().toUserOutVO(modifiedUser));
		//		}
		//		if (privacyConsentStatus != null) {
		//			target.setPrivacyConsentStatus(this.getPrivacyConsentStatusTypeDao().toPrivacyConsentStatusTypeVO(privacyConsentStatus));
		//		}
		//		ProbandContactParticulars particulars = source.getParticulars();
		//		if (particulars != null) {
		//			try {
		//				if (!CoreUtil.isPassDecryption()) {
		//					throw new Exception();
		//				}
		//				target.setPrefixedTitle1((String) CryptoUtil.decryptValue(particulars.getPrefixedTitle1Iv(), particulars.getEncryptedPrefixedTitle1()));
		//				target.setPrefixedTitle2((String) CryptoUtil.decryptValue(particulars.getPrefixedTitle2Iv(), particulars.getEncryptedPrefixedTitle2()));
		//				target.setPrefixedTitle3((String) CryptoUtil.decryptValue(particulars.getPrefixedTitle3Iv(), particulars.getEncryptedPrefixedTitle3()));
		//				target.setFirstName((String) CryptoUtil.decryptValue(particulars.getFirstNameIv(), particulars.getEncryptedFirstName()));
		//				target.setLastName((String) CryptoUtil.decryptValue(particulars.getLastNameIv(), particulars.getEncryptedLastName()));
		//				target.setPostpositionedTitle1((String) CryptoUtil.decryptValue(particulars.getPostpositionedTitle1Iv(), particulars.getEncryptedPostpositionedTitle1()));
		//				target.setPostpositionedTitle2((String) CryptoUtil.decryptValue(particulars.getPostpositionedTitle2Iv(), particulars.getEncryptedPostpositionedTitle2()));
		//				target.setPostpositionedTitle3((String) CryptoUtil.decryptValue(particulars.getPostpositionedTitle3Iv(), particulars.getEncryptedPostpositionedTitle3()));
		//				target.setDateOfBirth((Date) CryptoUtil.decryptValue(particulars.getDateOfBirthIv(), particulars.getEncryptedDateOfBirth()));
		//				target.setCitizenship((String) CryptoUtil.decryptValue(particulars.getCitizenshipIv(), particulars.getEncryptedCitizenship()));
		//				target.setComment((String) CryptoUtil.decryptValue(particulars.getCommentIv(), particulars.getEncryptedComment()));
		//				target.setYearOfBirth(CommonUtil.safeLongToInt(particulars.getYearOfBirth()));
		//				target.setAge(CommonUtil.getAge(target.getDateOfBirth()));
		//				target.setDecrypted(true);
		//			} catch (Exception e) {
		//				target.setPrefixedTitle1(null);
		//				target.setPrefixedTitle2(null);
		//				target.setPrefixedTitle3(null);
		//				target.setFirstName(null);
		//				target.setLastName(null);
		//				target.setPostpositionedTitle1(null);
		//				target.setPostpositionedTitle2(null);
		//				target.setPostpositionedTitle3(null);
		//				target.setDateOfBirth(null);
		//				target.setCitizenship(null);
		//				target.setComment(null);
		//				target.setYearOfBirth(CommonUtil.safeLongToInt(particulars.getYearOfBirth()));
		//				target.setAge(CommonUtil.getAge((new GregorianCalendar(target.getYearOfBirth(), GregorianCalendar.JULY, 1)).getTime()));
		//				target.setDecrypted(false);
		//			}
		//			target.setGender(L10nUtil.createSexVO(Locales.USER, particulars.getGender()));
		//			target.setName(getProbandName(target, false));
		//			target.setNameWithTitles(getProbandName(target, true));
		//			target.setInitials(getInitials(target));
		//			target.setHasImage(particulars.getFileSize() != null && particulars.getFileSize() > 0l);
		//		}
	}

	@Override
	public void toProbandOutVO(
			Proband source,
			ProbandOutVO target, Integer... maxInstances)
	{
		(new ProbandReflexionGraph(this, this.getProbandCategoryDao(), this.getDepartmentDao(), this.getStaffDao(), this.getPrivacyConsentStatusTypeDao(), this.getUserDao(),
				maxInstances)).toVOHelper(source, target, new HashMap<Class, HashMap<Long, Object>>());
	}

	private HashSet<Proband> toProbandSet(Collection<Long> probandIds) { // lazyload persistentset prevention
		HashSet<Proband> result = new HashSet<Proband>(probandIds.size());
		Iterator<Long> it = probandIds.iterator();
		while (it.hasNext()) {
			result.add(this.load(it.next()));
		}
		return result;
	}
}