// Package 
package gov.va.med.esr.service.impl;

// Java Classes
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import gov.va.med.esr.common.infra.ImpreciseDate;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.lookup.NameType;
import gov.va.med.esr.common.model.lookup.SSNType;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.messaging.SiteIdentity;
import gov.va.med.esr.common.model.person.BirthRecord;
import gov.va.med.esr.common.model.person.Name;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.model.person.id.VPIDEntityKey;
import gov.va.med.esr.service.PersonIdentityTraits;
import gov.va.med.fw.persistent.DAOOperations;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.util.StringUtils;

/**
 * This mock service alllows to retrive data from PSIM tables directly
 * 
 * Created Sep 20, 2005 4:11:27 PM
 *
 * @author Madhu Katikala
 * 
 */
public class LocalPSDelegateServiceImpl extends PSDelegateServiceImpl
{    
    private static final long serialVersionUID = -6579651998941450963L;

    private DAOOperations genericDAO = null;
    
    private String selectAndFromClause = "select VPID_ID, VPID_VALUE," +
        "FIRST_NAME,MIDDLE_NAME,LAST_NAME,PREFIX,SUFFIX," +
        "SSN,SSN_TYPE_CODE,PSEUDO_SSN_REASON_CODE," +
        "SSN_VRFN_STATUS_CODE,SSA_SENT_DATE,SSA_RECEIVED_DATE,SSA_VERIFIED_DATE," +
        "GENDER_CODE,DATE_OF_BIRTH,RECORD_CREATED_BY,RECORD_CREATED_DATE," +
        "RECORD_MODIFIED_BY,RECORD_MODIFIED_DATE,SSAVERIFCODE_CODE from rpt_psim_traits ";
    
    private String selectAndFromClauseForDfn = "select v.vpid_value vpid_value from " +
        "ps_person_vpid v, ps_person_correlation ps_corr, ps_system_of_interest_type sys_int, std_institution inst " +
        "WHERE ps_corr.person_vpid_id = v.ps_personvpid_id " + 
        "and ps_corr.system_of_interest_type_id = sys_int.id " +
        "and sys_int.institution_id = inst.id " +
        "and inst.stationnumber='STATIONNUMBER' " +  
        "and ps_corr.ALTKEY1_TEXT = 'DFN' ";
     
    private String selectAndFromClauseForSites = 
        "select inst.stationnumber stationnumber, ps_corr.ALTKEY1_TEXT dfn " +
        "from ps_person_vpid v, ps_person_correlation ps_corr, " + 
        "ps_system_of_interest_type sys_int, std_institution inst " +
        "WHERE  ps_corr.person_vpid_id = v.ps_personvpid_id " +
        "and ps_corr.system_of_interest_type_id = sys_int.id " +
        "and sys_int.institution_id = inst.id and v.vpid_value  = 'VPID_VALUE' " +
        "and inst.stationnumber not like '200%'";
            
    public DAOOperations getGenericDAO() throws ServiceException{
        if(genericDAO == null) {
            genericDAO = (DAOOperations)this.getComponent("genericDAO");
        }
        return this.genericDAO;
    }

    public void setGenericDAO(DAOOperations genericDAO) {
        this.genericDAO = genericDAO;
    }

    public PersonIdentityTraits getIdentityTraits(VPIDEntityKey key)
        throws ServiceException
    {
        if (key == null) return null;
        logger.info("Searching for Identity Traits for VPID :" + key.getVPID());

        // always return same set of identity traits
        String whereClause = " where VPID_VALUE = '" + key.getVPID() + "'";
        String query = selectAndFromClause + whereClause;
        try {
            List results = getGenericDAO().executeSQLQuery(query);
            for (Iterator i=results.iterator(); i.hasNext();){
                Object[] objectArray = (Object[])(i.next());
                PersonIdentityTraits personIdentityTraits = createPersonTraits(objectArray);
                return personIdentityTraits;
            }
        }catch (Exception e){
            throw new ServiceException("Generic DAO query of psim traits failed ",e);
        }
        return null;
    }

