/********************************************************************
 * Copyright © 2004-2005 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.common.persistent.person.hibernate;

// Java Classes
import java.io.Serializable;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.Validate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateSystemException;

import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.ee.EnrollmentDetermination;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKey;
import gov.va.med.esr.common.model.person.id.VPIDEntityKey;
import gov.va.med.esr.common.model.person.id.VPIDEntityKeyImpl;
import gov.va.med.esr.common.model.report.ReportSetupLite;
import gov.va.med.esr.common.persistent.person.PersonDAO;
import gov.va.med.esr.service.PersonSearchQueryInfo;
import gov.va.med.fw.model.UserPrincipalImpl;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.persistent.MaxRecordsExceededException;
import gov.va.med.fw.persistent.hibernate.AbstractDAOAction;
import gov.va.med.fw.persistent.hibernate.GenericDAOImpl;
import gov.va.med.fw.persistent.hibernate.PaginatedQueryExecutor;
import gov.va.med.fw.security.UserPrincipal;
import gov.va.med.fw.util.ObjectUtils;
import gov.va.med.fw.util.SortElement;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.ps.model.PersonVPID;

/**
 * This class is a DAO implementation that searches and retries Person objects.
 *
 * @author vhaivmngvs & Andrew Pach
 * @version 3.0
 */
public class PersonDAOImpl extends GenericDAOImpl implements PersonDAO
{
	private static final long serialVersionUID = -477687582162034031L;
    
    private boolean isDataClean = true;
    private static final String GET_BY_VPID = "personQuery_GetByVPID";
    private static final String PARAM_FOR_GET_BY_VPID = "VPIDValue";

    private static final String GET_VPID_BY_PERSONID = "personQuery_GetVPIDByPersonId";
    private static final String GET_PERSONID_BY_VPID = "personQuery_GetPersonIdByVPID";
    private static final String PARAM_PERSONID = "personId";
    private static final String PARAM_VPID = "VPIDValue";
    private static final String PARAM_VOA_IND = "voaInd";
    
    private static final String UPDATE_VOA_IND = "personQuery_UpdateVOAIndicator";

    private static final String GET_VPIDS_BY_PERSONIDS = "personQuery_GetVPIDSByPersonIds";
    private static final String GET_PERSONIDS_BY_VPIDS = "personQuery_GetPersonIdsByVPIDs";
    private static final String PARAM_PERSONIDS = "personIds";
    private static final String PARAM_VPIDS = "VPIDValues";

    private static final String GET_VPIDID_BY_VPIDVALUE = "personVPID_GetByVPID";
    
    
    // Query building fields
    private static final Map uiFieldToColumnMap = new HashMap();

    // Columns
    private static final String COLUMN_PERSON_ID = "p.identifier";
    private static final String COLUMN_VPID_VALUE = "p.VPIDValue";
    private static final String COLUMN_SENSITIVE_RECORD = "p.sensitiveRecord";
    private static final String COLUMN_MILITARY_SERVICE_NUMBER = "mse.serviceNumber";
    private static final String COLUMN_CLAIM_FOLDER_NUMBER = "p.claimFolderNumber";
    private static final String COLUMN_ED_ID = "ed.identifier";

    // Tables
    private static final String TABLE_PERSON = "Person p";
    private static final String TABLE_MILITARY_SERVICE_SITE_RECORDS =
        "p.militaryService.internalMilitaryServiceSiteRecords sites";
    private static final String TABLE_MILITARY_SERVICE_EPISODE =
        "sites.internalMilitaryServiceEpisodes mse";
    private static final String TABLE_ENROLLMENT_DETERMINATION = "p.internalEnrollmentDeterminations ed";

    // Select Clauses
    private static final String SELECT_COUNT_CLAUSE = "SELECT COUNT(*)";
    private static final String SELECT_RETRIEVE_DATA_CLAUSE = "SELECT " + COLUMN_PERSON_ID + ", " +
        COLUMN_VPID_VALUE + ", " + COLUMN_SENSITIVE_RECORD + ", " + COLUMN_ED_ID;

