package org.phoenixctms.ctsms.util;

import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.hibernate.LockMode;
import org.phoenixctms.ctsms.adapt.ProbandListStatusEntryCollisionFinder;
import org.phoenixctms.ctsms.compare.AlphanumStringComparator;
import org.phoenixctms.ctsms.compare.BankAccountOutVOComparator;
import org.phoenixctms.ctsms.compare.CvPositionPDFVOComparator;
import org.phoenixctms.ctsms.compare.MoneyTransferOutVOComparator;
import org.phoenixctms.ctsms.compare.VisitScheduleItemOutVOComparator;
import org.phoenixctms.ctsms.domain.*;
import org.phoenixctms.ctsms.enumeration.ECRFFieldStatusQueue;
import org.phoenixctms.ctsms.enumeration.InputFieldType;
import org.phoenixctms.ctsms.enumeration.JournalModule;
import org.phoenixctms.ctsms.enumeration.PaymentMethod;
import org.phoenixctms.ctsms.enumeration.PermissionProfile;
import org.phoenixctms.ctsms.enumeration.PermissionProfileGroup;
import org.phoenixctms.ctsms.enumeration.VariablePeriod;
import org.phoenixctms.ctsms.excel.ExcelExporter;
import org.phoenixctms.ctsms.excel.ExcelUtil;
import org.phoenixctms.ctsms.excel.ReimbursementsExcelDefaultSettings;
import org.phoenixctms.ctsms.excel.ReimbursementsExcelSettingCodes;
import org.phoenixctms.ctsms.excel.ReimbursementsExcelWriter;
import org.phoenixctms.ctsms.excel.VisitScheduleExcelDefaultSettings;
import org.phoenixctms.ctsms.excel.VisitScheduleExcelSettingCodes;
import org.phoenixctms.ctsms.excel.VisitScheduleExcelWriter;
import org.phoenixctms.ctsms.exception.AuthorisationException;
import org.phoenixctms.ctsms.exception.ServiceException;
import org.phoenixctms.ctsms.pdf.CVPDFPainter;
import org.phoenixctms.ctsms.pdf.CourseCertificatePDFDefaultSettings;
import org.phoenixctms.ctsms.pdf.CourseCertificatePDFPainter;
import org.phoenixctms.ctsms.pdf.CourseCertificatePDFSettingCodes;
import org.phoenixctms.ctsms.pdf.CourseParticipantListPDFPainter;
import org.phoenixctms.ctsms.pdf.ProbandLetterPDFPainter;
import org.phoenixctms.ctsms.security.CryptoUtil;
import org.phoenixctms.ctsms.util.L10nUtil.Locales;
import org.phoenixctms.ctsms.util.Settings.Bundle;
import org.phoenixctms.ctsms.util.date.BookingDuration;
import org.phoenixctms.ctsms.util.date.DateCalc;
import org.phoenixctms.ctsms.util.date.DateInterval;
import org.phoenixctms.ctsms.util.date.ShiftDuration;
import org.phoenixctms.ctsms.vo.AddressTypeVO;
import org.phoenixctms.ctsms.vo.AspSubstanceVO;
import org.phoenixctms.ctsms.vo.BankAccountOutVO;
import org.phoenixctms.ctsms.vo.CourseOutVO;
import org.phoenixctms.ctsms.vo.CourseParticipationStatusEntryInVO;
import org.phoenixctms.ctsms.vo.CourseParticipationStatusEntryOutVO;
import org.phoenixctms.ctsms.vo.CriteriaInstantVO;
import org.phoenixctms.ctsms.vo.CriterionInVO;
import org.phoenixctms.ctsms.vo.CriterionInstantVO;
import org.phoenixctms.ctsms.vo.CriterionOutVO;
import org.phoenixctms.ctsms.vo.CriterionPropertyVO;
import org.phoenixctms.ctsms.vo.CriterionRestrictionVO;
import org.phoenixctms.ctsms.vo.CriterionTieVO;
import org.phoenixctms.ctsms.vo.CvPositionPDFVO;
import org.phoenixctms.ctsms.vo.CvSectionVO;
import org.phoenixctms.ctsms.vo.DutyRosterTurnOutVO;
import org.phoenixctms.ctsms.vo.ECRFFieldOutVO;
import org.phoenixctms.ctsms.vo.ECRFFieldStatusEntryOutVO;
import org.phoenixctms.ctsms.vo.ECRFFieldStatusQueueCountVO;
import org.phoenixctms.ctsms.vo.ECRFFieldValueInVO;
import org.phoenixctms.ctsms.vo.ECRFFieldValueJsonVO;
import org.phoenixctms.ctsms.vo.ECRFFieldValueOutVO;
import org.phoenixctms.ctsms.vo.ECRFOutVO;
import org.phoenixctms.ctsms.vo.ECRFProgressVO;
import org.phoenixctms.ctsms.vo.ECRFSectionProgressVO;
import org.phoenixctms.ctsms.vo.InputFieldOutVO;
import org.phoenixctms.ctsms.vo.InputFieldSelectionSetValueOutVO;
import org.phoenixctms.ctsms.vo.InputFieldTypeVO;
import org.phoenixctms.ctsms.vo.InquiryOutVO;
import org.phoenixctms.ctsms.vo.InquiryValueInVO;
import org.phoenixctms.ctsms.vo.InquiryValueJsonVO;
import org.phoenixctms.ctsms.vo.InquiryValueOutVO;
import org.phoenixctms.ctsms.vo.InventoryBookingDurationSummaryDetailVO;
import org.phoenixctms.ctsms.vo.InventoryBookingDurationSummaryVO;
import org.phoenixctms.ctsms.vo.InventoryBookingOutVO;
import org.phoenixctms.ctsms.vo.InventoryOutVO;
import org.phoenixctms.ctsms.vo.LecturerCompetenceVO;
import org.phoenixctms.ctsms.vo.LecturerOutVO;
import org.phoenixctms.ctsms.vo.MoneyTransferByBankAccountSummaryDetailVO;
import org.phoenixctms.ctsms.vo.MoneyTransferByCostTypeSummaryDetailVO;
import org.phoenixctms.ctsms.vo.MoneyTransferByPaymentMethodSummaryDetailVO;
import org.phoenixctms.ctsms.vo.MoneyTransferOutVO;
import org.phoenixctms.ctsms.vo.MoneyTransferSummaryVO;
import org.phoenixctms.ctsms.vo.PasswordInVO;
import org.phoenixctms.ctsms.vo.PasswordOutVO;
import org.phoenixctms.ctsms.vo.PermissionProfileVO;
import org.phoenixctms.ctsms.vo.ProbandAddressOutVO;
import org.phoenixctms.ctsms.vo.ProbandListEntryOutVO;
import org.phoenixctms.ctsms.vo.ProbandListEntryTagOutVO;
import org.phoenixctms.ctsms.vo.ProbandListEntryTagValueInVO;
import org.phoenixctms.ctsms.vo.ProbandListEntryTagValueJsonVO;
import org.phoenixctms.ctsms.vo.ProbandListEntryTagValueOutVO;
import org.phoenixctms.ctsms.vo.ProbandListStatusEntryInVO;
import org.phoenixctms.ctsms.vo.ProbandListStatusEntryOutVO;
import org.phoenixctms.ctsms.vo.ProbandOutVO;
import org.phoenixctms.ctsms.vo.ReimbursementsExcelVO;
import org.phoenixctms.ctsms.vo.ShiftDurationSummaryDetailVO;
import org.phoenixctms.ctsms.vo.ShiftDurationSummaryVO;
import org.phoenixctms.ctsms.vo.StaffAddressOutVO;
import org.phoenixctms.ctsms.vo.StaffImageOutVO;
import org.phoenixctms.ctsms.vo.StaffOutVO;
import org.phoenixctms.ctsms.vo.TrialOutVO;
import org.phoenixctms.ctsms.vo.UserInVO;
import org.phoenixctms.ctsms.vo.UserOutVO;
import org.phoenixctms.ctsms.vo.VisitOutVO;
import org.phoenixctms.ctsms.vo.VisitScheduleExcelVO;
import org.phoenixctms.ctsms.vo.VisitScheduleItemOutVO;

public final class ServiceUtil {


	private final static String INPUT_FIELD_VALIDATION_ERROR_MESSAGE = "{0}: {1}";
	public final static Comparator<String> MONEY_TRANSFER_COST_TYPE_COMPARATOR = new AlphanumStringComparator(true);
	public final static String ECRF_FIELD_VALUE_DAO_ECRF_FIELD_ALIAS = "ecrfField0";
	public final static String ECRF_FIELD_VALUE_DAO_ECRF_FIELD_VALUE_ALIAS = "ecrfFieldValue0";
	public final static String INQUIRY_VALUE_DAO_INQUIRY_ALIAS = "inquiry0";
	public final static String INQUIRY_VALUE_DAO_INQUIRY_VALUE_ALIAS = "inquiryValue0";
	public final static String PROBAND_LIST_ENTRY_TAG_VALUE_DAO_PROBAND_LIST_ENTRY_TAG_ALIAS = "probandListEntryTag0";
	public final static String PROBAND_LIST_ENTRY_TAG_VALUE_DAO_PROBAND_LIST_ENTRY_TAG_VALUE_ALIAS = "tagValue0";


	public final static boolean LOG_ADD_UPDATE_ECRF_NO_DIFF = false;
	public final static boolean LOG_ADD_UPDATE_INPUT_FIELD_NO_DIFF = false;
	public final static boolean LOG_ECRF_FIELD_VALUE_PROBAND = false;


	public final static boolean LOG_ECRF_FIELD_VALUE_TRIAL = false;

	public final static boolean LOG_INQUIRY_VALUE_PROBAND = false;

	public final static boolean LOG_INQUIRY_VALUE_TRIAL = false;

	public final static boolean LOG_PROBAND_LIST_ENTRY_TAG_VALUE_PROBAND = false;

	public final static boolean LOG_PROBAND_LIST_ENTRY_TAG_VALUE_TRIAL = false;

	public final static boolean LOG_ECRF_FIELD_STATUS_ENTRY_TRIAL = false;
	public final static boolean LOG_ECRF_FIELD_STATUS_ENTRY_PROBAND = false;

