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

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;

import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.phoenixctms.ctsms.query.CriteriaUtil;
import org.phoenixctms.ctsms.query.SubCriteriaMap;
import org.phoenixctms.ctsms.security.CipherText;
import org.phoenixctms.ctsms.security.CryptoUtil;
import org.phoenixctms.ctsms.security.reencrypt.FieldReEncrypter;
import org.phoenixctms.ctsms.security.reencrypt.ReEncrypter;
import org.phoenixctms.ctsms.util.CommonUtil;
import org.phoenixctms.ctsms.util.CoreUtil;
import org.phoenixctms.ctsms.util.DefaultMessages;
import org.phoenixctms.ctsms.util.L10nUtil;
import org.phoenixctms.ctsms.util.MessageCodes;
import org.phoenixctms.ctsms.vo.BankAccountInVO;
import org.phoenixctms.ctsms.vo.BankAccountOutVO;
import org.phoenixctms.ctsms.vo.PSFVO;
import org.phoenixctms.ctsms.vo.ProbandOutVO;
import org.phoenixctms.ctsms.vo.UserOutVO;

/**
 * @see BankAccount
 */
public class BankAccountDaoImpl
		extends BankAccountDaoBase {

	private static final String BANK_ACCOUNT_NAME = "{0} - {1}/{2}";
	private static final String BANK_ACCOUNT_NAME_NA = "{0} - n/a";

	private static final String getBankAccountName(BankAccountOutVO bankAccount) {
		if (bankAccount != null) {
			if (bankAccount.isDecrypted()) {
				if (bankAccount.getNa()) {
					return MessageFormat.format(BANK_ACCOUNT_NAME_NA, CommonUtil.probandOutVOToString(bankAccount.getProband()));
				} else {
					String iban = bankAccount.getIban();
					String accountNumber = bankAccount.getAccountNumber();
					if (!CommonUtil.isEmptyString(iban)) {
						return MessageFormat.format(BANK_ACCOUNT_NAME, bankAccount.getAccountHolderName(), iban, bankAccount.getBic());
					} else if (!CommonUtil.isEmptyString(accountNumber)) {
						return MessageFormat.format(BANK_ACCOUNT_NAME, bankAccount.getAccountHolderName(), accountNumber, bankAccount.getBankCodeNumber());
					}
				}
			} else {
				return L10nUtil.getString(MessageCodes.ENCRYPTED_BANK_ACCOUNT_NAME, DefaultMessages.ENCRYPTED_BANK_ACCOUNT_NAME);
			}
		}
		return null;
	}

	private final static Collection<ReEncrypter<BankAccount>> RE_ENCRYPTERS = new ArrayList<ReEncrypter<BankAccount>>();
	static {
		RE_ENCRYPTERS.add(new FieldReEncrypter<BankAccount>() {

			@Override
			protected byte[] getIv(BankAccount item) {
				return item.getAccountHolderNameIv();
			}

			@Override
			protected byte[] getEncrypted(BankAccount item) {
				return item.getEncryptedAccountHolderName();
			}

			@Override
			protected void setIv(BankAccount item, byte[] iv) {
				item.setAccountHolderNameIv(iv);
			}

			@Override
			protected void setEncrypted(BankAccount item, byte[] cipherText) {
				item.setEncryptedAccountHolderName(cipherText);
			}

			@Override
			protected void setHash(BankAccount item, byte[] hash) {
				item.setAccountHolderNameHash(hash);
			}
		});
		RE_ENCRYPTERS.add(new FieldReEncrypter<BankAccount>() {

			@Override
			protected byte[] getIv(BankAccount item) {
				return item.getAccountNumberIv();
			}

			@Override
			protected byte[] getEncrypted(BankAccount item) {
				return item.getEncryptedAccountNumber();
			}

			@Override
			protected void setIv(BankAccount item, byte[] iv) {
				item.setAccountNumberIv(iv);
			}

			@Override
			protected void setEncrypted(BankAccount item, byte[] cipherText) {
				item.setEncryptedAccountNumber(cipherText);
			}

			@Override
			protected void setHash(BankAccount item, byte[] hash) {
				item.setAccountNumberHash(hash);
			}
		});
		RE_ENCRYPTERS.add(new FieldReEncrypter<BankAccount>() {

			@Override
			protected byte[] getIv(BankAccount item) {
				return item.getBankCodeNumberIv();
			}

			@Override
			protected byte[] getEncrypted(BankAccount item) {
				return item.getEncryptedBankCodeNumber();
			}

			@Override
			protected void setIv(BankAccount item, byte[] iv) {
				item.setBankCodeNumberIv(iv);
			}

			@Override
			protected void setEncrypted(BankAccount item, byte[] cipherText) {
				item.setEncryptedBankCodeNumber(cipherText);
			}

			@Override
			protected void setHash(BankAccount item, byte[] hash) {
				item.setBankCodeNumberHash(hash);
			}
		});
		RE_ENCRYPTERS.add(new FieldReEncrypter<BankAccount>() {

			@Override
			protected byte[] getIv(BankAccount item) {
				return item.getBankNameIv();
			}

			@Override
			protected byte[] getEncrypted(BankAccount item) {
				return item.getEncryptedBankName();
			}

			@Override
			protected void setIv(BankAccount item, byte[] iv) {
				item.setBankNameIv(iv);
			}

			@Override
			protected void setEncrypted(BankAccount item, byte[] cipherText) {
				item.setEncryptedBankName(cipherText);
			}

			@Override
			protected void setHash(BankAccount item, byte[] hash) {
				item.setBankNameHash(hash);
			}
		});
		RE_ENCRYPTERS.add(new FieldReEncrypter<BankAccount>() {

			@Override
			protected byte[] getIv(BankAccount item) {
				return item.getBicIv();
			}

			@Override
			protected byte[] getEncrypted(BankAccount item) {
				return item.getEncryptedBic();
			}

			@Override
			protected void setIv(BankAccount item, byte[] iv) {
				item.setBicIv(iv);
			}

			@Override
			protected void setEncrypted(BankAccount item, byte[] cipherText) {
				item.setEncryptedBic(cipherText);
			}

			@Override
			protected void setHash(BankAccount item, byte[] hash) {
				item.setBicHash(hash);
			}
		});
		RE_ENCRYPTERS.add(new FieldReEncrypter<BankAccount>() {

			@Override
			protected byte[] getIv(BankAccount item) {
				return item.getIbanIv();
			}

			@Override
			protected byte[] getEncrypted(BankAccount item) {
				return item.getEncryptedIban();
			}

			@Override
			protected void setIv(BankAccount item, byte[] iv) {
				item.setIbanIv(iv);
			}

			@Override
			protected void setEncrypted(BankAccount item, byte[] cipherText) {
				item.setEncryptedIban(cipherText);
			}

			@Override
			protected void setHash(BankAccount item, byte[] hash) {
				item.setIbanHash(hash);
			}
		});
	}

	@Override
	protected Collection<ReEncrypter<BankAccount>> getReEncrypters() {
		return RE_ENCRYPTERS;
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public BankAccount bankAccountInVOToEntity(BankAccountInVO bankAccountInVO) {
		BankAccount entity = this.loadBankAccountFromBankAccountInVO(bankAccountInVO);
		this.bankAccountInVOToEntity(bankAccountInVO, entity, true);
		return entity;
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void bankAccountInVOToEntity(
			BankAccountInVO source,
			BankAccount target,
			boolean copyIfNull) {
		super.bankAccountInVOToEntity(source, target, copyIfNull);
		Long probandId = source.getProbandId();
		if (probandId != null) {
			Proband proband = this.getProbandDao().load(probandId);
			target.setProband(proband);
			proband.addBankAccounts(target);
		} else if (copyIfNull) {
			Proband proband = target.getProband();
			target.setProband(null);
			if (proband != null) {
				proband.removeBankAccounts(target);
			}
		}
		try {
			if (copyIfNull || source.getAccountHolderName() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getAccountHolderName());
				target.setAccountHolderNameIv(cipherText.getIv());
				target.setEncryptedAccountHolderName(cipherText.getCipherText());
				target.setAccountHolderNameHash(CryptoUtil.hashForSearch(source.getAccountHolderName()));
			}
			if (copyIfNull || source.getAccountNumber() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getAccountNumber());
				target.setAccountNumberIv(cipherText.getIv());
				target.setEncryptedAccountNumber(cipherText.getCipherText());
				target.setAccountNumberHash(CryptoUtil.hashForSearch(source.getAccountNumber()));
			}
			if (copyIfNull || source.getBankCodeNumber() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getBankCodeNumber());
				target.setBankCodeNumberIv(cipherText.getIv());
				target.setEncryptedBankCodeNumber(cipherText.getCipherText());
				target.setBankCodeNumberHash(CryptoUtil.hashForSearch(source.getBankCodeNumber()));
			}
			if (copyIfNull || source.getBankName() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getBankName());
				target.setBankNameIv(cipherText.getIv());
				target.setEncryptedBankName(cipherText.getCipherText());
				target.setBankNameHash(CryptoUtil.hashForSearch(source.getBankName()));
			}
			if (copyIfNull || source.getBic() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getBic());
				target.setBicIv(cipherText.getIv());
				target.setEncryptedBic(cipherText.getCipherText());
				target.setBicHash(CryptoUtil.hashForSearch(source.getBic()));
			}
			if (copyIfNull || source.getIban() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getIban());
				target.setIbanIv(cipherText.getIv());
				target.setEncryptedIban(cipherText.getCipherText());
				target.setIbanHash(CryptoUtil.hashForSearch(source.getIban()));
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public BankAccount bankAccountOutVOToEntity(BankAccountOutVO bankAccountOutVO) {
		BankAccount entity = this.loadBankAccountFromBankAccountOutVO(bankAccountOutVO);
		this.bankAccountOutVOToEntity(bankAccountOutVO, entity, true);
		return entity;
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void bankAccountOutVOToEntity(
			BankAccountOutVO source,
			BankAccount target,
			boolean copyIfNull) {
		super.bankAccountOutVOToEntity(source, target, copyIfNull);
		ProbandOutVO probandVO = source.getProband();
		UserOutVO modifiedUserVO = source.getModifiedUser();
		if (probandVO != null) {
			Proband proband = this.getProbandDao().probandOutVOToEntity(probandVO);
			target.setProband(proband);
			proband.addBankAccounts(target);
		} else if (copyIfNull) {
			Proband proband = target.getProband();
			target.setProband(null);
			if (proband != null) {
				proband.removeBankAccounts(target);
			}
		}
		if (modifiedUserVO != null) {
			target.setModifiedUser(this.getUserDao().userOutVOToEntity(modifiedUserVO));
		} else if (copyIfNull) {
			target.setModifiedUser(null);
		}
		try {
			if (copyIfNull || source.getAccountHolderName() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getAccountHolderName());
				target.setAccountHolderNameIv(cipherText.getIv());
				target.setEncryptedAccountHolderName(cipherText.getCipherText());
				target.setAccountHolderNameHash(CryptoUtil.hashForSearch(source.getAccountHolderName()));
			}
			if (copyIfNull || source.getAccountNumber() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getAccountNumber());
				target.setAccountNumberIv(cipherText.getIv());
				target.setEncryptedAccountNumber(cipherText.getCipherText());
				target.setAccountNumberHash(CryptoUtil.hashForSearch(source.getAccountNumber()));
			}
			if (copyIfNull || source.getBankCodeNumber() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getBankCodeNumber());
				target.setBankCodeNumberIv(cipherText.getIv());
				target.setEncryptedBankCodeNumber(cipherText.getCipherText());
				target.setBankCodeNumberHash(CryptoUtil.hashForSearch(source.getBankCodeNumber()));
			}
			if (copyIfNull || source.getBankName() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getBankName());
				target.setBankNameIv(cipherText.getIv());
				target.setEncryptedBankName(cipherText.getCipherText());
				target.setBankNameHash(CryptoUtil.hashForSearch(source.getBankName()));
			}
			if (copyIfNull || source.getBic() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getBic());
				target.setBicIv(cipherText.getIv());
				target.setEncryptedBic(cipherText.getCipherText());
				target.setBicHash(CryptoUtil.hashForSearch(source.getBic()));
			}
			if (copyIfNull || source.getIban() != null) {
				CipherText cipherText = CryptoUtil.encryptValue(source.getIban());
				target.setIbanIv(cipherText.getIv());
				target.setEncryptedIban(cipherText.getCipherText());
				target.setIbanHash(CryptoUtil.hashForSearch(source.getIban()));
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private org.hibernate.Criteria createBankAccountCriteria() {
		org.hibernate.Criteria bankAccountCriteria = this.getSession().createCriteria(BankAccount.class);
		bankAccountCriteria.setCacheable(true);
		return bankAccountCriteria;
	}

	/**
	 * @throws Exception
	 * @inheritDoc
	 */
	@Override
	protected Collection<BankAccount> handleFindByProband(Long probandId, Boolean active, Boolean na, PSFVO psf) throws Exception {
		org.hibernate.Criteria bankAccountCriteria = createBankAccountCriteria();
		SubCriteriaMap criteriaMap = new SubCriteriaMap(BankAccount.class, bankAccountCriteria);
		if (probandId != null) {
			bankAccountCriteria.add(Restrictions.eq("proband.id", probandId.longValue()));
		}
		if (active != null) {
			bankAccountCriteria.add(Restrictions.eq("active", active.booleanValue()));
		}
		if (na != null) {
			bankAccountCriteria.add(Restrictions.eq("na", na.booleanValue()));
		}
		CriteriaUtil.applyPSFVO(criteriaMap, psf);
		return bankAccountCriteria.list();
	}

	@Override
	protected Collection<BankAccount> handleFindByProbandActiveId(Long probandId, Boolean active, Long bankAccountId) {
		org.hibernate.Criteria bankAccountCriteria = createBankAccountCriteria();
		if (probandId != null) {
			bankAccountCriteria.add(Restrictions.eq("proband.id", probandId.longValue()));
		}
		CriteriaUtil.applyVisibleIdCriterion("active", bankAccountCriteria, active, bankAccountId);
		return bankAccountCriteria.list();
	}

	@Override
	protected long handleGetCount(Long probandId) throws Exception {
		org.hibernate.Criteria bankAccountCriteria = createBankAccountCriteria();
		if (probandId != null) {
			bankAccountCriteria.add(Restrictions.eq("proband.id", probandId.longValue()));
		}
		return (Long) bankAccountCriteria.setProjection(Projections.rowCount()).uniqueResult();
	}

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

	/**
	 * Retrieves the entity object that is associated with the specified value object
	 * from the object store. If no such entity object exists in the object store,
	 * a new, blank entity is created
	 */
	private BankAccount loadBankAccountFromBankAccountOutVO(BankAccountOutVO bankAccountOutVO) {
		BankAccount bankAccount = this.load(bankAccountOutVO.getId());
		if (bankAccount == null) {
			bankAccount = BankAccount.Factory.newInstance();
		}
		return bankAccount;
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public BankAccountInVO toBankAccountInVO(final BankAccount entity) {
		return super.toBankAccountInVO(entity);
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void toBankAccountInVO(
			BankAccount source,
			BankAccountInVO target) {
		super.toBankAccountInVO(source, target);
		Proband proband = source.getProband();
		if (proband != null) {
			target.setProbandId(proband.getId());
		}
		try {
			target.setAccountHolderName((String) CryptoUtil.decryptValue(source.getAccountHolderNameIv(), source.getEncryptedAccountHolderName()));
			target.setAccountNumber((String) CryptoUtil.decryptValue(source.getAccountNumberIv(), source.getEncryptedAccountNumber()));
			target.setBankCodeNumber((String) CryptoUtil.decryptValue(source.getBankCodeNumberIv(), source.getEncryptedBankCodeNumber()));
			target.setBankName((String) CryptoUtil.decryptValue(source.getBankNameIv(), source.getEncryptedBankName()));
			target.setBic((String) CryptoUtil.decryptValue(source.getBicIv(), source.getEncryptedBic()));
			target.setIban((String) CryptoUtil.decryptValue(source.getIbanIv(), source.getEncryptedIban()));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public BankAccountOutVO toBankAccountOutVO(final BankAccount entity) {
		return super.toBankAccountOutVO(entity);
	}

	/**
	 * @inheritDoc
	 */
	@Override
	public void toBankAccountOutVO(
			BankAccount source,
			BankAccountOutVO target) {
		super.toBankAccountOutVO(source, target);
		Proband proband = source.getProband();
		User modifiedUser = source.getModifiedUser();
		if (proband != null) {
			target.setProband(this.getProbandDao().toProbandOutVO(proband));
		}
		if (modifiedUser != null) {
			target.setModifiedUser(this.getUserDao().toUserOutVO(modifiedUser));
		}
		try {
			if (!CoreUtil.isPassDecryption()) {
				throw new Exception();
			}
			target.setAccountHolderName((String) CryptoUtil.decryptValue(source.getAccountHolderNameIv(), source.getEncryptedAccountHolderName()));
			target.setAccountNumber((String) CryptoUtil.decryptValue(source.getAccountNumberIv(), source.getEncryptedAccountNumber()));
			target.setBankCodeNumber((String) CryptoUtil.decryptValue(source.getBankCodeNumberIv(), source.getEncryptedBankCodeNumber()));
			target.setBankName((String) CryptoUtil.decryptValue(source.getBankNameIv(), source.getEncryptedBankName()));
			target.setBic((String) CryptoUtil.decryptValue(source.getBicIv(), source.getEncryptedBic()));
			target.setIban((String) CryptoUtil.decryptValue(source.getIbanIv(), source.getEncryptedIban()));
			target.setDecrypted(true);
		} catch (Exception e) {
			target.setAccountHolderName(null);
			target.setAccountNumber(null);
			target.setBankCodeNumber(null);
			target.setBankName(null);
			target.setBic(null);
			target.setIban(null);
			target.setDecrypted(false);
		}
		target.setName(getBankAccountName(target));
	}
}