    // From Clauses
    private static final String FROM_PERSON = " FROM " + TABLE_PERSON + " ";
    private static final String FROM_PERSON_ED = FROM_PERSON +
        "LEFT OUTER JOIN " + TABLE_ENROLLMENT_DETERMINATION + " ";
    private static final String SEARCH_FROM_CLAUSE = FROM_PERSON_ED +
        " WHERE " + COLUMN_PERSON_ID + " in (SELECT " + COLUMN_PERSON_ID + FROM_PERSON + " ";
    private static final String FROM_CLAUSE_ADD_MS_JOIN =
        " JOIN " + TABLE_MILITARY_SERVICE_SITE_RECORDS + " JOIN " + TABLE_MILITARY_SERVICE_EPISODE + " ";

    private static final String IS_NULL = "is null";

    // The number of search parameters
    private static final int NUM_SEARCH_PARAMS = 2;

    /**
     * Static initializer to populate a map of UI result columns to database columns.  This is needed for
     * UI column sorting.
     */
    /*
    static
    {
        // Initialize map of UI fields to their respective column names
        // The UI fields are defined as the properties of the vlh:column tag
        // (e.g. <vlh:column property="ssn" ...>)

        // The following is an example of how to add a field to this map
        // uiFieldToColumnMap.put("ssn", COLUMN_SSN);
    }
    */

    /**
     * Method to retrieve a Person by VPID
     *
     * @param key
     *
     * @return
     * @throws DAOException
     */
    public Person getByVPID(VPIDEntityKey key) throws DAOException
    {
    	if(key == null)
    		return null;
    	
        List persons = findByNamedQueryAndNamedParam(GET_BY_VPID, PARAM_FOR_GET_BY_VPID, 
        		VPIDEntityKeyImpl.getLongVPID(key.getVPID())); //11403 - maker sure to get the long vpid
        verifyDataIntegrity(key, persons);
        return (Person) (persons.size() >= 1 ? persons.get(0) : null);
    }
    
    /**
     * @see PersonDAO#getIdsByVPIDs(List)
     */
    public Map getIdsByVPIDs(List vpids) throws DAOException
    {
    	if ( vpids == null || vpids.size() <= 0 )
    	{
    		return null;
    	}
		HashMap resultMap = new HashMap();
		try
        {
			List results = findByNamedQueryAndNamedParam(GET_PERSONIDS_BY_VPIDS,
				PARAM_VPIDS, vpids);

            if ((results == null) || results.isEmpty() )
            {
                return null;
            }
            for ( int i=0; i< results.size();i++)
            {
            	Object[] values = (Object[])results.get(i);
            	String vpid = (String)values[0];
            	BigDecimal personid = (BigDecimal) values[1];
            	resultMap.put(vpid, personid);
            }

		}
        catch (DataAccessException ex)
        {
			throw new DAOException("Failed to get personids by vpids.", ex);
		}
		
        return resultMap;
    }
    
    /**
     * @see PersonDAO#getVPIDsbyIds(List)
     */
    public Map getVPIDsbyIds(List personids) throws DAOException
    {
		
    	if ( personids == null || personids.size() <= 0 )
    	{
    		return null;
    	}

		HashMap resultMap = new HashMap();
		try
        {
			List results = findByNamedQueryAndNamedParam(GET_VPIDS_BY_PERSONIDS,
				PARAM_PERSONIDS, personids);

            if ((results == null) || results.isEmpty() )
            {
                return null;
            }
            for ( int i=0; i< results.size();i++)
            {
            	Object[] values = (Object[])results.get(i);
            	String vpid = (String)values[0];
            	BigDecimal personid = (BigDecimal) values[1];
            	resultMap.put(personid, vpid);
            }

		}
        catch (DataAccessException ex)
        {
			throw new DAOException("Failed to get vpids by personIds.", ex);
		}
		
        return resultMap;
    }
    

    private void verifyDataIntegrity(VPIDEntityKey vpid, List persons) throws DAOException {
        if (persons.size() > 1) {
        	if(isDataClean)
        		throw new DAOException("Found more than one Person for VPID: " + vpid.getVPID());

    		if(logger.isErrorEnabled()) {
    			Object firstObject = persons.get(0);    			
    			Object personId = firstObject;
    			if(firstObject instanceof Person)
    				personId = ((Person) firstObject).getPersonEntityKey().getKeyValueAsString();
    			else if(firstObject instanceof Object[])
    				personId = ((Object[]) firstObject)[0];

    			logger.error("The data is not clean since there is more than one (actually " + persons.size() + ") Person for VPID " +
    					" - arbitrarily choosing first one, it has personId=" + personId);
    		}
        }
    }