    public PersonIdentityTraits getIdentityTraits(String dfn,
        String stationNumber) throws ServiceException
    {
        if (dfn == null || stationNumber == null) return null; 
        logger.info("Searching for Identity Traits for dfn and station number :" + dfn + "/" + stationNumber);
        return getIdentityTraits(getVPID(dfn,stationNumber));
    }

    public Map getIdentityTraits(Collection vpidEntityKeys) throws ServiceException
    {
        Map identityTraits = new HashMap();
        for (Iterator iter = vpidEntityKeys.iterator(); iter.hasNext();) {
            VPIDEntityKey vpidKey = (VPIDEntityKey)iter.next();            
            identityTraits.put(vpidKey.getKeyValueAsString(), getIdentityTraits(vpidKey));
        }
        return identityTraits;
    }

    /**
     * Only the first VPID that matched is returned when multiple records are found
     * @see gov.va.med.esr.service.PSDelegateService#getVPID(java.lang.String,
     *      java.lang.String)
     */
    public VPIDEntityKey getVPID(String dfn, String stationNumber)
        throws ServiceException
    {
        String sqlQuery = selectAndFromClauseForDfn;
        sqlQuery = sqlQuery.replaceAll("STATIONNUMBER",stationNumber);
        sqlQuery = sqlQuery.replaceAll("DFN",dfn);
        try {
        List results = getGenericDAO().executeSQLQuery(sqlQuery);
        for (Iterator i=results.iterator(); i.hasNext();){
            String vpid_value = (String)(i.next());
            return (CommonEntityKeyFactory.createVPIDEntityKey(vpid_value));
        }
        } catch (Exception e){
            throw new ServiceException("Generic DAO query of psim traits failed ",e);
        }
        return null;
    }

    /**
     * @see gov.va.med.esr.service.PSDelegateService#getVPID(java.lang.String,
     *      java.lang.String)
     */
    public Set getSites(VPIDEntityKey key)
        throws ServiceException
    {               
        Set sites = new HashSet();
        if (key == null) return sites;
        logger.info("Searching for sites for VPID :" + key.getVPID());
        String query = selectAndFromClauseForSites;
        query = query.replaceAll("VPID_VALUE",key.getVPID());
        try {
            List results = getGenericDAO().executeSQLQuery(query);
            for (Iterator i=results.iterator(); i.hasNext();){
                Object[] objectArray = (Object[])(i.next());
                SiteIdentity siteIdentity = new SiteIdentity();
                siteIdentity.setDfn((String)objectArray[1]);
                VAFacility facility = getLookupService().getVaFacilityByStationNumber((String)objectArray[0]);
                siteIdentity.setVaFacility(facility);
                sites.add(siteIdentity);
            }
        }catch (Exception e){
            throw new ServiceException("Generic DAO query of psim traits failed ",e);
        }
        return sites;
    }

    public Set attendedSearch(PersonIdentityTraits traits, boolean enforceESRSecurity) throws ServiceException {
        return this.attendedSearch(traits);
    }
    
    /**
     * @see gov.va.med.esr.service.PSDelegateService#attendedSearch
     */
    public Set attendedSearch(PersonIdentityTraits criteria) throws ServiceException
    {
        Set results = new HashSet();
        StringBuffer whereClause = new StringBuffer(" where 1 = 1 ");
        
        if(StringUtils.isNotEmpty(criteria.getSsnText())) {
            whereClause.append(" AND SSN = '" + criteria.getSsnText() + "'");
        }
        
        Name name = criteria.getLegalName();
        if(name != null) {
            if(StringUtils.isNotEmpty(name.getGivenName())) {
                whereClause.append(" AND FIRST_NAME = '" + name.getGivenName().toUpperCase() + "'");
            }
            if(StringUtils.isNotEmpty(name.getFamilyName())) {
                whereClause.append(" AND LAST_NAME = '" + name.getFamilyName().toUpperCase() + "'");
            }
        }
        String query = selectAndFromClause + whereClause;
        try {
            List list = getGenericDAO().executeSQLQuery(query);
            for (Iterator i=list.iterator(); i.hasNext();){
                Object[] objectArray = (Object[])(i.next());
                PersonIdentityTraits personIdentityTraits = createPersonTraits(objectArray);
                results.add(personIdentityTraits);
            }
        }catch (Exception e){
            throw new ServiceException("Generic DAO query of psim traits failed ",e);
        }

        return results;
    }

