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

import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.lookup.SSNType;
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.persistent.MaxRecordsExceededException;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.TimeoutServiceException;
import gov.va.med.fw.util.DateUtils;
import gov.va.med.fw.util.StopWatchLogger;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.fw.util.TimeoutException;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.Validate;

/**
 * TEMPORARY implementation to provide search capabilites on person traits.
 *
 * @author DNS   GALLAS
 * Created on July 14, 2008
 *
 * CCR12190 Remove direct calls to RPT_PSIM_TRAITS in ESR 3.12
 * This class is no longer injected for psDelegateService in business_services.xml
 * Can be used in dev when MVI is down to directly search DB for traits
 *
 */
public class ReportPSDelegateServiceImpl extends PSDelegateServiceImpl {

    private static final int MAX_RECORDS = 10;
    private static final int UPPER_LIMIT = MAX_RECORDS + 1;
    private final static String DATE_FORMAT = "yyyyMMdd";


    /**
     * An instance of serialVersionUID
     */
    private static final long serialVersionUID = -3600716622840392949L;

    private DAOOperations genericDAO = null;

    private String selectAndFromClause = "select VPID_VALUE from rpt_psim_traits ";



    /**
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    public void afterPropertiesSet() throws Exception
    {
        Validate.notNull(genericDAO, "genericDAO is a required property for ReportPSDelegateServiceImpl");
    }

    public DAOOperations getGenericDAO() {
        return genericDAO;
    }

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


    protected Set doSearch(PersonIdentityTraits criteria, String matchType) throws ServiceException {

    	try
        {
    		return searchPersonTraits(criteria, matchType);
        }
        // MaxRecordsExceededException needs to bubble up to the UI unmodified
        catch (MaxRecordsExceededException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new ServiceException(
                "Unable to perform a LOCAL search for identity traits", e);
        }

    }



    private Set searchPersonTraits(PersonIdentityTraits criteria, String matchType) throws Exception
    {


        Set results = new HashSet();

        String whereClause = buildWhereClause(criteria, matchType);
        String query = selectAndFromClause + whereClause;

        List list = null;
        try
        {
            StopWatchLogger watch = new StopWatchLogger("Searching RPT_PSIM_TRAITS with criteria=" + whereClause + "]");
            watch.start();
            list = getGenericDAO().executeSQLQuery(query);
            watch.stopAndLog("returned " + (list != null ? list.size() : 0) + " records");
        }
        catch (Exception e)
        {
            throw new ServiceException("Generic DAO query of psim traits failed ",e);
        }

        // If no results returned, search PSIM.
        if (list.size() == 0)
        {
            if (logger.isInfoEnabled())
                logger.info("No results found in LOCAL search, searching PSIM. ");

            results = super.doSearch(criteria, false, true);  //attended search
        }

        if (list.size() > MAX_RECORDS)
        {
            // Using -1 to indicate the total records that would have been returned is not known.
            throw new MaxRecordsExceededException(-1, MAX_RECORDS,
                "LOCAL search by identity traits exceeded allowable limit of " + MAX_RECORDS + " matched records.");
        }

        for (Iterator i=list.iterator(); i.hasNext();)
        {
            String VPID = (String)(i.next());
            PersonIdentityTraits personIdentityTraits = createPersonTraits(VPID);
            results.add(personIdentityTraits);
        }

        return results;
    }

    private String buildWhereClause(PersonIdentityTraits criteria, String matchType)
    {
        // Limit to no more than 10 rows
        StringBuffer whereClause = new StringBuffer(" where rownum <= " + UPPER_LIMIT);

        SSN ssn = criteria.getSsn();
        if (ssn != null)
        {
            if (StringUtils.isNotEmpty(criteria.getSsnText()))
            {
                whereClause.append(" AND SSN = '" + criteria.getSsnText() + "'");
            }

            SSNType ssnType = ssn.getType();
            if (ssnType != null)
            {
                whereClause.append(" AND SSN_TYPE_CODE = '" + ssnType.getCode() + "'");
            }

            if (ssn.getPseudoSSNReason() != null && StringUtils.isNotEmpty(ssn.getPseudoSSNReason().getCode()))
            {
                whereClause.append(" AND PSEUDO_SSN_REASON_CODE = '" + ssn.getPseudoSSNReason().getCode() + "'");
            }

            if (ssn.getSsaVerificationStatus() != null && StringUtils.isNotEmpty(ssn.getSsaVerificationStatus().getCode()))
            {
                whereClause.append(" AND SSN_VRFN_STATUS_CODE = '" + ssn.getSsaVerificationStatus().getCode() + "'");
            }
        }

        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() + "'");
            }

            if (StringUtils.isNotEmpty(name.getMiddleName()))
            {
                whereClause.append(" AND MIDDLE_NAME = '" + name.getMiddleName().toUpperCase() + "'");
            }

            if (StringUtils.isNotEmpty(name.getPrefix()))
            {
                whereClause.append(" AND PREFIX = '" + name.getPrefix().toUpperCase() + "'");
            }

            if (StringUtils.isNotEmpty(name.getSuffix())) {
                whereClause.append(" AND SUFFIX = '" + name.getSuffix().toUpperCase() + "'");
            }
        }

        if (criteria.getGender() != null && StringUtils.isNotEmpty(criteria.getGender().getCode()))
        {
            whereClause.append(" AND GENDER_CODE = '" + criteria.getGender().getCode() + "'");
        }

        if(criteria.getBirthRecord() != null && criteria.getBirthRecord().getBirthDate() != null)
        {
            String birthDate = DateUtils.format(criteria.getBirthRecord().getBirthDate().getDate(), DATE_FORMAT);
            whereClause.append(" AND DATE_OF_BIRTH = '" + birthDate + "'");
        }


        return whereClause.toString();
    }

    /**
     * Use the VPID returned by the local search to perform search on PSIM.
     *
     * @param traitsData
     * @return
     * @throws Exception
     */
    private PersonIdentityTraits createPersonTraits(String VPID)
        throws Exception
    {
        VPIDEntityKey entityKey =
            CommonEntityKeyFactory.createVPIDEntityKey(VPID);
        return super.getIdentityTraits(entityKey);
    }



}