    /**
     * Gets a partially built Person object (i.e. the search results) for a VPID Key.
     * @param key The VPID Key
     * @return The partially built Person
     * @throws DAOException If any errors were encountered.
     */
    public Person getSearchResultsByVPID(VPIDEntityKey key) throws DAOException
    {
        try
        {
    		Map contextData = new HashMap();
    		contextData.put("key", 
    				CommonEntityKeyFactory.createVPIDEntityKey(VPIDEntityKeyImpl.getLongVPID(key.getVPID())));	//CCR11403: make sure use long VPID			        		        	
    		HibernateCallback callback = new AbstractDAOAction(contextData) { 
    			public Object execute(Session session) {
    	            // Build the data retrieval query
    	            Query dataQuery = getSearchSelectDataQueryString(session,
    	            		(VPIDEntityKey) getContextData().get("key"));
    	            dataQuery.setFirstResult(0);
    	            dataQuery.setMaxResults(Integer.MAX_VALUE);

    	            return dataQuery.list();    				
    			}
    		};
    		List results = this.getHibernateTemplate().executeFind(callback);
    		
            verifyDataIntegrity(key, results);
            Person person = null;
            if (results.size() >= 1) {
                // Fill in a person object with only the data retrieved from the query
                Object[] data = (Object[]) results.get(0);
                person = buildPersonFromSearchResults(data);
            }

            // Return the built person
            return person;
        }
        catch (HibernateException ex)
        {
            throw new DAOException("An error occurred while getting a Person by VPID " + key.getVPID() + ".", ex);
        }
    }
    
    public void updateVOAIndicator (Person person) throws DAOException 
    {
    	//Original
    	//Query query = super.getSession().getNamedQuery(UPDATE_VOA_IND);
    	//New
		Query query = this.getHibernateTemplate().getSessionFactory().getCurrentSession().getNamedQuery(UPDATE_VOA_IND);
		query.setParameter(PARAM_VOA_IND, person.getVOAIndicator());
		query.setParameter(PARAM_PERSONID, (BigDecimal)person.getEntityKey().getKeyValue());
		int updateCount = query.executeUpdate();                				

		if (updateCount < 1) {
			if(logger.isWarnEnabled())
				logger.warn("Person VOAIndicator not updated with person: " + person.getEntityKey().getKeyValue() + " for msgControlId=" + person.getVOAIndicator());
		}
    	
    }

    /**
     * Builds and returns a Person object with the data that was returned from the search query
     * @param resultData The query results
     * @return The built Person object
     */
    private Person buildPersonFromSearchResults(Object[] resultData)
    {
        Person person = new Person(CommonEntityKeyFactory.createVPIDEntityKey((String)resultData[1]));
        setPersonId(person, (Serializable)resultData[0]);
        person.setSensitiveRecord((Boolean)resultData[2]);
        Serializable enrollmentDeterminationId = (Serializable)resultData[3];
        if (enrollmentDeterminationId != null)
        {
            person.setEnrollmentDetermination(new EnrollmentDetermination());
        }
        return person;
    }

    /**
     * @see gov.va.med.esr.common.persistent.person.PersonDAO#find(PersonSearchQueryInfo)
     */
    public List find(PersonSearchQueryInfo searchQueryInfo) throws DAOException, MaxRecordsExceededException
    {
        try
        {
        	Date startDate = new Date();
        	
    		Map contextData = new HashMap();
    		contextData.put("searchQueryInfo", searchQueryInfo);				        		        	
    		HibernateCallback callback = new AbstractDAOAction(contextData) { 
    			public Object execute(Session session) throws DAOException {
    				PersonSearchQueryInfo targetQueryInfo = (PersonSearchQueryInfo) this.getContextData().get("searchQueryInfo");
    	            // Build the count and data retrieval queries
    	            Query countQuery = getSearchSelectCountQueryString(session, targetQueryInfo);
    	            Query dataQuery = getSearchSelectDataQueryString(session, targetQueryInfo);

    	            // Execute the query to retrieve the results
    	            PaginatedQueryExecutor queryExecutor = new PaginatedQueryExecutor(countQuery, dataQuery, targetQueryInfo);
    	           
    	            try {
    	            	return queryExecutor.executeQuery();
    	            } catch(MaxRecordsExceededException e) {
    	            	throw new DAOException("max records exceeded", e);
    	            }	            
    			}
    		};
    		List results = null;
    		try {
    			results = this.getHibernateTemplate().executeFind(callback);
    		} catch(HibernateSystemException e) {
    			MaxRecordsExceededException rootCause = (MaxRecordsExceededException) getRootExceptionOfType(e, MaxRecordsExceededException.class);
    			if(rootCause != null)
    				throw rootCause;
    			throw e;
    		}    		
    		
            if (logger.isInfoEnabled())
            {
                logger.info("Total time to perform person search: " +
                    (new Date().getTime() - startDate.getTime()) + " ms.");
                logger.info("Size of search results: " + ObjectUtils.getObjectSize(results) + " bytes.");
            }

            // Fill in a person object with only the data retrieved from the query
            List processedResults = new ArrayList(results.size());
            for (int index = 0; index < results.size(); index++)
            {
                Object[] data = (Object[])results.get(index);
                Person person = buildPersonFromSearchResults(data);
                processedResults.add(person);
            }

            // Return the processed results to the caller
            return processedResults;
        }
        catch (HibernateException ex)
        {
            throw new DAOException("An error occurred while finding a person.", ex);
        }
    }