    /**
     * @see gov.va.med.esr.service.impl.PSDelegateServiceImpl#unattendedSearch(gov.va.med.esr.service.PersonIdentityTraits)
     */
    public Set unattendedSearch(PersonIdentityTraits traits) throws ServiceException
    {
        return attendedSearch(traits);
    }

    /**
     * Gets history of updates to identity traits
     */
    public List getIdentityTraitsUpdateHistory(VPIDEntityKey key) throws ServiceException
    {
        List historyList = new ArrayList();
        PersonIdentityTraits personTraits = getIdentityTraits(key);
        historyList.add(personTraits);
        return historyList;
    }

    private PersonIdentityTraits createPersonTraits(Object[] traitsData)
        throws Exception
    {
        PersonIdentityTraits traits = new PersonIdentityTraits();        
        VPIDEntityKey VPIDEntityKey = 
            CommonEntityKeyFactory.createVPIDEntityKey((String)traitsData[1]);
        traits.setVpid(VPIDEntityKey);

        Name legalName = new Name();
        legalName.setGivenName((String)traitsData[2]);
        legalName.setMiddleName((String)traitsData[3]);
        legalName.setFamilyName((String)traitsData[4]);
        legalName.setPrefix((String)traitsData[5]);
        legalName.setSuffix((String)traitsData[6]);
        legalName.setType(getLookupService().getNameTypeByCode(NameType.LEGAL_NAME.getName()));
        traits.addName(legalName);
    
        SSN ssn = new SSN();
        ssn.setSsnText((String)traitsData[7]);
        String raw = (String) traitsData[8];
        if(StringUtils.isNotBlank(raw)) {
        	if("OFFICIAL".equals(raw)) // old values no longer used
        		raw = SSNType.CODE_ACTIVE.getCode();
        	ssn.setType(getLookupService().getSSNTypeByCode(raw));
        }
        raw = (String) traitsData[9];
        if(StringUtils.isNotBlank(raw)) {
        	ssn.setPseudoSSNReason(getLookupService().getPseudoSSNReasonByCode(raw));
        }
        raw = (String) traitsData[10];
        if(StringUtils.isNotBlank(raw)) {
	        ssn.setSsaVerificationStatus(this.getLookupService()
	            .getSSAVerificationStatusByCode(raw));
        }
       	ssn.setSsaSentDate(getDate((String) traitsData[11]));
       	ssn.setSsaReceivedDate(getDate((String) traitsData[12]));
       	ssn.setSsaVerificationDate(getDate((String) traitsData[13]));
        traits.setSsn(ssn);

        traits.setGender(getLookupService().getGenderByCode((String)traitsData[14]));
        BirthRecord birth = new BirthRecord();
        birth.setBirthDate(new ImpreciseDate((String)traitsData[15]));
        traits.setBirthRecord(birth);
        return traits;
    }
    
    private Date getDate(String raw) throws Exception{
    	if(StringUtils.isBlank(raw))
    		return null;
    	return new SimpleDateFormat("YYYY-MM-DD HH:mm:ss.S").parse(raw);
    }
    
    public void notifyOfPersonChange(VPIDEntityKey key) throws ServiceException{}

    public void requestIdentityTraitsUpdate(PersonIdentityTraits updatedTraits) 
        throws ServiceException {}

    public void notifyPsdOfDemographicChange(VPIDEntityKey key) {}
}