	public static InputFieldSelectionSetValueOutVO addAutocompleteSelectionSetValue(InputField inputField, String textValue, Timestamp now, User user,
			InputFieldSelectionSetValueDao selectionSetValueDao, JournalEntryDao journalEntryDao) throws Exception {
		if (textValue != null && textValue.length() > 0 && inputField != null &&
				InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType()) && inputField.getLearn() &&
				selectionSetValueDao.getCount(inputField.getId(), textValue) == 0) {
			InputFieldSelectionSetValue selectionSetValue = InputFieldSelectionSetValue.Factory.newInstance();
			selectionSetValue.setField(inputField);
			inputField.addSelectionSetValues(selectionSetValue);
			selectionSetValue.setLocalized(false);
			selectionSetValue.setNameL10nKey(textValue);
			selectionSetValue.setPreset(false);
			selectionSetValue.setValue(textValue);
			CoreUtil.modifyVersion(selectionSetValue, now, user);
			selectionSetValue = selectionSetValueDao.create(selectionSetValue);
			InputFieldSelectionSetValueOutVO result = selectionSetValueDao.toInputFieldSelectionSetValueOutVO(selectionSetValue);
			logSystemMessage(selectionSetValue.getField(), result.getField(), now, user, SystemMessageCodes.SELECTION_SET_VALUE_CREATED, result, null, journalEntryDao);
			return result;
		}
		return null;
	}

	private static void addCostTypeDetailComment(MoneyTransfer mt,MoneyTransferByCostTypeSummaryDetailVO byCostTypeDetail) {

		if (mt.isShowComment()) {
			String comment;
			try {
				if (!CoreUtil.isPassDecryption()) {
					throw new Exception();
				}
				comment = (String) CryptoUtil.decryptValue(mt.getCommentIv(), mt.getEncryptedComment());
			} catch (Exception e) {
				comment = null;
				byCostTypeDetail.setDecrypted(false);
			}
			if (!CommonUtil.isEmptyString(comment)) {
				byCostTypeDetail.getComments().add(comment);
			}
		}
		//		if () {
		//			if (!CommonUtil.isEmptyString(mt.getReference())) {
		//				mt.getReferences().add(mt.getReference());
		//			}
		//		}
		//		if () {
		//			if (!CommonUtil.isEmptyString(mt.getVoucherCode())) {
		//				mt.getVoucherCodes().add(mt.getVoucherCode());
		//			}
		//		}

	}

	public static ArrayList<ECRFFieldStatusQueueCountVO> addEcrfFieldStatusEntryCounts(Collection<ECRFFieldStatusQueueCountVO> a, Collection<ECRFFieldStatusQueueCountVO> b) {

		ECRFFieldStatusQueue[] queues = ECRFFieldStatusQueue.values();
		HashMap<ECRFFieldStatusQueue,Long[]> aMap = new HashMap<ECRFFieldStatusQueue, Long[]>(queues.length);
		HashMap<ECRFFieldStatusQueue,Long[]> bMap = new HashMap<ECRFFieldStatusQueue, Long[]>(queues.length);
		ArrayList<ECRFFieldStatusQueueCountVO> result = new ArrayList<ECRFFieldStatusQueueCountVO>(queues.length);
		if (a != null) {
			Iterator<ECRFFieldStatusQueueCountVO> it = a.iterator();
			while (it.hasNext()) {
				ECRFFieldStatusQueueCountVO count = it.next();
				aMap.put(count.getQueue(), new Long[] { count.getTotal(), count.getInitial(), count.getUpdated(), count.getProposed(), count.getResolved(), count.getUnresolved() });
			}
		}
		if (b != null) {
			Iterator<ECRFFieldStatusQueueCountVO> it = b.iterator();
			while (it.hasNext()) {
				ECRFFieldStatusQueueCountVO count = it.next();
				bMap.put(count.getQueue(), new Long[] { count.getTotal(), count.getInitial(), count.getUpdated(), count.getProposed(), count.getResolved(), count.getUnresolved() });
			}
		}
		for (int i = 0; i < queues.length; i++) {
			if (!aMap.containsKey(queues[i])) {
				aMap.put(queues[i], new Long[] { 0l, 0l, 0l, 0l, 0l, 0l });
			}
			if (!bMap.containsKey(queues[i])) {
				bMap.put(queues[i], new Long[] { 0l, 0l, 0l, 0l, 0l, 0l });
			}
			ECRFFieldStatusQueueCountVO count = new ECRFFieldStatusQueueCountVO();
			count.setQueue(queues[i]);
			count.setTotal(aMap.get(queues[i])[0] + bMap.get(queues[i])[0]);
			count.setInitial(aMap.get(queues[i])[1] + bMap.get(queues[i])[1]);
			count.setUpdated(aMap.get(queues[i])[2] + bMap.get(queues[i])[2]);
			count.setProposed(aMap.get(queues[i])[3] + bMap.get(queues[i])[3]);
			count.setResolved(aMap.get(queues[i])[4] + bMap.get(queues[i])[4]);
			count.setUnresolved(aMap.get(queues[i])[5] + bMap.get(queues[i])[5]);
			result.add(count);
		}
		return result;

	}

	public static ProbandListStatusEntryOutVO addProbandListStatusEntry(ProbandListEntry listEntry, Boolean signup, String reasonL10nKey, Object[] args, Timestamp realTimestamp,
			Long probandListStatusTypeId, ECRF ecrf, ECRFStatusType newState,
			Timestamp now, User user,
			ProbandDao probandDao, ProbandListEntryDao probandListEntryDao, ProbandListStatusEntryDao probandListStatusEntryDao, ProbandListStatusTypeDao probandListStatusTypeDao,
			JournalEntryDao journalEntryDao) throws Exception {
		if (L10nUtil.containsProbandListStatusReason(Locales.PROBAND_LIST_STATUS_ENTRY_REASON, reasonL10nKey)) {
			ProbandListStatusType statusType = null;
			if (probandListStatusTypeId != null) {
				statusType = CheckIDUtil.checkProbandListStatusTypeId(probandListStatusTypeId, probandListStatusTypeDao);
			} else {
				if (ecrf != null && newState != null && newState.isApplyEcrfProbandListStatus() && ecrf.getProbandListStatus() != null) {
					statusType = ecrf.getProbandListStatus();
				} else if (listEntry.getLastStatus() != null) {
					statusType = listEntry.getLastStatus().getStatus();
				}
			}
			if (statusType != null) {
				String reason = L10nUtil.getProbandListStatusReason(Locales.PROBAND_LIST_STATUS_ENTRY_REASON,
						reasonL10nKey, DefaultProbandListStatusReasons.DEFAULT_REASON, args);
				if (!statusType.isReasonRequired() || !CommonUtil.isEmptyString(reason)) {
					ProbandListStatusEntryInVO newProbandListStatusEntry = new ProbandListStatusEntryInVO();
					newProbandListStatusEntry.setListEntryId(listEntry.getId());
					newProbandListStatusEntry.setRealTimestamp(realTimestamp);
					newProbandListStatusEntry.setReason(reason);
					newProbandListStatusEntry.setStatusId(statusType.getId());
					return addProbandListStatusEntry(newProbandListStatusEntry, signup, now, user, false, false, probandDao, probandListEntryDao, probandListStatusEntryDao,
							probandListStatusTypeDao,
							journalEntryDao);
				}
			} else {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.PROBAND_LIST_STATUS_TYPE_REQUIRED);
			}
		}
		return null;
	}

	public static ProbandListStatusEntryOutVO addProbandListStatusEntry(ProbandListEntry listEntry, Boolean signup, String reasonL10nKey, Object[] args, Timestamp realTimestamp,
			Long probandListStatusTypeId,
			Timestamp now, User user,
			ProbandDao probandDao, ProbandListEntryDao probandListEntryDao, ProbandListStatusEntryDao probandListStatusEntryDao, ProbandListStatusTypeDao probandListStatusTypeDao,
			JournalEntryDao journalEntryDao) throws Exception {
		return addProbandListStatusEntry(listEntry, signup, reasonL10nKey, args, now, probandListStatusTypeId, null, null, now, user, probandDao, probandListEntryDao,
				probandListStatusEntryDao, probandListStatusTypeDao, journalEntryDao);
	}





	public static ProbandListStatusEntryOutVO addProbandListStatusEntry(ProbandListStatusEntryInVO newProbandListStatusEntry, Boolean signup, Timestamp now, User user,
			boolean logTrial,
			boolean logProband,
			ProbandDao probandDao, ProbandListEntryDao probandListEntryDao, ProbandListStatusEntryDao probandListStatusEntryDao, ProbandListStatusTypeDao probandListStatusTypeDao,
			JournalEntryDao journalEntryDao) throws Exception {
		checkAddProbandListStatusEntryInput(newProbandListStatusEntry, signup, probandDao, probandListEntryDao, probandListStatusEntryDao, probandListStatusTypeDao);
		// ProbandListStatusEntryDao probandListStatusEntryDao = this.getProbandListStatusEntryDao();
		ProbandListStatusEntry probandListStatusEntry = probandListStatusEntryDao.probandListStatusEntryInVOToEntity(newProbandListStatusEntry);
		CoreUtil.modifyVersion(probandListStatusEntry, now, user);
		probandListStatusEntry = probandListStatusEntryDao.create(probandListStatusEntry);
		ProbandListEntry listEntry = probandListStatusEntry.getListEntry();
		listEntry.setLastStatus(probandListStatusEntry);
		probandListEntryDao.update(listEntry);
		// /JournalEntryDao journalEntryDao = this.getJournalEntryDao();
		ProbandListStatusEntryOutVO result = probandListStatusEntryDao.toProbandListStatusEntryOutVO(probandListStatusEntry);
		if (logProband) {
			logSystemMessage(probandListStatusEntry.getListEntry().getProband(), result.getListEntry().getTrial(), now, user, SystemMessageCodes.PROBAND_LIST_STATUS_ENTRY_CREATED,
					result, null, journalEntryDao);
		}
		if (logTrial) {
			// logSystemMessage(probandListStatusEntry.getListEntry().getTrial(), result.getListEntry().getTrial(), now, user,
			// SystemMessageCodes.PROBAND_LIST_STATUS_ENTRY_CREATED, result, null, journalEntryDao);
			logSystemMessage(probandListStatusEntry.getListEntry().getTrial(), result.getListEntry().getProband(), now, user,
					SystemMessageCodes.PROBAND_LIST_STATUS_ENTRY_CREATED, result, null, journalEntryDao);
		}
		return result;
	}

	private static void appendCvStaffPath(StringBuilder staffPath, StaffOutVO staff, boolean first) {
		if (staff != null) {
			if (first || !staff.isPerson()) {
				if (staffPath.length() > 0) {
					staffPath.append(", ");
				}
				staffPath.append(CommonUtil.getCvStaffName(staff));
			}
			appendCvStaffPath(staffPath, staff.getParent(), false);
		}
	}

	public static void appendDistinctProbandAddressColumnValues(Collection addresses,
			HashMap<String, Object> fieldRow,
			boolean aggregateAddresses,
			String streetsColumnName,
			String zipCodesColumnName,
			String cityNamesColumnName) {
		Iterator<ProbandAddressOutVO> addressesIt = addresses.iterator();
		String fieldKey;
		while (addressesIt.hasNext()) {
			ProbandAddressOutVO addressOutVO = addressesIt.next();
			StringBuilder fieldValue;
			if (aggregateAddresses) {
				fieldKey = streetsColumnName;
				if (fieldRow.containsKey(fieldKey)) {
					fieldValue = new StringBuilder((String) fieldRow.get(fieldKey));
				} else {
					fieldValue = new StringBuilder();
				}
				if (fieldValue.length() > 0) {
					fieldValue.append(ExcelUtil.EXCEL_LINE_BREAK);
				}
				fieldValue
				.append(CommonUtil.getStreetString(addressOutVO.getStreetName(), addressOutVO.getHouseNumber(), addressOutVO.getEntrance(), addressOutVO.getDoorNumber()));
				fieldRow.put(fieldKey, fieldValue.toString());
				fieldKey = zipCodesColumnName;
				if (fieldRow.containsKey(fieldKey)) {
					fieldValue = new StringBuilder((String) fieldRow.get(fieldKey));
				} else {
					fieldValue = new StringBuilder();
				}
				if (fieldValue.length() > 0) {
					fieldValue.append(ExcelUtil.EXCEL_LINE_BREAK);
				}
				fieldValue.append(addressOutVO.getZipCode());
				fieldRow.put(fieldKey, fieldValue.toString());
				fieldKey = cityNamesColumnName;
				if (fieldRow.containsKey(fieldKey)) {
					fieldValue = new StringBuilder((String) fieldRow.get(fieldKey));
				} else {
					fieldValue = new StringBuilder();
				}
				if (fieldValue.length() > 0) {
					fieldValue.append(ExcelUtil.EXCEL_LINE_BREAK);
				}
				fieldValue.append(addressOutVO.getCityName());
				fieldRow.put(fieldKey, fieldValue.toString());
			} else {
				fieldKey = addressOutVO.getType().getName(); // aggregateAddresses ? ProbandListExcelWriter.getAddressesColumnName() : addressOutVO.getType().getName();
				if (fieldRow.containsKey(fieldKey)) {
					fieldValue = new StringBuilder((String) fieldRow.get(fieldKey));
				} else {
					fieldValue = new StringBuilder();
				}
				if (fieldValue.length() > 0) {
					fieldValue.append(ExcelUtil.EXCEL_LINE_BREAK);
				}
				fieldValue.append(addressOutVO.getName());
				fieldRow.put(fieldKey, fieldValue.toString());
			}
		}
	}

	public static void applyLogonLimitations(PasswordInVO password) {
		password.setExpires(Settings.getBoolean(SettingCodes.LOGON_EXPIRES, Settings.Bundle.SETTINGS, false));
		password.setValidityPeriod(password.isExpires() ? Settings.getVariablePeriod(SettingCodes.LOGON_VALIDITY_PERIOD, Settings.Bundle.SETTINGS, VariablePeriod.EXPLICIT) : null);
		password.setValidityPeriodDays(VariablePeriod.EXPLICIT.equals(password.getValidityPeriod()) ? Settings.getLongNullable(SettingCodes.LOGON_VALIDITY_PERIOD_DAYS,
				Settings.Bundle.SETTINGS, null) : null);
		password.setLimitLogons(Settings.getBoolean(SettingCodes.LOGON_LIMIT_LOGONS, Settings.Bundle.SETTINGS, false));
		password.setMaxSuccessfulLogons(password.isLimitLogons() ? Settings.getLongNullable(SettingCodes.LOGON_MAX_SUCCESSFUL_LOGONS, Settings.Bundle.SETTINGS, null) : null);
		password.setLimitWrongPasswordAttempts(Settings.getBoolean(SettingCodes.LOGON_LIMIT_WRONG_PASSWORD_ATTEMPTS, Settings.Bundle.SETTINGS, false));
		password.setMaxWrongPasswordAttemptsSinceLastSuccessfulLogon(password.isLimitWrongPasswordAttempts() ? Settings.getLongNullable(
				SettingCodes.LOGON_MAX_WRONG_PASSWORD_ATTEMPTS_SINCE_LAST_SUCCESSFUL_LOGON, Settings.Bundle.SETTINGS, null) : null);
	}

	public static void applyOneTimeLogonLimitation(PasswordInVO password) {
		password.setLimitLogons(true);
		password.setMaxSuccessfulLogons(1L);
	}

	public static String aspSubstanceIDsToString(Collection<Long> aspSubstanceIds, AspSubstanceDao aspSubstanceDao) {
		Collection<AspSubstanceVO> result = new ArrayList<AspSubstanceVO>(aspSubstanceIds.size());
		Iterator<Long> it = aspSubstanceIds.iterator();
		while (it.hasNext()) {
			result.add(aspSubstanceDao.toAspSubstanceVO(aspSubstanceDao.load(it.next())));
		}
		return CommonUtil.aspSubstanceVOCollectionToString(result);
	}

	public static void cancelNotifications(Collection<Notification> notifications, NotificationDao notificationDao,
			org.phoenixctms.ctsms.enumeration.NotificationType notificationType)
					throws Exception {
		Iterator<Notification> notificationsIt = notifications.iterator();
		while (notificationsIt.hasNext()) {
			Notification notification = notificationsIt.next();
			if (!notification.isObsolete() && (notificationType == null || notificationType.equals(notification.getType().getType()))) {
				notification.setObsolete(true);
				notificationDao.update(notification);
			}
		}
	}

	public static void checkAddCourseParticipationStatusEntryInput(CourseParticipationStatusEntryInVO courseParticipationIn, boolean admin, Boolean selfRegistration,
			StaffDao staffDao, CourseDao courseDao, CvSectionDao cvSectionDao, CourseParticipationStatusTypeDao courseParticipationStatusTypeDao,
			CourseParticipationStatusEntryDao courseParticipationStatusEntryDao) throws ServiceException
			{
		// referential checks
		Staff staff = CheckIDUtil.checkStaffId(courseParticipationIn.getStaffId(), staffDao);
		Course course = CheckIDUtil.checkCourseId(courseParticipationIn.getCourseId(), courseDao, LockMode.PESSIMISTIC_WRITE);
		if (courseParticipationIn.getSectionId() != null) {
			CheckIDUtil.checkCvSectionId(courseParticipationIn.getSectionId(), cvSectionDao);
		}
		CourseParticipationStatusType state = CheckIDUtil.checkCourseParticipationStatusTypeId(courseParticipationIn.getStatusId(), courseParticipationStatusTypeDao);
		// other input checks
		if (!staff.isPerson()) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_STAFF_NOT_PERSON);
		}
		if (selfRegistration != null && selfRegistration.booleanValue() != course.isSelfRegistration()) {
			throw L10nUtil.initServiceException(selfRegistration ? ServiceExceptionCodes.COURSE_PARTICIPATION_COURSE_SELF_REGISTRATION
					: ServiceExceptionCodes.COURSE_PARTICIPATION_COURSE_ADMIN_REGISTRATION);
		}
		if (courseParticipationIn.getShowCv() && !course.isShowCvPreset()) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_SHOW_CV_PRESET_DISABLED);
		}
		if (courseParticipationIn.getShowCv() && courseParticipationIn.getSectionId() == null) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_CV_SECTION_REQUIRED);
		}
		if (!courseParticipationIn.getShowCv() && courseParticipationIn.getShowCommentCv()) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_SHOW_CV_DISABLED);
		}
		if (courseParticipationStatusEntryDao.getStaffCourseStatusCount(courseParticipationIn.getStaffId(), courseParticipationIn.getCourseId(), null) > 0) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_ALREADY_PARTICIPATING, CommonUtil.staffOutVOToString(staffDao.toStaffOutVO(staff)));
		}
		if (course.isSelfRegistration() && !admin) {
			if (course.getMaxNumberOfParticipants() != null
					&& courseParticipationStatusEntryDao.getStaffCourseStatusCount(null, courseParticipationIn.getCourseId(), null) >= course.getMaxNumberOfParticipants()) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_MAX_NUMBER_OF_PARTICIPANTS_EXCEEDED, course.getMaxNumberOfParticipants());
			}
			if (course.getParticipationDeadline() != null && course.getParticipationDeadline().compareTo(CommonUtil.dateToTimestamp(new Date())) < 0) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_DEADLINE_EXCEEDED); // ,(new
				// SimpleDateFormat()).format(course.getParticipationDeadline()));
			}
		}
		boolean validState = false;
		Iterator<CourseParticipationStatusType> statesIt = courseParticipationStatusTypeDao.findInitialStates(admin, course.isSelfRegistration()).iterator();
		while (statesIt.hasNext()) {
			if (state.equals(statesIt.next())) {
				validState = true;
				break;
			}
		}
		if (!validState) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_INVALID_INITIAL_PARTICIPATION_STATUS_TYPE,
					L10nUtil.getCourseParticipationStatusTypeName(Locales.USER, state.getNameL10nKey()));
		}
			}

	private static void checkAddProbandListStatusEntryInput(ProbandListStatusEntryInVO probandListStatusEntryIn, Boolean signup,
			ProbandDao probandDao, ProbandListEntryDao probandListEntryDao, ProbandListStatusEntryDao probandListStatusEntryDao, ProbandListStatusTypeDao probandListStatusTypeDao
			) throws ServiceException
			{
		// referential checks
		// ProbandListEntryDao probandListEntryDao = this.getProbandListEntryDao();
		ProbandListEntry probandListEntry = CheckIDUtil.checkProbandListEntryId(probandListStatusEntryIn.getListEntryId(), probandListEntryDao);
		ProbandListStatusEntry lastStatus = probandListEntry.getLastStatus();
		// ProbandListStatusTypeDao probandListStatusTypeDao = this.getProbandListStatusTypeDao();
		ProbandListStatusType state = CheckIDUtil.checkProbandListStatusTypeId(probandListStatusEntryIn.getStatusId(), probandListStatusTypeDao);
		checkTrialLocked(probandListEntry.getTrial());
		checkProbandLocked(probandListEntry.getProband());
		boolean validState = false;
		if (lastStatus == null) {
			Iterator<ProbandListStatusType> statesIt = probandListStatusTypeDao.findInitialStates(signup, probandListEntry.getProband().isPerson()).iterator();
			while (statesIt.hasNext()) {
				if (state.equals(statesIt.next())) {
					validState = true;
					break;
				}
			}
			if (!validState) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.INVALID_INITIAL_PROBAND_LIST_STATUS_TYPE,
						L10nUtil.getProbandListStatusTypeName(Locales.USER, state.getNameL10nKey()));
			}
		} else {
			ProbandListStatusType lastState = lastStatus.getStatus();
			Iterator<ProbandListStatusType> statesIt = probandListStatusTypeDao.findTransitions(lastState.getId()).iterator();
			while (statesIt.hasNext()) {
				if (state.equals(statesIt.next())) {
					validState = true;
					break;
				}
			}
			if (!validState) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.INVALID_NEW_PROBAND_LIST_STATUS_TYPE,
						L10nUtil.getProbandListStatusTypeName(Locales.USER, state.getNameL10nKey()));
			}
			if (probandListStatusEntryIn.getRealTimestamp().compareTo(lastStatus.getRealTimestamp()) < 0) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.PROBAND_LIST_STATUS_REAL_DATE_LESS_THAN_LAST_DATE);
			}
		}
		if (signup != null && state.isSignup() && !probandListEntry.getTrial().isSignupProbandList()) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.TRIAL_SIGNUP_DISABLED);
		}
		String reason = probandListStatusEntryIn.getReason();
		if (CommonUtil.isEmptyString(reason) && state.isReasonRequired()) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.PROBAND_LIST_STATUS_ENTRY_REASON_REQUIRED);
		}
		if ((new ProbandListStatusEntryCollisionFinder(probandDao, probandListEntryDao, probandListStatusEntryDao)).collides(probandListStatusEntryIn)) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.PROBAND_LIST_ENTRY_PROBAND_BLOCKED, probandListEntry.getProband().getId().toString());
			// xCommonUtil.probandOutVOToString(probandDao.toProbandOutVO(probandListEntry.getProband())));
		}
			}

	public static void checkInputFieldBooleanValue(InputField inputField, boolean optional, boolean booleanValue, InputFieldDao inputFieldDao) throws ServiceException {
		if (inputField != null) {
			InputFieldType fieldType = inputField.getFieldType();
			if (fieldType != null) {
				if (InputFieldType.CHECKBOX.equals(fieldType)) {
				} else if (booleanValue == true) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_BOOLEAN_VALUE_NOT_FALSE,
							CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
				}
			}
		}
	}

	public static void checkInputFieldDateValue(InputField inputField, boolean optional, Date dateValue, InputFieldDao inputFieldDao) throws ServiceException {
		if (inputField != null) {
			InputFieldType fieldType = inputField.getFieldType();
			if (fieldType != null) {
				if (InputFieldType.DATE.equals(fieldType)) {
					if (!optional && dateValue == null) {
						throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_VALUE_REQUIRED,
								CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
					}
					if (dateValue != null) {
						Date minDate = inputField.getMinDate();
						if (minDate != null && DateCalc.getStartOfDay(minDate).compareTo(DateCalc.getStartOfDay(dateValue)) > 0) {
							throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
						}
						Date maxDate = inputField.getMaxDate();
						if (maxDate != null && DateCalc.getStartOfDay(maxDate).compareTo(DateCalc.getStartOfDay(dateValue)) < 0) {
							throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
						}
					}
				} else if (dateValue != null) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_DATE_VALUE_NOT_NULL,
							CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
				}
			}
		}
	}

	public static void checkInputFieldFloatValue(InputField inputField, boolean optional, Float floatValue, InputFieldDao inputFieldDao) throws ServiceException {
		if (inputField != null) {
			InputFieldType fieldType = inputField.getFieldType();
			if (fieldType != null) {
				if (InputFieldType.FLOAT.equals(fieldType)) {
					if (!optional && floatValue == null) {
						throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_VALUE_REQUIRED,
								CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
					}
					if (floatValue != null) {
						Float lowerLimit = inputField.getFloatLowerLimit();
						if (lowerLimit != null && lowerLimit.compareTo(floatValue) > 0) {
							throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
						}
						Float upperLimit = inputField.getFloatUpperLimit();
						if (upperLimit != null && upperLimit.compareTo(floatValue) < 0) {
							throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
						}
					}
				} else if (floatValue != null) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_FLOAT_VALUE_NOT_NULL,
							CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
				}
			}
		}
	}

	public static void checkInputFieldInkValue(InputField inputField, boolean optional, byte[] inkValue, InputFieldDao inputFieldDao) throws ServiceException {
		if (inputField != null) {
			InputFieldType fieldType = inputField.getFieldType();
			if (fieldType != null) {
				if (InputFieldType.SKETCH.equals(fieldType)) {
					if (!optional && (inkValue == null || inkValue.length == 0)) {
						throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_VALUE_REQUIRED,
								CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
					}
				} else if (inkValue != null) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_INK_VALUE_NOT_NULL,
							CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
				}
			}
		}
	}

	public static void checkInputFieldLongValue(InputField inputField, boolean optional, Long longValue, InputFieldDao inputFieldDao) throws ServiceException {
		if (inputField != null) {
			InputFieldType fieldType = inputField.getFieldType();
			if (fieldType != null) {
				if (InputFieldType.INTEGER.equals(fieldType)) {
					if (!optional && longValue == null) {
						throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_VALUE_REQUIRED,
								CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
					}
					if (longValue != null) {
						Long lowerLimit = inputField.getLongLowerLimit();
						if (lowerLimit != null && lowerLimit.compareTo(longValue) > 0) {
							throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
						}
						Long upperLimit = inputField.getLongUpperLimit();
						if (upperLimit != null && upperLimit.compareTo(longValue) < 0) {
							throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
						}
					}
				} else if (longValue != null) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_LONG_VALUE_NOT_NULL,
							CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
				}
			}
		}
	}


	public static void checkInputFieldSelectionSetValues(InputField inputField, boolean optional, Collection<Long> selectionSetValueIds,
			InputFieldDao inputFieldDao, InputFieldSelectionSetValueDao selectionSetValueDao) throws ServiceException {
		if (inputField != null) {
			InputFieldType fieldType = inputField.getFieldType();
			if (fieldType != null) {
				if (isLoadSelectionSet(fieldType)) {
					// if (InputFieldType.SELECT_ONE.equals(fieldType) || InputFieldType.SELECT_MANY.equals(fieldType) || InputFieldType.SKETCH.equals(fieldType)) {
					if (!optional && (selectionSetValueIds == null || selectionSetValueIds.size() == 0)) {
						// if (!InputFieldType.SKETCH.equals(fieldType) || inputField.getSelectionSetValues().size() > 0) {
						if (!InputFieldType.SKETCH.equals(fieldType) || selectionSetValueDao.getCount(inputField.getId()) > 0) {
							throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_SELECTION_REQUIRED,
									CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
						}
					}
					if (selectionSetValueIds != null && selectionSetValueIds.size() > 0) {
						if (InputFieldType.SELECT_ONE_DROPDOWN.equals(fieldType) || InputFieldType.SELECT_ONE_RADIO_H.equals(fieldType)
								|| InputFieldType.SELECT_ONE_RADIO_V.equals(fieldType)) {
							if (selectionSetValueIds.size() != 1) {
								throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_SINGLE_SELECTION_REQUIRED,
										CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
							}
						} else {
							Integer minSelections = inputField.getMinSelections();
							if (minSelections != null && minSelections.compareTo(selectionSetValueIds.size()) > 0) {
								throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
							}
							Integer maxSelections = inputField.getMaxSelections();
							if (maxSelections != null && maxSelections.compareTo(selectionSetValueIds.size()) < 0) {
								throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
							}
						}
						Iterator<Long> it = selectionSetValueIds.iterator();
						HashSet<Long> dupeCheck = new HashSet<Long>(selectionSetValueIds.size());
						while (it.hasNext()) {
							Long id = it.next();
							if (id == null) {
								throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_SELECTION_SET_VALUE_ID_IS_NULL,
										CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
							}
							InputFieldSelectionSetValue selectionSetValue = CheckIDUtil.checkInputFieldSelectionSetValueId(id, selectionSetValueDao);
							if (!dupeCheck.add(selectionSetValue.getId())) {
								InputFieldSelectionSetValueOutVO selectionSetValueVO = selectionSetValueDao.toInputFieldSelectionSetValueOutVO(selectionSetValue);
								throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_DUPLICATE_SELECTION,
										CommonUtil.inputFieldOutVOToString(selectionSetValueVO.getField()), selectionSetValueVO.getName());
							}
						}
					}
				} else if (selectionSetValueIds != null && selectionSetValueIds.size() > 0) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_SELECTION_NOT_EMTPY,
							CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
				}
			}
		}
	}

	public static void checkInputFieldTextValue(InputField inputField, boolean optional, String textValue, InputFieldDao inputFieldDao,
			InputFieldSelectionSetValueDao selectionSetValueDao)
					throws ServiceException {
		if (inputField != null) {
			InputFieldType fieldType = inputField.getFieldType();
			if (fieldType != null) {
				if (InputFieldType.SINGLE_LINE_TEXT.equals(fieldType) || InputFieldType.MULTI_LINE_TEXT.equals(fieldType)) {
					if (!optional && CommonUtil.isEmptyString(textValue)) {
						throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_VALUE_REQUIRED,
								CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
					}
					if (textValue != null && textValue.length() > 0) {
						String regExp = inputField.getRegExp();
						if (regExp != null && regExp.length() > 0) {
							java.util.regex.Pattern valuePattern = null;
							try {
								valuePattern = Pattern.compile(regExp);
							} catch (PatternSyntaxException e) {
								throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_INVALID_REGEXP_PATTERN,
										CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)), e.getMessage());
							}
							if (valuePattern != null && !valuePattern.matcher(textValue).find()) {
								throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
							}
						}
					}
				} else if (InputFieldType.AUTOCOMPLETE.equals(fieldType)) {
					if (!optional && CommonUtil.isEmptyString(textValue)) {
						throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_VALUE_REQUIRED,
								CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
					}
					if (textValue != null && textValue.length() > 0) {
						if (inputField.getStrict() && !inputField.getLearn() && selectionSetValueDao.getCount(inputField.getId(), textValue) == 0) {
							throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_TEXT_VALUE_NOT_FOUND,
									CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
						}
					}
				} else if (textValue != null) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_TEXT_VALUE_NOT_NULL,
							CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
				}
			}
		}
	}

	public static void checkInputFieldTimestampValue(InputField inputField, boolean optional, Date timestampValue, InputFieldDao inputFieldDao) throws ServiceException {
		if (inputField != null) {
			InputFieldType fieldType = inputField.getFieldType();
			if (fieldType != null) {
				if (InputFieldType.TIMESTAMP.equals(fieldType)) {
					if (!optional && timestampValue == null) {
						throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_VALUE_REQUIRED,
								CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
					}
					if (timestampValue != null) {
						Date minTimestamp = inputField.getMinTimestamp();
						if (minTimestamp != null && minTimestamp.compareTo(timestampValue) > 0) {
							throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
						}
						Date maxTimestamp = inputField.getMaxTimestamp();
						if (maxTimestamp != null && maxTimestamp.compareTo(timestampValue) < 0) {
							throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
						}
					}
				} else if (timestampValue != null) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_TIMESTAMP_VALUE_NOT_NULL,
							CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
				}
			}
		}
	}

	public static void checkInputFieldTimeValue(InputField inputField, boolean optional, Date timeValue, InputFieldDao inputFieldDao) throws ServiceException {
		if (inputField != null) {
			InputFieldType fieldType = inputField.getFieldType();
			if (fieldType != null) {
				if (InputFieldType.TIME.equals(fieldType)) {
					if (!optional && timeValue == null) {
						throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_VALUE_REQUIRED,
								CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
					}
					if (timeValue != null) {
						Date minTime = inputField.getMinTime();
						if (minTime != null && minTime.compareTo(timeValue) > 0) {
							throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
						}
						Date maxTime = inputField.getMaxTime();
						if (maxTime != null && maxTime.compareTo(timeValue) < 0) {
							throw L10nUtil.initServiceException(getValidationErrorMsg(inputFieldDao.toInputFieldOutVO(inputField)));
						}
					}
				} else if (timeValue != null) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.INPUT_FIELD_TIME_VALUE_NOT_NULL,
							CommonUtil.inputFieldOutVOToString(inputFieldDao.toInputFieldOutVO(inputField)));
				}
			}
		}
	}

	public static void checkLocale(String locale) throws ServiceException {
		if (!CoreUtil.checkSupportedLocale(locale)) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.INVALID_LOCALE);
		}
	}

	public static void checkLockedEcrfs(ECRF ecrf, ECRFStatusEntryDao ecrfStatusEntryDao, ECRFDao ecrfDao) throws ServiceException {
		long valuesLockedEcrfCount = ecrfStatusEntryDao.getCount(null, ecrf.getId(), null, true, null, null, null); // row lock order
		if (valuesLockedEcrfCount > 0) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.LOCKED_ECRFS, ecrfDao.toECRFOutVO(ecrf).getUniqueName(), valuesLockedEcrfCount);
		}
	}

	public static void checkLogonLimitations(PasswordInVO password) throws ServiceException {
		if (password.isExpires()) {
			if (password.getValidityPeriod() == null) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.PASSWORD_VALIDITY_PERIOD_REQUIRED);
			} else if (VariablePeriod.EXPLICIT.equals(password.getValidityPeriod())) {
				if (password.getValidityPeriodDays() == null) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.PASSWORD_VALIDITY_PERIOD_EXPLICIT_DAYS_REQUIRED);
				} else if (password.getValidityPeriodDays() < 1) {
					throw L10nUtil.initServiceException(ServiceExceptionCodes.PASSWORD_VALIDITY_PERIOD_EXPLICIT_DAYS_LESS_THAN_ONE);
				}
			}
		}
		if (password.isLimitLogons()) {
			if (password.getMaxSuccessfulLogons() == null) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.PASSWORD_NUMBER_OF_MAX_SUCCESSFUL_LOGONS_REQUIRED);
			} else if (password.getMaxSuccessfulLogons() < 1) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.PASSWORD_NUMBER_OF_MAX_SUCCESSFUL_LOGONS_LESS_THAN_ONE);
			}
		}
		if (password.isLimitWrongPasswordAttempts()) {
			if (password.getMaxWrongPasswordAttemptsSinceLastSuccessfulLogon() == null) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.PASSWORD_NUMBER_OF_MAX_WRONG_PASSWORD_ATTEMPTS_REQUIRED);
			} else if (password.getMaxWrongPasswordAttemptsSinceLastSuccessfulLogon() < 1) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.PASSWORD_NUMBER_OF_MAX_WRONG_PASSWORD_ATTEMPTS_LESS_THAN_ONE);
			}
		}
	}

	public static void checkProbandLocked(Proband proband) throws ServiceException { // , ProbandDao probandDao
		if (proband != null && proband.getCategory().isLocked()) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.PROBAND_LOCKED, Long.toString(proband.getId()),
					L10nUtil.getProbandCategoryName(Locales.USER, proband.getCategory().getNameL10nKey()));
		}
	}

	public static void checkReminderPeriod(VariablePeriod reminderPeriod, Long reminderPeriodDays) throws ServiceException {
		if (VariablePeriod.EXPLICIT.equals(reminderPeriod)) {
			if (reminderPeriodDays == null) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.REMINDER_PERIOD_EXPLICIT_DAYS_REQUIRED);
			} else if (reminderPeriodDays < 1) {
				throw L10nUtil.initServiceException(ServiceExceptionCodes.REMINDER_PERIOD_EXPLICIT_DAYS_LESS_THAN_ONE);
			}
		}
	}

	public static void checkTimeZone(String timeZone) throws ServiceException {
		if (!CoreUtil.checkTimeZone(timeZone)) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.INVALID_TIME_ZONE);
		}
	}

	public static void checkTrialLocked(Trial trial) throws ServiceException { // , TrialDao trialDao)
		if (trial != null && trial.getStatus().isLockdown()) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.TRIAL_LOCKED, Long.toString(trial.getId()),
					L10nUtil.getTrialStatusTypeName(Locales.USER, trial.getStatus().getNameL10nKey()));
		}
	}

	public static void checkUpdateCourseParticipationStatusEntryInput(CourseParticipationStatusEntry originalCourseParticipation,
			CourseParticipationStatusEntryInVO courseParticipationIn, boolean admin,
			CvSectionDao cvSectionDao, CourseParticipationStatusTypeDao courseParticipationStatusTypeDao,
			CourseParticipationStatusEntryDao courseParticipationStatusEntryDao) throws ServiceException
			{
		// referential checks
		if (courseParticipationIn.getSectionId() != null) {
			CheckIDUtil.checkCvSectionId(courseParticipationIn.getSectionId(), cvSectionDao);
		}
		CourseParticipationStatusType state = CheckIDUtil.checkCourseParticipationStatusTypeId(courseParticipationIn.getStatusId(), courseParticipationStatusTypeDao);
		// other input checks
		Staff staff = originalCourseParticipation.getStaff();
		if (!staff.getId().equals(courseParticipationIn.getStaffId())) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_STAFF_CHANGED);
		}
		Course course = originalCourseParticipation.getCourse();
		if (!course.getId().equals(courseParticipationIn.getCourseId())) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_COURSE_CHANGED);
		}
		if (courseParticipationIn.getShowCv() && !course.isShowCvPreset()) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_SHOW_CV_PRESET_DISABLED);
		}
		if (courseParticipationIn.getShowCv() && courseParticipationIn.getSectionId() == null) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_CV_SECTION_REQUIRED);
		}
		if (!courseParticipationIn.getShowCv() && courseParticipationIn.getShowCommentCv()) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_SHOW_CV_DISABLED);
		}
		boolean validState = false;
		Iterator<CourseParticipationStatusType> statesIt = courseParticipationStatusTypeDao.findTransitions(originalCourseParticipation.getStatus().getId(), admin,
				course.isSelfRegistration()).iterator();
		while (statesIt.hasNext()) {
			if (state.equals(statesIt.next())) {
				validState = true;
				break;
			}
		}
		if (!validState) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.COURSE_PARTICIPATION_INVALID_NEW_PARTICIPATION_STATUS_TYPE,
					L10nUtil.getCourseParticipationStatusTypeName(Locales.USER, state.getNameL10nKey()));
		}
			}

	public static void checkUserInput(UserInVO userIn, String plainDepartmentPassword, DepartmentDao departmentDao, StaffDao staffDao) throws Exception {
		Department department = CheckIDUtil.checkDepartmentId(userIn.getDepartmentId(), departmentDao);
		if (!CryptoUtil.checkDepartmentPassword(department, plainDepartmentPassword)) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.DEPARTMENT_PASSWORT_WRONG);
		}
		if (userIn.getIdentityId() != null) {
			CheckIDUtil.checkStaffId(userIn.getIdentityId(), staffDao);
		}
		checkLocale(userIn.getLocale());
		checkTimeZone(userIn.getTimeZone());
	}

	public static void checkUsernameExists(String username, UserDao userDao) throws ServiceException {
		if (userDao.searchUniqueName(username) != null) {
			throw L10nUtil.initServiceException(ServiceExceptionCodes.USERNAME_ALREADY_EXISTS, username);
		}
	}

	public static CourseCertificatePDFPainter createCourseCertificatePDFPainter(Collection<CourseParticipationStatusEntryOutVO> participantVOs, StaffDao staffDao,
			StaffAddressDao staffAddressDao, LecturerDao lecturerDao, LecturerCompetenceDao competenceDao) throws Exception {
		CourseCertificatePDFPainter painter = new CourseCertificatePDFPainter();
		Collection allCompetences = competenceDao.loadAllSorted(0, 0);
		competenceDao.toLecturerCompetenceVOCollection(allCompetences);
		if (participantVOs != null) {
			HashMap<Long, StaffOutVO> institutionVOMap = new HashMap<Long, StaffOutVO>(participantVOs.size());
			HashMap<Long, StaffAddressOutVO> institutionAddressVOMap = new HashMap<Long, StaffAddressOutVO>(participantVOs.size());
			HashMap<Long, HashMap<Long, Collection<LecturerOutVO>>> lecturerVOMap = new HashMap<Long, HashMap<Long, Collection<LecturerOutVO>>>(participantVOs.size());
			Iterator<CourseParticipationStatusEntryOutVO> participantIt = participantVOs.iterator();
			while (participantIt.hasNext()) {
				CourseParticipationStatusEntryOutVO participationVO = participantIt.next();
				CourseOutVO courseVO = participationVO.getCourse();
				StaffOutVO institutionVO = courseVO.getInstitution();
				if (institutionVO != null && !institutionVOMap.containsKey(courseVO.getId())) {
					institutionVO = staffDao.toStaffOutVO(staffDao.load(institutionVO.getId()), Settings.getInt(CourseCertificatePDFSettingCodes.GRAPH_MAX_STAFF_INSTANCES,
							Bundle.COURSE_CERTIFICATE_PDF, CourseCertificatePDFDefaultSettings.GRAPH_MAX_STAFF_INSTANCES));
					institutionVOMap.put(courseVO.getId(), institutionVO);
					institutionAddressVOMap.put(courseVO.getId(), findOrganisationCvAddress(institutionVO, true, staffAddressDao));
				}
				if (!lecturerVOMap.containsKey(courseVO.getId())) {
					HashMap<Long, Collection<LecturerOutVO>> competenceLecturerVOMap = new HashMap<Long, Collection<LecturerOutVO>>(allCompetences.size());
					Iterator<LecturerCompetenceVO> competenceIt = allCompetences.iterator();
					while (competenceIt.hasNext()) {
						LecturerCompetenceVO competenceVO = competenceIt.next();
						Collection lecturers = lecturerDao.findByCourseStaffCompetence(courseVO.getId(), null, competenceVO.getId(), null);
						lecturerDao.toLecturerOutVOCollection(lecturers);
						competenceLecturerVOMap.put(competenceVO.getId(), lecturers);
					}
					lecturerVOMap.put(courseVO.getId(), competenceLecturerVOMap);
				}
			}
			painter.setInstitutionAddressVOMap(institutionAddressVOMap);
			painter.setInstitutionVOMap(institutionVOMap);
			painter.setLecturerVOMap(lecturerVOMap);
			painter.setParticipantVOs(participantVOs);
		}
		painter.setAllCompetenceVOs(allCompetences);
		return painter;
	}

	public static CourseParticipantListPDFPainter createCourseParticipantListPDFPainter(Collection<CourseOutVO> courseVOs, boolean blank, LecturerDao lecturerDao,
			LecturerCompetenceDao competenceDao, CourseParticipationStatusEntryDao courseParticipationDao, InventoryBookingDao bookingDao) throws Exception {
		CourseParticipantListPDFPainter painter = new CourseParticipantListPDFPainter();
		Collection allCompetences = competenceDao.loadAllSorted(0, 0);
		competenceDao.toLecturerCompetenceVOCollection(allCompetences);
		if (courseVOs != null) {
			HashMap<Long, Collection<CourseParticipationStatusEntryOutVO>> participationVOMap = new HashMap<Long, Collection<CourseParticipationStatusEntryOutVO>>(courseVOs.size());
			HashMap<Long, HashMap<Long, Collection<LecturerOutVO>>> lecturerVOMap = new HashMap<Long, HashMap<Long, Collection<LecturerOutVO>>>(courseVOs.size());
			HashMap<Long, Collection<InventoryBookingOutVO>> bookingVOMap = new HashMap<Long, Collection<InventoryBookingOutVO>>(allCompetences.size());
			Iterator<CourseOutVO> courseIt = courseVOs.iterator();
			while (courseIt.hasNext()) {
				CourseOutVO courseVO = courseIt.next();
				HashMap<Long, Collection<LecturerOutVO>> competenceLecturerVOMap = new HashMap<Long, Collection<LecturerOutVO>>(allCompetences.size());
				Iterator<LecturerCompetenceVO> competenceIt = allCompetences.iterator();
				while (competenceIt.hasNext()) {
					LecturerCompetenceVO competenceVO = competenceIt.next();
					Collection lecturers = lecturerDao.findByCourseStaffCompetence(courseVO.getId(), null, competenceVO.getId(), null);
					lecturerDao.toLecturerOutVOCollection(lecturers);
					competenceLecturerVOMap.put(competenceVO.getId(), lecturers);
				}
				lecturerVOMap.put(courseVO.getId(), competenceLecturerVOMap);
				Collection participations = blank ? new ArrayList<CourseParticipationStatusEntry>() : courseParticipationDao.findByCourseSorted(courseVO.getId());
				courseParticipationDao.toCourseParticipationStatusEntryOutVOCollection(participations);
				participationVOMap.put(courseVO.getId(), participations);
				Collection bookings = bookingDao.findByCourseSorted(courseVO.getId(), true, true);
				bookingDao.toInventoryBookingOutVOCollection(bookings);
				bookingVOMap.put(courseVO.getId(), bookings);
			}
			painter.setCourseVOs(courseVOs);
			painter.setLecturerVOMap(lecturerVOMap);
			painter.setParticipationVOMap(participationVOMap);
			painter.setBookingVOMap(bookingVOMap);
		}
		painter.setDrawPageNumbers(!blank);
		painter.setAllCompetenceVOs(allCompetences);
		return painter;
	}

	public static CVPDFPainter createCVPDFPainter(Collection<StaffOutVO> staffVOs, StaffDao staffDao, CvSectionDao cvSectionDao, CvPositionDao cvPositionDao,
			CourseParticipationStatusEntryDao courseParticipationDao, StaffAddressDao staffAddressDao) throws Exception {
		CVPDFPainter painter = new CVPDFPainter();
		Collection allCvSections = cvSectionDao.loadAllSorted(0, 0);
		cvSectionDao.toCvSectionVOCollection(allCvSections);
		if (staffVOs != null) {
			ArrayList<StaffOutVO> personVOs = new ArrayList<StaffOutVO>(staffVOs.size());
			HashMap<Long, StaffAddressOutVO> addressVOMap = new HashMap<Long, StaffAddressOutVO>(staffVOs.size());
			HashMap<Long, StaffImageOutVO> imageVOMap = new HashMap<Long, StaffImageOutVO>(staffVOs.size());
			HashMap<Long, HashMap<Long, Collection<CvPositionPDFVO>>> cvPositionVOMap = new HashMap<Long, HashMap<Long, Collection<CvPositionPDFVO>>>(staffVOs.size());
			Iterator<StaffOutVO> staffIt = staffVOs.iterator();
			while (staffIt.hasNext()) {
				StaffOutVO staffVO = staffIt.next();
				if (staffVO.isPerson()) {
					personVOs.add(staffVO);
					StaffAddressOutVO addressVO = findOrganisationCvAddress(staffVO, true, staffAddressDao);
					addressVOMap.put(staffVO.getId(), addressVO);
					imageVOMap.put(staffVO.getId(), staffDao.toStaffImageOutVO(staffDao.load(staffVO.getId())));
					HashMap<Long, Collection<CvPositionPDFVO>> staffPositionVOMap = new HashMap<Long, Collection<CvPositionPDFVO>>(allCvSections.size());
					Iterator<CvSectionVO> sectionIt = allCvSections.iterator();
					while (sectionIt.hasNext()) {
						CvSectionVO sectionVO = sectionIt.next();
						staffPositionVOMap.put(sectionVO.getId(), loadCvPositions(staffVO.getId(), sectionVO.getId(), cvPositionDao, courseParticipationDao));
					}
					cvPositionVOMap.put(staffVO.getId(), staffPositionVOMap);
				}
			}
			painter.setStaffVOs(personVOs);
			painter.setCvPositionVOMap(cvPositionVOMap);
			painter.setAddressVOMap(addressVOMap);
			painter.setImageVOMap(imageVOMap);
		}
		painter.setAllCvSectionVOs(allCvSections);
		return painter;
	}

	public static void createKeyPair(User user, String plainDepartmentPassword, KeyPairDao keyPairDao) throws Exception {
		KeyPair keyPair = KeyPair.Factory.newInstance();
		java.security.KeyPair keys = CryptoUtil.createKeyPair();
		keyPair.setPublicKey(keys.getPublic().getEncoded());
		CryptoUtil.encryptPrivateKey(keyPair, keys.getPrivate().getEncoded(), plainDepartmentPassword);
		user.setKeyPair(keyPair);
		keyPair.setUser(user);
		keyPairDao.create(keyPair);
	}

	public static Password createPassword(Password password, User user, Timestamp timestamp, Password lastPassword, String plainNewPassword, String plainDepartmentPassword,
			PasswordDao passwordDao) throws Exception {
		CryptoUtil.encryptPasswords(password, plainNewPassword, plainDepartmentPassword);
		password.setSuccessfulLogons(0L);
		password.setWrongPasswordAttemptsSinceLastSuccessfulLogon(0L);
		password.setLastLogonAttemptHost(null);
		password.setLastLogonAttemptTimestamp(null);
		password.setLastSuccessfulLogonHost(null);
		password.setLastSuccessfulLogonTimestamp(null);
		password.setTimestamp(timestamp);
		password.setPreviousPassword(lastPassword);
		password.setUser(user);
		user.getPasswords().add(password);
		return passwordDao.create(password);
	}

	public static PasswordOutVO createPassword(Password password, User user, Timestamp timestamp, Password lastPassword, String plainNewPassword, String plainDepartmentPassword,
			PasswordDao passwordDao, JournalEntryDao journalEntryDao) throws Exception {
		password = createPassword(password, user, timestamp, lastPassword, plainNewPassword, plainDepartmentPassword, passwordDao);
		PasswordOutVO result = passwordDao.toPasswordOutVO(password);
		logSystemMessage(user, result.getUser(), timestamp, CoreUtil.getUser(), SystemMessageCodes.PASSWORD_CREATED, result, null, journalEntryDao);
		return result;
	}

	public static ECRFFieldValueInVO createPresetEcrfFieldInValue(ECRFField ecrfField, long listEntryId, Long index,
			InputFieldSelectionSetValueDao inputFieldSelectionSetValueDao) {
		ECRFFieldValueInVO ecrfFieldValueIn = new ECRFFieldValueInVO();
		InputField inputField = ecrfField.getField();
		if (ecrfField.isSeries()) {
			ecrfFieldValueIn.setIndex(index);
		} else {
			ecrfFieldValueIn.setIndex(null);
		}
		ecrfFieldValueIn.setEcrfFieldId(ecrfField.getId());
		ecrfFieldValueIn.setListEntryId(listEntryId);
		ecrfFieldValueIn.setReasonForChange(null);
		Boolean booleanPreset = inputField.getBooleanPreset();
		ecrfFieldValueIn.setBooleanValue(booleanPreset == null ? false : booleanPreset.booleanValue());
		ecrfFieldValueIn.setDateValue(CoreUtil.forceDate(inputField.getDatePreset()));
		ecrfFieldValueIn.setTimeValue(CoreUtil.forceDate(inputField.getTimePreset()));
		ecrfFieldValueIn.setFloatValue(inputField.getFloatPreset());
		ecrfFieldValueIn.setLongValue(inputField.getLongPreset());
		ecrfFieldValueIn.setTimestampValue(inputField.getTimestampPreset());
		ecrfFieldValueIn.setInkValues(null);
		if (InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType())) {
			ecrfFieldValueIn.setTextValue(getAutocompletePresetValue(inputField.getId(), inputFieldSelectionSetValueDao));
		} else {
			if (inputField.isLocalized()) {
				ecrfFieldValueIn.setTextValue(L10nUtil.getInputFieldTextPreset(Locales.USER, inputField.getTextPresetL10nKey()));
			} else {
				ecrfFieldValueIn.setTextValue(inputField.getTextPresetL10nKey());
			}
			if (InputFieldType.SELECT_ONE_DROPDOWN.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_ONE_RADIO_H.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_ONE_RADIO_V.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_MANY_H.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_MANY_V.equals(inputField.getFieldType())) {
				Iterator<InputFieldSelectionSetValue> it = inputFieldSelectionSetValueDao.findByFieldPreset(inputField.getId(), true, null).iterator();
				while (it.hasNext()) {
					ecrfFieldValueIn.getSelectionValueIds().add(it.next().getId());
				}
			}
		}
		return ecrfFieldValueIn;

	}

	public static ArrayList<ECRFFieldValueInVO> createPresetEcrfFieldInValues(long listEntryId, long ecrfId, String section, Long index, ECRFFieldDao ecrfFieldDao,
			ECRFFieldValueDao ecrfFieldValueDao, InputFieldSelectionSetValueDao inputFieldSelectionSetValueDao) {
		ArrayList<ECRFFieldValueInVO> result = new ArrayList<ECRFFieldValueInVO>();
		Iterator<ECRFField> ecrfFieldIt = ecrfFieldDao.findByEcrfSectionPosition(ecrfId, section, null).iterator();
		while (ecrfFieldIt.hasNext()) {
			ECRFField ecrfField = ecrfFieldIt.next();
			if (ecrfFieldValueDao.getByListEntryEcrfFieldIndex(listEntryId, ecrfField.getId(), index) == null) {
				result.add(createPresetEcrfFieldInValue(ecrfField, listEntryId, index, inputFieldSelectionSetValueDao));
			}
		}
		return result;
	}

	public static ECRFFieldValueJsonVO createPresetEcrfFieldJsonValue(ECRFField ecrfField, Long index, InputFieldSelectionSetValueDao inputFieldSelectionSetValueDao) {
		ECRFFieldValueJsonVO ecrfFieldValueVO = new ECRFFieldValueJsonVO();
		InputField inputField = ecrfField.getField();
		if (ecrfField.isSeries()) {
			ecrfFieldValueVO.setIndex(index);
			ecrfFieldValueVO.setSeries(true);
		} else {
			ecrfFieldValueVO.setIndex(null);
			ecrfFieldValueVO.setSeries(false);
		}
		ecrfFieldValueVO.setEcrfFieldId(ecrfField.getId());
		ecrfFieldValueVO.setPosition(ecrfField.getPosition());
		ecrfFieldValueVO.setJsVariableName(ecrfField.getJsVariableName());
		ecrfFieldValueVO.setJsValueExpression(ecrfField.getJsValueExpression());
		ecrfFieldValueVO.setJsOutputExpression(ecrfField.getJsOutputExpression());
		ecrfFieldValueVO.setDisabled(ecrfField.isDisabled());
		ecrfFieldValueVO.setSection(ecrfField.getSection());
		ECRF ecrf = ecrfField.getEcrf();
		if (ecrf != null) {
			ecrfFieldValueVO.setProbandGroupToken(ecrf.getGroup() != null ? ecrf.getGroup().getToken() : null);
			ecrfFieldValueVO.setVisitToken(ecrf.getVisit() != null ? ecrf.getVisit().getToken() : null);
		}
		ecrfFieldValueVO.setInputFieldId(inputField.getId());
		ecrfFieldValueVO.setInputFieldType(inputField.getFieldType());
		if (inputField.isLocalized()) {
			ecrfFieldValueVO.setInputFieldName(L10nUtil.getInputFieldName(Locales.USER, inputField.getNameL10nKey()));
		} else {
			ecrfFieldValueVO.setInputFieldName(inputField.getNameL10nKey());
		}
		Boolean booleanPreset = inputField.getBooleanPreset();
		ecrfFieldValueVO.setBooleanValue(booleanPreset == null ? false : booleanPreset.booleanValue());
		ecrfFieldValueVO.setDateValue(CoreUtil.forceDate(inputField.getDatePreset()));
		ecrfFieldValueVO.setTimeValue(CoreUtil.forceDate(inputField.getTimePreset()));
		ecrfFieldValueVO.setFloatValue(inputField.getFloatPreset());
		ecrfFieldValueVO.setLongValue(inputField.getLongPreset());
		ecrfFieldValueVO.setTimestampValue(inputField.getTimestampPreset());
		ecrfFieldValueVO.setInkValues(null);
		if (InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType())) {
			ecrfFieldValueVO.setTextValue(getAutocompletePresetValue(inputField.getId(), inputFieldSelectionSetValueDao));
		} else {
			if (inputField.isLocalized()) {
				ecrfFieldValueVO.setTextValue(L10nUtil.getInputFieldTextPreset(Locales.USER, inputField.getTextPresetL10nKey()));
			} else {
				ecrfFieldValueVO.setTextValue(inputField.getTextPresetL10nKey());
			}
			if (isLoadSelectionSet(inputField.getFieldType())) {
				Iterator<InputFieldSelectionSetValue> it = inputField.getSelectionSetValues().iterator();
				while (it.hasNext()) {
					InputFieldSelectionSetValue selectionValue = it.next();
					if (selectionValue.isPreset()) {
						ecrfFieldValueVO.getSelectionValueIds().add(selectionValue.getId());
					}
					ecrfFieldValueVO.getInputFieldSelectionSetValues().add(inputFieldSelectionSetValueDao.toInputFieldSelectionSetValueJsonVO(selectionValue));
				}
			}
		}
		return ecrfFieldValueVO;
	}

	public static ECRFFieldValueOutVO createPresetEcrfFieldOutValue(ECRFFieldOutVO ecrfFieldVO, ProbandListEntryOutVO listEntryVO, Long index, Locales locale,
			ECRFFieldStatusEntryDao ecrfFieldStatusEntryDao, ECRFFieldStatusTypeDao ecrfFieldStatusTypeDao
			) { //InputFieldSelectionSetValueDao inputFieldSelectionSetValueDao) {
		ECRFFieldValueOutVO ecrfFieldValueVO = new ECRFFieldValueOutVO();
		if (ecrfFieldVO.getSeries()) {
			ecrfFieldValueVO.setIndex(index);
		} else {
			ecrfFieldValueVO.setIndex(null);
		}
		InputFieldOutVO inputField = ecrfFieldVO.getField();
		if (locale != null && inputField.getLocalized()) {
			InputFieldOutVO localizedInputField = new InputFieldOutVO();
			localizedInputField.copy(localizedInputField);
			if (!InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType().getType())) {
				localizedInputField.setTextPreset(L10nUtil.getInputFieldTextPreset(locale, localizedInputField.getTextPresetL10nKey()));
			}
			localizedInputField.setName(L10nUtil.getInputFieldName(locale, localizedInputField.getNameL10nKey()));
			localizedInputField.setTitle(L10nUtil.getInputFieldTitle(locale, localizedInputField.getTitleL10nKey()));
			localizedInputField.setComment(L10nUtil.getInputFieldComment(locale, localizedInputField.getCommentL10nKey()));
			localizedInputField.setValidationErrorMsg(L10nUtil.getInputFieldValidationErrorMsg(locale, localizedInputField.getValidationErrorMsgL10nKey()));
			inputField = localizedInputField;
		}
		ecrfFieldValueVO.setEcrfField(ecrfFieldVO);
		ecrfFieldValueVO.setListEntry(listEntryVO);
		ecrfFieldValueVO.setBooleanValue(inputField.getBooleanPreset());
		ecrfFieldValueVO.setDateValue(inputField.getDatePreset());
		ecrfFieldValueVO.setTimeValue(inputField.getTimePreset());
		ecrfFieldValueVO.setFloatValue(inputField.getFloatPreset());
		ecrfFieldValueVO.setLongValue(inputField.getLongPreset());
		ecrfFieldValueVO.setTimestampValue(inputField.getTimestampPreset());
		ecrfFieldValueVO.setInkValues(null);
		//		if (InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType().getType())) {
		//			ecrfFieldValueVO.setTextValue(getAutocompletePresetValue(inputField.getId(), inputFieldSelectionSetValueDao));
		//		} else {
		ecrfFieldValueVO.setTextValue(inputField.getTextPreset());
		Iterator<InputFieldSelectionSetValueOutVO> it = inputField.getSelectionSetValues().iterator();
		while (it.hasNext()) {
			InputFieldSelectionSetValueOutVO selectionValue = it.next();
			if (selectionValue.isPreset()) {
				if (locale != null && selectionValue.getLocalized()) {
					InputFieldSelectionSetValueOutVO localizedSelectionValue = new InputFieldSelectionSetValueOutVO();
					localizedSelectionValue.copy(selectionValue);
					localizedSelectionValue.setName(L10nUtil.getInputFieldSelectionSetValueName(locale, localizedSelectionValue.getNameL10nKey()));
					selectionValue = localizedSelectionValue;
				}
				ecrfFieldValueVO.getSelectionValues().add(selectionValue);
			}
		}
		if (listEntryVO != null && ecrfFieldVO != null) {

			ECRFFieldStatusQueue[] queues = ECRFFieldStatusQueue.values();
			for (int i = 0; i < queues.length; i++) {
				ECRFFieldStatusEntry lastStatus = ecrfFieldStatusEntryDao.findLastStatus(queues[i], listEntryVO.getId(), ecrfFieldVO.getId(), ecrfFieldValueVO.getIndex());
				if (lastStatus != null) {
					ecrfFieldValueVO.getLastFieldStatuses().add(ecrfFieldStatusTypeDao.toECRFFieldStatusTypeVO(lastStatus.getStatus()));
					if (!lastStatus.getStatus().isResolved()
							&& (ecrfFieldValueVO.getLastUnresolvedFieldStatusEntry() == null || ecrfFieldValueVO.getLastUnresolvedFieldStatusEntry().getId() < lastStatus.getId())) {
						ecrfFieldValueVO.setLastUnresolvedFieldStatusEntry(ecrfFieldStatusEntryDao.toECRFFieldStatusEntryOutVO(lastStatus));
					}
				}
			}
			// populateEcrfFieldStatusEntryCount(ecrfFieldValueVO.getEcrfFieldStatusQueueCounts(), listEntryVO.getId(), ecrfFieldVO.getId(), ecrfFieldValueVO.getIndex(),
			// ecrfFieldStatusEntryDao);

			//			// ECRFFieldStatusEntryDao ecrfFieldStatusEntryDao = this.getECRFFieldStatusEntryDao();
			//			ecrfFieldValueVO.setValidationUnresolved(ecrfFieldStatusEntryDao.getCount(ECRFFieldStatusQueue.VALIDATION, listEntryVO.getId(), ecrfFieldVO.getId(),
			//					ecrfFieldValueVO.getIndex(), true, false) > 0l);
			//			ecrfFieldValueVO.setQueryUnresolved(ecrfFieldStatusEntryDao.getCount(ECRFFieldStatusQueue.QUERY, listEntryVO.getId(), ecrfFieldVO.getId(), ecrfFieldValueVO.getIndex(),
			//					true, false) > 0l);
		}

		//		}
		return ecrfFieldValueVO;
	}

	public static InquiryValueInVO createPresetInquiryInValue(Inquiry inquiry, long probandId,
			InputFieldSelectionSetValueDao inputFieldSelectionSetValueDao) {
		InquiryValueInVO inquiryValueIn = new InquiryValueInVO();
		InputField inputField = inquiry.getField();
		inquiryValueIn.setInquiryId(inquiry.getId());
		inquiryValueIn.setProbandId(probandId);
		Boolean booleanPreset = inputField.getBooleanPreset();
		inquiryValueIn.setBooleanValue(booleanPreset == null ? false : booleanPreset.booleanValue());
		inquiryValueIn.setDateValue(CoreUtil.forceDate(inputField.getDatePreset()));
		inquiryValueIn.setTimeValue(CoreUtil.forceDate(inputField.getTimePreset()));
		inquiryValueIn.setFloatValue(inputField.getFloatPreset());
		inquiryValueIn.setLongValue(inputField.getLongPreset());
		inquiryValueIn.setTimestampValue(inputField.getTimestampPreset());
		inquiryValueIn.setInkValues(null);
		if (InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType())) {
			inquiryValueIn.setTextValue(getAutocompletePresetValue(inputField.getId(),inputFieldSelectionSetValueDao));
		} else {
			if (inputField.isLocalized()) {
				inquiryValueIn.setTextValue(L10nUtil.getInputFieldTextPreset(Locales.USER, inputField.getTextPresetL10nKey()));
			} else {
				inquiryValueIn.setTextValue(inputField.getTextPresetL10nKey());
			}
			if (InputFieldType.SELECT_ONE_DROPDOWN.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_ONE_RADIO_H.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_ONE_RADIO_V.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_MANY_H.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_MANY_V.equals(inputField.getFieldType())) {
				Iterator<InputFieldSelectionSetValue> it = inputFieldSelectionSetValueDao.findByFieldPreset(inputField.getId(), true, null).iterator();
				while (it.hasNext()) {
					inquiryValueIn.getSelectionValueIds().add(it.next().getId());
				}
			}
		}
		return inquiryValueIn;

	}

	public static InquiryValueJsonVO createPresetInquiryJsonValue(Inquiry inquiry, InputFieldSelectionSetValueDao inputFieldSelectionSetValueDao) {
		InquiryValueJsonVO inquiryValueVO = new InquiryValueJsonVO();
		InputField inputField = inquiry.getField();
		inquiryValueVO.setInquiryId(inquiry.getId());
		inquiryValueVO.setPosition(inquiry.getPosition());
		inquiryValueVO.setJsVariableName(inquiry.getJsVariableName());
		inquiryValueVO.setJsValueExpression(inquiry.getJsValueExpression());
		inquiryValueVO.setJsOutputExpression(inquiry.getJsOutputExpression());
		inquiryValueVO.setDisabled(inquiry.isDisabled());
		inquiryValueVO.setCategory(inquiry.getCategory());
		inquiryValueVO.setInputFieldId(inputField.getId());
		inquiryValueVO.setInputFieldType(inputField.getFieldType());
		if (inputField.isLocalized()) {
			inquiryValueVO.setInputFieldName(L10nUtil.getInputFieldName(Locales.USER, inputField.getNameL10nKey()));
		} else {
			inquiryValueVO.setInputFieldName(inputField.getNameL10nKey());
		}
		Boolean booleanPreset = inputField.getBooleanPreset();
		inquiryValueVO.setBooleanValue(booleanPreset == null ? false : booleanPreset.booleanValue());
		inquiryValueVO.setDateValue(CoreUtil.forceDate(inputField.getDatePreset()));
		inquiryValueVO.setTimeValue(CoreUtil.forceDate(inputField.getTimePreset()));
		inquiryValueVO.setFloatValue(inputField.getFloatPreset());
		inquiryValueVO.setLongValue(inputField.getLongPreset());
		inquiryValueVO.setTimestampValue(inputField.getTimestampPreset());
		inquiryValueVO.setInkValues(null);
		if (InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType())) {
			inquiryValueVO.setTextValue(getAutocompletePresetValue(inputField.getId(),inputFieldSelectionSetValueDao));
		} else {
			if (inputField.isLocalized()) {
				inquiryValueVO.setTextValue(L10nUtil.getInputFieldTextPreset(Locales.USER, inputField.getTextPresetL10nKey()));
			} else {
				inquiryValueVO.setTextValue(inputField.getTextPresetL10nKey());
			}
			if (isLoadSelectionSet(inputField.getFieldType())) {
				Iterator<InputFieldSelectionSetValue> it = inputField.getSelectionSetValues().iterator();
				while (it.hasNext()) {
					InputFieldSelectionSetValue selectionValue = it.next();
					if (selectionValue.isPreset()) {
						inquiryValueVO.getSelectionValueIds().add(selectionValue.getId());
					}
					inquiryValueVO.getInputFieldSelectionSetValues().add(inputFieldSelectionSetValueDao.toInputFieldSelectionSetValueJsonVO(selectionValue));
				}
			}
		}
		return inquiryValueVO;
	}

	public static InquiryValueOutVO createPresetInquiryOutValue(ProbandOutVO probandVO, InquiryOutVO inquiryVO, Locales locale
			) { //InputFieldSelectionSetValueDao inputFieldSelectionSetValueDao) {
		InquiryValueOutVO inquiryValueVO = new InquiryValueOutVO();
		InputFieldOutVO inputField = inquiryVO.getField();
		if (locale != null && inputField.getLocalized()) {
			InputFieldOutVO localizedInputField = new InputFieldOutVO();
			localizedInputField.copy(localizedInputField);
			if (!InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType().getType())) {
				localizedInputField.setTextPreset(L10nUtil.getInputFieldTextPreset(locale, localizedInputField.getTextPresetL10nKey()));
			}
			localizedInputField.setName(L10nUtil.getInputFieldName(locale, localizedInputField.getNameL10nKey()));
			localizedInputField.setTitle(L10nUtil.getInputFieldTitle(locale, localizedInputField.getTitleL10nKey()));
			localizedInputField.setComment(L10nUtil.getInputFieldComment(locale, localizedInputField.getCommentL10nKey()));
			localizedInputField.setValidationErrorMsg(L10nUtil.getInputFieldValidationErrorMsg(locale, localizedInputField.getValidationErrorMsgL10nKey()));
			inputField = localizedInputField;
		}
		inquiryValueVO.setInquiry(inquiryVO);
		inquiryValueVO.setProband(probandVO);
		inquiryValueVO.setBooleanValue(inputField.getBooleanPreset());
		inquiryValueVO.setDateValue(inputField.getDatePreset());
		inquiryValueVO.setTimeValue(inputField.getTimePreset());
		inquiryValueVO.setFloatValue(inputField.getFloatPreset());
		inquiryValueVO.setLongValue(inputField.getLongPreset());
		inquiryValueVO.setTimestampValue(inputField.getTimestampPreset());
		inquiryValueVO.setInkValues(null);


		//		if (InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType().getType())) {
		//			inquiryValueVO.setTextValue(getAutocompletePresetValue(inputField.getId(),inputFieldSelectionSetValueDao));
		//		} else {
		inquiryValueVO.setTextValue(inputField.getTextPreset());

		Iterator<InputFieldSelectionSetValueOutVO> it = inputField.getSelectionSetValues().iterator();
		while (it.hasNext()) {
			InputFieldSelectionSetValueOutVO selectionValue = it.next();
			if (selectionValue.isPreset()) {
				if (locale != null && selectionValue.getLocalized()) {
					InputFieldSelectionSetValueOutVO localizedSelectionValue = new InputFieldSelectionSetValueOutVO();
					localizedSelectionValue.copy(selectionValue);
					localizedSelectionValue.setName(L10nUtil.getInputFieldSelectionSetValueName(locale, localizedSelectionValue.getNameL10nKey()));
					selectionValue = localizedSelectionValue;
				}
				inquiryValueVO.getSelectionValues().add(selectionValue);
			}
		}
		//		}
		return inquiryValueVO;


	}


	public static ProbandListEntryTagValueInVO createPresetProbandListEntryTagInValue(ProbandListEntryTag listEntryTag, long listEntryId,
			InputFieldSelectionSetValueDao inputFieldSelectionSetValueDao) {
		ProbandListEntryTagValueInVO probandListEntryTagValueIn = new ProbandListEntryTagValueInVO();
		InputField inputField = listEntryTag.getField();
		probandListEntryTagValueIn.setTagId(listEntryTag.getId());
		probandListEntryTagValueIn.setListEntryId(listEntryId);
		Boolean booleanPreset = inputField.getBooleanPreset();
		probandListEntryTagValueIn.setBooleanValue(booleanPreset == null ? false : booleanPreset.booleanValue());
		probandListEntryTagValueIn.setDateValue(CoreUtil.forceDate(inputField.getDatePreset()));
		probandListEntryTagValueIn.setTimeValue(CoreUtil.forceDate(inputField.getTimePreset()));
		probandListEntryTagValueIn.setFloatValue(inputField.getFloatPreset());
		probandListEntryTagValueIn.setLongValue(inputField.getLongPreset());
		probandListEntryTagValueIn.setTimestampValue(inputField.getTimestampPreset());
		probandListEntryTagValueIn.setInkValues(null);
		if (InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType())) {
			probandListEntryTagValueIn.setTextValue(getAutocompletePresetValue(inputField.getId(),inputFieldSelectionSetValueDao));
		} else {
			if (inputField.isLocalized()) {
				probandListEntryTagValueIn.setTextValue(L10nUtil.getInputFieldTextPreset(Locales.USER, inputField.getTextPresetL10nKey()));
			} else {
				probandListEntryTagValueIn.setTextValue(inputField.getTextPresetL10nKey());
			}
			if (InputFieldType.SELECT_ONE_DROPDOWN.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_ONE_RADIO_H.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_ONE_RADIO_V.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_MANY_H.equals(inputField.getFieldType())
					|| InputFieldType.SELECT_MANY_V.equals(inputField.getFieldType())) {
				Iterator<InputFieldSelectionSetValue> it = inputFieldSelectionSetValueDao.findByFieldPreset(inputField.getId(), true, null).iterator();
				while (it.hasNext()) {
					probandListEntryTagValueIn.getSelectionValueIds().add(it.next().getId());
				}
			}
		}
		return probandListEntryTagValueIn;

	}

	public static ProbandListEntryTagValueJsonVO createPresetProbandListEntryTagJsonValue(ProbandListEntryTag listEntryTag,
			InputFieldSelectionSetValueDao inputFieldSelectionSetValueDao) {
		ProbandListEntryTagValueJsonVO listEntryTagValueVO = new ProbandListEntryTagValueJsonVO();
		InputField inputField = listEntryTag.getField();
		listEntryTagValueVO.setTagId(listEntryTag.getId());
		listEntryTagValueVO.setPosition(listEntryTag.getPosition());
		listEntryTagValueVO.setJsVariableName(listEntryTag.getJsVariableName());
		listEntryTagValueVO.setJsValueExpression(listEntryTag.getJsValueExpression());
		listEntryTagValueVO.setJsOutputExpression(listEntryTag.getJsOutputExpression());
		listEntryTagValueVO.setDisabled(listEntryTag.isDisabled());
		listEntryTagValueVO.setInputFieldId(inputField.getId());
		listEntryTagValueVO.setInputFieldType(inputField.getFieldType());
		if (inputField.isLocalized()) {
			listEntryTagValueVO.setInputFieldName(L10nUtil.getInputFieldName(Locales.USER, inputField.getNameL10nKey()));
		} else {
			listEntryTagValueVO.setInputFieldName(inputField.getNameL10nKey());
		}
		Boolean booleanPreset = inputField.getBooleanPreset();
		listEntryTagValueVO.setBooleanValue(booleanPreset == null ? false : booleanPreset.booleanValue());
		listEntryTagValueVO.setDateValue(CoreUtil.forceDate(inputField.getDatePreset()));
		listEntryTagValueVO.setTimeValue(CoreUtil.forceDate(inputField.getTimePreset()));
		listEntryTagValueVO.setFloatValue(inputField.getFloatPreset());
		listEntryTagValueVO.setLongValue(inputField.getLongPreset());
		listEntryTagValueVO.setTimestampValue(inputField.getTimestampPreset());
		listEntryTagValueVO.setInkValues(null);
		if (InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType())) {
			listEntryTagValueVO.setTextValue(getAutocompletePresetValue(inputField.getId(),inputFieldSelectionSetValueDao));
		} else {
			if (inputField.isLocalized()) {
				listEntryTagValueVO.setTextValue(L10nUtil.getInputFieldTextPreset(Locales.USER, inputField.getTextPresetL10nKey()));
			} else {
				listEntryTagValueVO.setTextValue(inputField.getTextPresetL10nKey());
			}
			if (isLoadSelectionSet(inputField.getFieldType())) {
				Iterator<InputFieldSelectionSetValue> it = inputField.getSelectionSetValues().iterator();
				while (it.hasNext()) {
					InputFieldSelectionSetValue selectionValue = it.next();
					if (selectionValue.isPreset()) {
						listEntryTagValueVO.getSelectionValueIds().add(selectionValue.getId());
					}
					listEntryTagValueVO.getInputFieldSelectionSetValues().add(inputFieldSelectionSetValueDao.toInputFieldSelectionSetValueJsonVO(selectionValue));
				}
			}
		}

		return listEntryTagValueVO;
	}

	public static ProbandListEntryTagValueOutVO createPresetProbandListEntryTagOutValue(ProbandListEntryOutVO probandListEntryVO, ProbandListEntryTagOutVO listEntryTagVO,
			Locales locale) { //, InputFieldSelectionSetValueDao inputFieldSelectionSetValueDao) {
		ProbandListEntryTagValueOutVO listEntryTagValueVO = new ProbandListEntryTagValueOutVO();
		InputFieldOutVO inputField = listEntryTagVO.getField();
		if (locale != null && inputField.getLocalized()) {
			InputFieldOutVO localizedInputField = new InputFieldOutVO();
			localizedInputField.copy(localizedInputField);
			if (!InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType().getType())) {
				localizedInputField.setTextPreset(L10nUtil.getInputFieldTextPreset(locale, localizedInputField.getTextPresetL10nKey()));
			}
			localizedInputField.setName(L10nUtil.getInputFieldName(locale, localizedInputField.getNameL10nKey()));
			localizedInputField.setTitle(L10nUtil.getInputFieldTitle(locale, localizedInputField.getTitleL10nKey()));
			localizedInputField.setComment(L10nUtil.getInputFieldComment(locale, localizedInputField.getCommentL10nKey()));
			localizedInputField.setValidationErrorMsg(L10nUtil.getInputFieldValidationErrorMsg(locale, localizedInputField.getValidationErrorMsgL10nKey()));
			inputField = localizedInputField;
		}
		listEntryTagValueVO.setTag(listEntryTagVO);
		listEntryTagValueVO.setListEntry(probandListEntryVO);
		listEntryTagValueVO.setBooleanValue(inputField.getBooleanPreset());
		listEntryTagValueVO.setDateValue(inputField.getDatePreset());
		listEntryTagValueVO.setTimeValue(inputField.getTimePreset());
		listEntryTagValueVO.setFloatValue(inputField.getFloatPreset());
		listEntryTagValueVO.setLongValue(inputField.getLongPreset());
		listEntryTagValueVO.setTimestampValue(inputField.getTimestampPreset());
		listEntryTagValueVO.setInkValues(null);




		//		if (InputFieldType.AUTOCOMPLETE.equals(inputField.getFieldType().getType())) {
		//			listEntryTagValueVO.setTextValue(getAutocompletePresetValue(inputField.getId(),inputFieldSelectionSetValueDao));
		//		} else {
		listEntryTagValueVO.setTextValue(inputField.getTextPreset());

		Iterator<InputFieldSelectionSetValueOutVO> it = inputField.getSelectionSetValues().iterator();
		while (it.hasNext()) {
			InputFieldSelectionSetValueOutVO selectionValue = it.next();
			if (selectionValue.isPreset()) {
				if (locale != null && selectionValue.getLocalized()) {
					InputFieldSelectionSetValueOutVO localizedSelectionValue = new InputFieldSelectionSetValueOutVO();
					localizedSelectionValue.copy(selectionValue);
					localizedSelectionValue.setName(L10nUtil.getInputFieldSelectionSetValueName(locale, localizedSelectionValue.getNameL10nKey()));
					selectionValue = localizedSelectionValue;
				}
				listEntryTagValueVO.getSelectionValues().add(selectionValue);
			}
		}
		//		}
		return listEntryTagValueVO;


	}

	public static ProbandLetterPDFPainter createProbandLetterPDFPainter(Collection<ProbandOutVO> probandVOs, ProbandAddressDao probandAddressDao) throws Exception {
		ProbandLetterPDFPainter painter = new ProbandLetterPDFPainter();
		if (probandVOs != null) {
			ArrayList<ProbandOutVO> VOs = new ArrayList<ProbandOutVO>(probandVOs.size());
			HashMap<Long, Collection<ProbandAddressOutVO>> addressVOMap = new HashMap<Long, Collection<ProbandAddressOutVO>>(probandVOs.size());
			Iterator<ProbandOutVO> probandIt = probandVOs.iterator();
			while (probandIt.hasNext()) {
				ProbandOutVO probandVO = probandIt.next();
				if (probandVO.isPerson()) { // && !probandVO.isBlinded()
					Collection addresses = probandAddressDao.findByProband(probandVO.getId(), true, false, null, null);
					probandAddressDao.toProbandAddressOutVOCollection(addresses);
					addressVOMap.put(probandVO.getId(), addresses);
					VOs.add(probandVO);
				}
			}
			painter.setProbandVOs(VOs);
			painter.setAddressVOMap(addressVOMap);
		}
		return painter;
	}

	public static ProbandLetterPDFPainter createProbandLetterPDFPainter(ProbandAddressOutVO probandAddress) throws Exception {
		ProbandLetterPDFPainter painter = new ProbandLetterPDFPainter();
		if (probandAddress != null) {
			ProbandOutVO probandVO = probandAddress.getProband();
			HashMap<Long, Collection<ProbandAddressOutVO>> addressVOMap = new HashMap<Long, Collection<ProbandAddressOutVO>>(1);
			ArrayList<ProbandOutVO> probandVOs = new ArrayList<ProbandOutVO>(1);
			if (probandVO.isPerson()) { // && !probandVO.isBlinded()
				ArrayList<ProbandAddressOutVO> addresses = new ArrayList<ProbandAddressOutVO>(1);
				addresses.add(probandAddress);
				addressVOMap.put(probandVO.getId(), addresses);
				probandVOs.add(probandVO);
			}
			painter.setProbandVOs(probandVOs);
			painter.setAddressVOMap(addressVOMap);
		}
		return painter;
	}

	public static ReimbursementsExcelVO createReimbursementsExcel(Collection<MoneyTransfer> moneyTransfers, Collection<String> costTypes, TrialOutVO trialVO,
			ProbandOutVO probandVO, String costType, PaymentMethod method, Boolean paid,
			MoneyTransferDao moneyTransferDao,
			BankAccountDao bankAccountDao,
			ProbandAddressDao probandAddressDao,
			AddressTypeDao addressTypeDao,
			UserDao userDao) throws Exception {
		boolean passDecryption = CoreUtil.isPassDecryption();
		ReimbursementsExcelWriter writer = new ReimbursementsExcelWriter(!passDecryption, method);
		writer.setCostType(costType);
		writer.setPaid(paid);
		writer.setTrial(trialVO);
		writer.setProband(probandVO);
		boolean showAddresses;
		boolean aggregateAddresses;
		if (method != null) {
			switch (method) {
				case PETTY_CASH:
					showAddresses = Settings.getBoolean(ReimbursementsExcelSettingCodes.PETTY_CASH_SHOW_ADDRESSES, Bundle.REIMBURSEMENTS_EXCEL,
							ReimbursementsExcelDefaultSettings.PETTY_CASH_SHOW_ADDRESSES);
					aggregateAddresses = Settings.getBoolean(ReimbursementsExcelSettingCodes.PETTY_CASH_AGGREGATE_ADDRESSES, Bundle.REIMBURSEMENTS_EXCEL,
							ReimbursementsExcelDefaultSettings.PETTY_CASH_AGGREGATE_ADDRESSES);
					break;
				case VOUCHER:
					showAddresses = Settings.getBoolean(ReimbursementsExcelSettingCodes.VOUCHER_SHOW_ADDRESSES, Bundle.REIMBURSEMENTS_EXCEL,
							ReimbursementsExcelDefaultSettings.VOUCHER_SHOW_ADDRESSES);
					aggregateAddresses = Settings.getBoolean(ReimbursementsExcelSettingCodes.VOUCHER_AGGREGATE_ADDRESSES, Bundle.REIMBURSEMENTS_EXCEL,
							ReimbursementsExcelDefaultSettings.VOUCHER_AGGREGATE_ADDRESSES);
					break;
				case WIRE_TRANSFER:
					showAddresses = Settings.getBoolean(ReimbursementsExcelSettingCodes.WIRE_TRANSFER_SHOW_ADDRESSES, Bundle.REIMBURSEMENTS_EXCEL,
							ReimbursementsExcelDefaultSettings.WIRE_TRANSFER_SHOW_ADDRESSES);
					aggregateAddresses = Settings.getBoolean(ReimbursementsExcelSettingCodes.WIRE_TRANSFER_AGGREGATE_ADDRESSES, Bundle.REIMBURSEMENTS_EXCEL,
							ReimbursementsExcelDefaultSettings.WIRE_TRANSFER_AGGREGATE_ADDRESSES);
					break;
				default:
					showAddresses = false;
					aggregateAddresses = false;
					break;
			}
		} else {
			showAddresses = Settings.getBoolean(ReimbursementsExcelSettingCodes.SHOW_ADDRESSES, Bundle.REIMBURSEMENTS_EXCEL, ReimbursementsExcelDefaultSettings.SHOW_ADDRESSES);
			aggregateAddresses = Settings.getBoolean(ReimbursementsExcelSettingCodes.AGGREGATE_ADDRESSES, Bundle.REIMBURSEMENTS_EXCEL,
					ReimbursementsExcelDefaultSettings.AGGREGATE_ADDRESSES);
		}
		Collection addressTypes = showAddresses ? addressTypeDao.findByStaffProbandAnimalId(null, true, null, null) : new ArrayList();
		addressTypeDao.toAddressTypeVOCollection(addressTypes);
		ArrayList<String> distinctColumnNames;
		if (passDecryption) {
			distinctColumnNames = new ArrayList<String>((aggregateAddresses ? 3 : addressTypes.size()));
			if (aggregateAddresses) {
				distinctColumnNames.add(ReimbursementsExcelWriter.getStreetsColumnName());
				distinctColumnNames.add(ReimbursementsExcelWriter.getZipCodesColumnName());
				distinctColumnNames.add(ReimbursementsExcelWriter.getCityNamesColumnName());
			} else {
				Iterator<AddressTypeVO> addressTypesIt = addressTypes.iterator();
				while (addressTypesIt.hasNext()) {
					distinctColumnNames.add(addressTypesIt.next().getName());
				}
			}
		} else {
			distinctColumnNames = new ArrayList<String>();
		}
		Collection VOs = null;
		Iterator VOIt;
		boolean listMoneyTransfers = false;
		HashMap<Long, HashMap<String, Object>> distinctFieldRows = null;
		if (method != null) {
			MoneyTransferSummaryVO summary;
			switch (method) {
				case PETTY_CASH:
					listMoneyTransfers = true;
					break;
				case VOUCHER:
					listMoneyTransfers = true;
					break;
				case WIRE_TRANSFER:
					summary = new MoneyTransferSummaryVO();
					summary.setListEntry(null);
					summary.setTrial(trialVO);
					summary.setProband(probandVO);
					if (probandVO != null) {
						summary.setId(probandVO.getId());
					} else if (trialVO != null) {
						summary.setId(trialVO.getId());
					}
					populateMoneyTransferSummary(summary, costTypes, moneyTransfers, false, false, true, false, bankAccountDao);
					VOs = summary.getTotalsByBankAccounts();
					distinctFieldRows = new HashMap<Long, HashMap<String, Object>>(VOs.size());
					VOIt = VOs.iterator();
					while (VOIt.hasNext()) {
						MoneyTransferByBankAccountSummaryDetailVO vo = (MoneyTransferByBankAccountSummaryDetailVO) VOIt.next();
						HashMap<String, Object> fieldRow = new HashMap<String, Object>(distinctColumnNames.size());
						Collection addresses = showAddresses ? probandAddressDao.findByProband(vo.getBankAccount().getProband().getId(), null, null, true, null)
								: new ArrayList<ProbandAddress>();
						probandAddressDao.toProbandAddressOutVOCollection(addresses);
						appendDistinctProbandAddressColumnValues(addresses,
								fieldRow,
								aggregateAddresses,
								ReimbursementsExcelWriter.getStreetsColumnName(),
								ReimbursementsExcelWriter.getZipCodesColumnName(),
								ReimbursementsExcelWriter.getCityNamesColumnName());
						distinctFieldRows.put(vo.getId(), fieldRow);
					}
					break;
				default:
					listMoneyTransfers = true;
			}
		} else {
			listMoneyTransfers = true;
		}
		if (listMoneyTransfers) {
			VOs = moneyTransfers;
			moneyTransferDao.toMoneyTransferOutVOCollection(VOs);
			distinctFieldRows = new HashMap<Long, HashMap<String, Object>>(VOs.size());
			VOIt = VOs.iterator();
			while (VOIt.hasNext()) {
				MoneyTransferOutVO vo = (MoneyTransferOutVO) VOIt.next();
				HashMap<String, Object> fieldRow = new HashMap<String, Object>(distinctColumnNames.size());
				Collection addresses = showAddresses ? probandAddressDao.findByProband(vo.getProband().getId(), null, null, true, null) : new ArrayList<ProbandAddress>();
				probandAddressDao.toProbandAddressOutVOCollection(addresses);
				appendDistinctProbandAddressColumnValues(addresses,
						fieldRow,
						aggregateAddresses,
						ReimbursementsExcelWriter.getStreetsColumnName(),
						ReimbursementsExcelWriter.getZipCodesColumnName(),
						ReimbursementsExcelWriter.getCityNamesColumnName());
				distinctFieldRows.put(vo.getId(), fieldRow);
			}
			VOs = new ArrayList<MoneyTransferOutVO>(VOs);
			Collections.sort((List<MoneyTransferOutVO>) VOs, new MoneyTransferOutVOComparator());
		}
		writer.setVOs(VOs);
		writer.setDistinctColumnNames(distinctColumnNames);
		writer.setDistinctFieldRows(distinctFieldRows);
		User user = CoreUtil.getUser();
		writer.getExcelVO().setRequestingUser(userDao.toUserOutVO(user));
		(new ExcelExporter(writer, writer)).write();
		return writer.getExcelVO();
	}

	public static VisitScheduleExcelVO creatVisitScheduleExcel(Collection<VisitScheduleItem> visitScheduleItems, VisitScheduleExcelWriter.Styles style, ProbandOutVO probandVO,
			TrialOutVO trialVO,
			VisitScheduleItemDao visitScheduleItemDao,
			ProbandListStatusEntryDao probandListStatusEntryDao,
			ProbandAddressDao probandAddressDao,
			UserDao userDao) throws Exception {
		boolean passDecryption = CoreUtil.isPassDecryption();
		VisitScheduleExcelWriter writer = new VisitScheduleExcelWriter(!passDecryption, style);
		writer.setTrial(trialVO);
		writer.setProband(probandVO);
		writer.setAddress(probandVO == null ? null : probandAddressDao.toProbandAddressOutVO(probandAddressDao.findByProbandWireTransfer(probandVO.getId())));
		boolean showEnrollmentStatusReason = false;
		boolean showEnrollmentStatus = false;
		boolean showEnrollmentStatusTimestamp = false;
		boolean showEnrollmentStatusTypeIsCount = false;
		boolean showAliquotVisitReimbursement = false;
		boolean showFirstVisitReimbursement = false;
		switch (style) {
			case TRIAL_VISIT_SCHEDULE:
				showEnrollmentStatusReason = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_REASON, Bundle.VISIT_SCHEDULE_EXCEL,
						VisitScheduleExcelDefaultSettings.TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_REASON);
				showEnrollmentStatus = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS, Bundle.VISIT_SCHEDULE_EXCEL,
						VisitScheduleExcelDefaultSettings.TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS);
				showEnrollmentStatusTimestamp = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TIMESTAMP,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TIMESTAMP);
				showEnrollmentStatusTypeIsCount = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TYPE_IS_COUNT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TYPE_IS_COUNT);
				showAliquotVisitReimbursement = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRIAL_VISIT_SCHEDULE_SHOW_ALIQUOT_VISIT_REIMBURSEMENT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.TRIAL_VISIT_SCHEDULE_SHOW_ALIQUOT_VISIT_REIMBURSEMENT);
				showFirstVisitReimbursement = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRIAL_VISIT_SCHEDULE_SHOW_FIRST_VISIT_REIMBURSEMENT, Bundle.VISIT_SCHEDULE_EXCEL,
						VisitScheduleExcelDefaultSettings.TRIAL_VISIT_SCHEDULE_SHOW_FIRST_VISIT_REIMBURSEMENT);
				break;
			case PROBAND_VISIT_SCHEDULE:
				showEnrollmentStatusReason = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_REASON, Bundle.VISIT_SCHEDULE_EXCEL,
						VisitScheduleExcelDefaultSettings.PROBAND_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_REASON);
				showEnrollmentStatus = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS, Bundle.VISIT_SCHEDULE_EXCEL,
						VisitScheduleExcelDefaultSettings.PROBAND_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS);
				showEnrollmentStatusTimestamp = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TIMESTAMP,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.PROBAND_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TIMESTAMP);
				showEnrollmentStatusTypeIsCount = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TYPE_IS_COUNT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.PROBAND_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TYPE_IS_COUNT);
				showAliquotVisitReimbursement = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_VISIT_SCHEDULE_SHOW_ALIQUOT_VISIT_REIMBURSEMENT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.PROBAND_VISIT_SCHEDULE_SHOW_ALIQUOT_VISIT_REIMBURSEMENT);
				showFirstVisitReimbursement = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_VISIT_SCHEDULE_SHOW_FIRST_VISIT_REIMBURSEMENT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.PROBAND_VISIT_SCHEDULE_SHOW_FIRST_VISIT_REIMBURSEMENT);
				break;
			case PROBAND_TRIAL_VISIT_SCHEDULE:
				showEnrollmentStatusReason = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_REASON,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_REASON);
				showEnrollmentStatus = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS, Bundle.VISIT_SCHEDULE_EXCEL,
						VisitScheduleExcelDefaultSettings.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS);
				showEnrollmentStatusTimestamp = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TIMESTAMP,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TIMESTAMP);
				showEnrollmentStatusTypeIsCount = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TYPE_IS_COUNT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TYPE_IS_COUNT);
				showAliquotVisitReimbursement = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_ALIQUOT_VISIT_REIMBURSEMENT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_ALIQUOT_VISIT_REIMBURSEMENT);
				showFirstVisitReimbursement = Settings.getBoolean(VisitScheduleExcelSettingCodes.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_FIRST_VISIT_REIMBURSEMENT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.PROBAND_TRIAL_VISIT_SCHEDULE_SHOW_FIRST_VISIT_REIMBURSEMENT);
				break;
			case TRAVEL_EXPENSES_VISIT_SCHEDULE:
				showEnrollmentStatusReason = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_REASON,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_REASON);
				showEnrollmentStatus = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS, Bundle.VISIT_SCHEDULE_EXCEL,
						VisitScheduleExcelDefaultSettings.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS);
				showEnrollmentStatusTimestamp = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TIMESTAMP,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TIMESTAMP);
				showEnrollmentStatusTypeIsCount = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TYPE_IS_COUNT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_ENROLLMENT_STATUS_TYPE_IS_COUNT);
				showAliquotVisitReimbursement = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_ALIQUOT_VISIT_REIMBURSEMENT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_ALIQUOT_VISIT_REIMBURSEMENT);
				showFirstVisitReimbursement = Settings.getBoolean(VisitScheduleExcelSettingCodes.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_FIRST_VISIT_REIMBURSEMENT,
						Bundle.VISIT_SCHEDULE_EXCEL, VisitScheduleExcelDefaultSettings.TRAVEL_EXPENSES_VISIT_SCHEDULE_SHOW_FIRST_VISIT_REIMBURSEMENT);
				break;
			default:
		}
		ArrayList<String> distinctColumnNames;
		if (passDecryption) {
			distinctColumnNames = new ArrayList<String>(
					(showEnrollmentStatusReason ? 1 : 0) +
					(showEnrollmentStatus ? 1 : 0) +
					(showEnrollmentStatusTimestamp ? 1 : 0) +
					(showEnrollmentStatusTypeIsCount ? 1 : 0) +
					(showAliquotVisitReimbursement ? 1 : 0) +
					(showFirstVisitReimbursement ? 1 : 0));
			if (showEnrollmentStatusReason) {
				distinctColumnNames.add(VisitScheduleExcelWriter.getEnrollmentStatusReasonColumnName());
			}
		} else {
			distinctColumnNames = new ArrayList<String>(
					(showEnrollmentStatus ? 1 : 0) +
					(showEnrollmentStatusTimestamp ? 1 : 0) +
					(showEnrollmentStatusTypeIsCount ? 1 : 0) +
					(showAliquotVisitReimbursement ? 1 : 0) +
					(showFirstVisitRei