    /**
     * Builds and returns the Hibernate query to retrieve the number of person records.
     *
     * @param searchQueryInfo search parameters
     *
     * @return the count query
     * @throws HibernateException if there were any problems building the query
     */
    private Query getSearchSelectCountQueryString(Session session, PersonSearchQueryInfo searchQueryInfo) throws HibernateException
    {
        // Create parameter and value lists
        ArrayList paramList = new ArrayList(NUM_SEARCH_PARAMS);
        ArrayList valueList = new ArrayList(NUM_SEARCH_PARAMS);

        // Get the count query
        Query query = session.createQuery(getSearchSelectCountClause() +
            getSearchFromClause(searchQueryInfo) +
            getSearchWhereClause(searchQueryInfo, paramList, valueList) + ")");

        // Prepare the count query by filling in the parameters values
        prepareQuery(query, paramList, valueList);

        // Return the final query
        return query;
    }

    /**
     * Builds and returns the Hibernate query to retrieve the partial person data by VPID.
     *
     * @param key VPID Key
     *
     * @return the data query
     * @throws HibernateException if there were any problems building the query
     */
    private Query getSearchSelectDataQueryString(Session session, VPIDEntityKey key) throws HibernateException
    {
        // Create parameter and value lists
        ArrayList paramList = new ArrayList(1);
        ArrayList valueList = new ArrayList(1);

        // Get the count query
        Query query = session.createQuery(getSearchSelectRetrieveDataClause() + FROM_PERSON_ED +
            getSearchWhereClause(key, paramList, valueList));

        // Prepare the query by filling in the parameters values
        prepareQuery(query, paramList, valueList);

        // Return the final query
        return query;
    }

    /**
     * Builds and returns the Hibernate query to retrieve the person data.
     *
     * @param searchQueryInfo search parameters
     *
     * @return the data query
     * @throws HibernateException if there were any problems building the query
     */
    private Query getSearchSelectDataQueryString(Session session, PersonSearchQueryInfo searchQueryInfo) throws HibernateException
    {
        // Create parameter and value lists
        ArrayList paramList = new ArrayList(NUM_SEARCH_PARAMS);
        ArrayList valueList = new ArrayList(NUM_SEARCH_PARAMS);

        // Get the count query
        Query query = session.createQuery(getSearchSelectRetrieveDataClause() +
            getSearchFromClause(searchQueryInfo) +
            getSearchWhereClause(searchQueryInfo, paramList, valueList) +
            getSearchOrderByClause(searchQueryInfo.getSortElements()) + ")");

        // Prepare the count query by filling in the parameters values
        prepareQuery(query, paramList, valueList);

        // Return the final query
        return query;
    }

    /**
     * Builds and returns the search select clause to retrieve data.
     *
     * @return The search select clause to retrieve data.
     */
    private static String getSearchSelectRetrieveDataClause()
    {
        return SELECT_RETRIEVE_DATA_CLAUSE;
    }

    /**
     * Builds and returns the search select clause to retrieve a count of the number of records.
     *
     * @return The select clause to retrieve a count of the number of records.
     */
    private static String getSearchSelectCountClause()
    {
        return SELECT_COUNT_CLAUSE;
    }

    /**
     * Builds and returns the search from clause.
     *
     * @return the search from clause.
     */
    private static String getSearchFromClause(PersonSearchQueryInfo searchInfo)
    {
        String returnClause = SEARCH_FROM_CLAUSE;
        if (!StringUtils.isEmpty(searchInfo.getMilitaryServiceNumber()))
        {
            returnClause += FROM_CLAUSE_ADD_MS_JOIN;
        }
        return returnClause;
    }

    /**
     * Builds and returns the search where clause.
     *
     * @param searchQueryInfo the person search parameter information
     * @param paramList The parameter list
     * @param valueList The value list
     *
     * @return the where clause or the empty string if no parameters are specified.
     */
    private String getSearchWhereClause(PersonSearchQueryInfo searchQueryInfo, List paramList, List valueList)
    {
        ArrayList criteriaList = new ArrayList(NUM_SEARCH_PARAMS);

        StringBuffer clauseBuffer = new StringBuffer();

        // Fetch individual search parameters
        String militaryServiceNumber = StringUtils.trimToNull(searchQueryInfo.getMilitaryServiceNumber());
        String cliamFolderNumber = StringUtils.trimToNull(searchQueryInfo.getClaimFolderNumber());

        boolean caseSensitive = searchQueryInfo.getCaseSensitive();
        boolean removeEmptyStrings = searchQueryInfo.getRemoveEmptyStrings();

        // Build the criteria lists
        if (militaryServiceNumber == null)
        {
            if (!removeEmptyStrings)
            {
                criteriaList.add(COLUMN_MILITARY_SERVICE_NUMBER + " " + IS_NULL);
            }
        }
        else
        {
            criteriaList.add(caseSensitive ? COLUMN_MILITARY_SERVICE_NUMBER + " = :militaryServiceNumber" :
                "upper(" + COLUMN_MILITARY_SERVICE_NUMBER + ") = upper(:militaryServiceNumber)");
            paramList.add("militaryServiceNumber");
            valueList.add(militaryServiceNumber);
        }

        if (cliamFolderNumber == null)
        {
            if (!removeEmptyStrings)
            {
                criteriaList.add(COLUMN_CLAIM_FOLDER_NUMBER + " " + IS_NULL);
            }
        }
        else
        {
            criteriaList.add(COLUMN_CLAIM_FOLDER_NUMBER + " = :cliamFolderNumber");
            paramList.add("cliamFolderNumber");
            valueList.add(cliamFolderNumber);
        }

        // Build the where clause based on the parameters
        if (paramList.size() > 0)
        {
            clauseBuffer.append(" WHERE ").append(criteriaList.get(0));

            for (int index = 1; index < criteriaList.size(); index++)
            {
                clauseBuffer.append(" AND ").append(criteriaList.get(index));
            }
        }
        return clauseBuffer.toString();
    }

    /**
     * Builds and returns the search where clause based on a VPID Key.
     *
     * @param key the VPID key
     * @param paramList The parameter list
     * @param valueList The value list
     *
     * @return the where clause or the empty string if no parameters are specified.
     */
    private String getSearchWhereClause(VPIDEntityKey key, List paramList, List valueList)
    {
        paramList.add("VPIDValue");
        valueList.add(key.getVPID());
        return " WHERE " + COLUMN_VPID_VALUE + " = :VPIDValue";
    }

    /**
     * Builds and returns the search order by clause.
     *
     * @param sortElements the columns and directions to sort on.  If null is passed in, the empty string will be
     * returned.
     *
     * @return the order by clause or the empty string.
     */
    private String getSearchOrderByClause(List sortElements)
    {
        // Create the order by clause if at least one sort column was specified
        StringBuffer clauseBuffer = new StringBuffer();
        if (sortElements != null)
        {
            for (Iterator iterator = sortElements.iterator(); iterator.hasNext();)
            {
                // Get the GUI sort column
                SortElement sortElement = (SortElement)iterator.next();

                // Get the database column associated with the GUI column
                String databaseColumn = (String)uiFieldToColumnMap.get(sortElement.getSortColumn());

                // If a database column exists for the GUI column, add it to the clause
                if (databaseColumn != null)
                {
                    if (clauseBuffer.length() > 0)
                    {
                        clauseBuffer.append(", ").append(databaseColumn).append(" ").append(sortElement.getSortDirection());
                    }
                    else
                    {
                        clauseBuffer.append(" ORDER BY ").append(databaseColumn).append(" ").append(sortElement.getSortDirection());
                    }
                }
                else
                {
                    // A GUI sort column is not supported by the database so don't implement the
                    // sort.  This will cause the PaginatedQueryExecutor to read all the records
                    // and require the GUI to handle the sorting.
                    return "";
                }
            }
        }

        // Return the clause
        return clauseBuffer.toString();
    }

    /**
     * Prepares a query by setting parameters in the parameter list with the values in the value list.
     *
     * @param query The query to prepare
     * @param paramList The list of parameters
     * @param valueList The list of parameter values
     *
     * @throws HibernateException if there was a problem setting the parameters
     */
    private void prepareQuery(Query query, List paramList, List valueList) throws HibernateException
    {
        for (int i = 0; i < paramList.size(); i++)
        {
            query.setParameter((String)paramList.get(i), valueList.get(i));
        }
    }

    private void setPersonId(Person person, Serializable id)
    {
        try
        {
            Class clazz = Class.forName("gov.va.med.fw.model.AbstractKeyedEntity");
            Method method = clazz.getDeclaredMethod("setIdentifier", new Class[] {Serializable.class});
            method.setAccessible(true);
            method.invoke(person, new Object[] {id});
        }
        catch (Exception e)
        {
            throw new RuntimeException("Unable to set identifier.", e);
        }
    }

	/**
	 * @return Returns the isDataClean.
	 */
	public boolean isDataClean() {
		return isDataClean;
	}

	/**
	 * @param isDataClean The isDataClean to set.
	 */
	public void setIsDataClean(boolean isDataClean) {
		this.isDataClean = isDataClean;
	}

	/**
	 * Performs a lookup to get VPID using a PersonId
	 *
	 * @param personId
	 * @return
	 * @throws DAOException
	 */
	public VPIDEntityKey getVPIDByPersonId(PersonIdEntityKey personId) throws DAOException
    {
		Validate.notNull(personId, "NULL personId not allowed.");

		try
        {
			List results = findByNamedQueryAndNamedParam(GET_VPID_BY_PERSONID,
				PARAM_PERSONID, new BigDecimal(personId.getKeyValueAsString()));

            if ((results == null) || results.isEmpty() || (!(results.get(0) instanceof String)))
            {
                // ***** REVISIT *****
                // Should we throw an exception here instead?
                return null;
            }

            return CommonEntityKeyFactory.createVPIDEntityKey((String)results.get(0));

		}
        catch (DataAccessException ex)
        {
			throw new DAOException("Failed to get VPIDEntityKey by personId.", ex);
		}
		
	}

	/**
	 * Performs a lookup to get PersonId using a VPID
	 *
	 * @param vpid
	 * @return
	 * @throws DAOException
	 */
	public PersonIdEntityKey getPersonIdByVPID(VPIDEntityKey vpid)
			throws DAOException {
		try
        {
			List results = findByNamedQueryAndNamedParam(GET_PERSONID_BY_VPID, PARAM_VPID, 
					VPIDEntityKeyImpl.getLongVPID(vpid.getVPID())); //CCR11403: make sure it's long vpid

			verifyDataIntegrity(vpid, results);

            if ((results == null) || results.isEmpty() || (!(results.get(0) instanceof BigDecimal)))
            {
                // ***** REVISIT *****
                // Should we throw an exception here instead?
                return null;
            }

            return CommonEntityKeyFactory.createPersonIdEntityKey((BigDecimal)results.get(0));
		}
        catch (DataAccessException ex)
        {
			throw new DAOException("Failed to getPersonIdEntityKey by VPID.", ex);
		}
	}

	public PersonVPID getPersonVPIDByVpidValue(VPIDEntityKey vpid) throws DAOException {
			
		String vpidValue = ((VPIDEntityKeyImpl)vpid).getLongVPID();
		try {			
			Map contextData = new HashMap();
			contextData.put(PARAM_VPID, vpidValue);				        		        	
			HibernateCallback callback = new AbstractDAOAction(contextData) { 
				public Object execute(Session session) {
				    Query query = session.getNamedQuery(GET_VPIDID_BY_VPIDVALUE);
				    session.createQuery(query.getQueryString());
	   	            query.setString(PARAM_VPID, (String) getContextData().get(PARAM_VPID));
    	            return query.setMaxResults(1).uniqueResult();    				
				}
			};			
			 return (PersonVPID) this.getHibernateTemplate().execute(callback);			
		}catch(DataAccessException e) {
			throw new DAOException("Failed to get PersonVPID By VPIDValue",e);
		}
	}
}
