package gov.va.med.esr.common.batchprocess;


import java.math.BigDecimal;
import java.util.Calendar;
import java.util.List;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.lookup.SSAVerificationStatus;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.model.person.SSNVerification;
import gov.va.med.esr.common.model.person.SSNVerificationDetail;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKeyImpl;
import gov.va.med.esr.common.model.person.id.VPIDEntityKey;
import gov.va.med.esr.common.persistent.person.PersonDAO;
import gov.va.med.esr.service.PersonIdentityTraits;
import gov.va.med.esr.service.PersonService;
import gov.va.med.esr.service.UniqueIdentifierGenerator;
import gov.va.med.fw.batchprocess.DataProcessExecutionContext;
import gov.va.med.fw.persistent.DAOOperations;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.support.AbstractSpawnedThreadTask;

public class RequestSSNVerificationProcessSpawnedThreadTask extends
	AbstractSpawnedThreadTask{

	//service injection
    private PersonService personService;
    private PersonDAO personDAO;
    private DAOOperations dao;


	private Object[] acquiredData;
	private SSAVerificationStatus  SSNVerificationStatus = null;

	//static variable that all instances should share one copy
	private SSNVerificationProcessExecutionContext context = null;
	private  String processName = null;


    /**
     * An instance of generator
     */
    private UniqueIdentifierGenerator generator;


    /**
     * @return Returns the personDAO.
     */
    public PersonDAO getPersonDAO()
    {
        return personDAO;
    }

    /**
     * @param personDAO
     *            The personDAO to set.
     */
    public void setPersonDAO(PersonDAO personDAO)
    {
        this.personDAO = personDAO;
    }


	/**
     * @return Returns the psDelegateService.
     */
    public PersonService getPersonService()
    {
        return personService;
    }

    /**
     * @param psDelegateService
     *            The psDelegateService to set.
     */
    public void setPersonService(PersonService personService)
    {
        this.personService = personService;
    }

    public UniqueIdentifierGenerator getGenerator() {
		return generator;
	}

	public void setGenerator(UniqueIdentifierGenerator generator) {
		this.generator = generator;
	}

	/**
	 * @return Returns the dao.
	 */
	public DAOOperations getDao() {
		return dao;
	}

	/**
	 * @param dao
	 *            The dao to set.
	 */
	public void setDao(DAOOperations dao) {
		this.dao = dao;
	}

	/**
	 * @return Returns the acquiredData.
	 */
	public Object[] getAcquiredData() {
		return acquiredData;
	}

	/**
	 * @param acquiredData
	 *            The acquiredData to set.
	 */
	public void setAcquiredData(Object[] acquiredData) {
		this.acquiredData = acquiredData;
	}


	/*
	 * all getter/setter for static variables
	 */
	public SSNVerificationProcessExecutionContext getContext() {
		return context;
	}

	public void setContext(SSNVerificationProcessExecutionContext context) {
		this.context = context;
	}

	public String getProcessName() {
		return processName;
	}

	public void setProcessName(String processName) {
		this.processName = processName;
	}

	public  SSAVerificationStatus getSSNVerificationStatus() {
		return SSNVerificationStatus;
	}

	public void setSSNVerificationStatus(SSAVerificationStatus verificationStatus) {
		SSNVerificationStatus = verificationStatus;
	}

    private String generateControlIdentifier() throws ServiceException {
        return this.generator.generate().toString();
     }
	/*
	 * (non-Javadoc)
	 *
	 * @see gov.va.med.fw.service.support.SpawnedThreadTask#execute()
	 */
	public void executeTask() throws Throwable {

		if (acquiredData.length == 3)
		{
			processVeteran();
		}
	}

	private void processVeteran()
	{
        if ( logger.isDebugEnabled())
        {
        	logger.debug("+++++ Entering  RequestSSNVerificationProcessSpawnedThreadTask.processVeteran()");
        }

		SSNVerificationDetail detail = (SSNVerificationDetail)acquiredData[0];
		RequestSSNVerificationStatistics stats = (RequestSSNVerificationStatistics)acquiredData[1];
		List vetFileOutputData = (List)acquiredData[2];

		BigDecimal personId = detail.getPersonId();
		VPIDEntityKey vpid = null;
		PersonIdentityTraits identityTraits = null;
		Person person = null;

		try {
			vpid = this.getPersonService().getVPIDByPersonId(
					new PersonIdEntityKeyImpl(personId));
			if (vpid == null) {
				handleVeteranError(
						context,
						stats,
						"Empty vpid while executing Request SSN Verification batch process for personId= "
								+ personId);
				return;
			}

			identityTraits = this.getPersonService().getESRCorrelation(vpid);

			if (identityTraits == null) {
				handleVeteranError(
						context,
						stats,
						"Empty identityTraits while executing Request SSN Verification batch process for vpid= "
								+ vpid);
				return;
			}

			SSN ssn = identityTraits.getSsn();

			// Process only the ones which do not have pending trait
			// updates.
			if (!identityTraits.isHasPendingUpdates() && ssn != null) {

				ssn.setSsaVerificationStatus(SSNVerificationStatus);

				ssn.setSsaSentDate(Calendar.getInstance().getTime());

				// get the person from ADR with the person_id and
				// overlay with the updated traits from 200ESR Correlation
				person = (Person) this.getPersonDAO().getByKey(
						new PersonIdEntityKeyImpl(personId));
				person.setIdentityTraits(identityTraits);

				// Update MVI to update SSN status and sent time for ESR correlation
				this.getPersonService().updateProfileForESRCorrelation(
						person);
		        if ( logger.isDebugEnabled())
		        {
		        	logger.debug("RequestSSNVerificationProcessSpawnedThreadTask.processVeteran(): after updateProfileForESRCorrelation()");
		        }
				SSASSNVerificationData data = convertIdentityTraitToOutputFileData(
						personId.toString(), vpid.getKeyValueAsString(), identityTraits);
				// Add to list of data to be written to file
				//synchronized block to be thread-safe
				synchronized (this)
				{
					vetFileOutputData.add(data);
				}

				detail.setHECInternalId(data
						.getHECInternalID());

				detail.setPersonId(new BigDecimal(data.getPersonId()));
				detail.setSsnText(data.getSsn());

				//save it
				this.getDao().saveObject(detail);
		        if ( logger.isDebugEnabled())
		        {
		        	logger.debug("RequestSSNVerificationProcessSpawnedThreadTask.processVeteran(): after saveObject(detail): " + detail);
		        }

		        //the successful records are updated in handleDadaProcessCompleted() method in RequestSSNVerificationProcess.java

			} else {
				stats.setNumberOfRecordsIgnoredForPendingUpdateToIdentityTraits(stats
								.getNumberOfRecordsIgnoredForPendingUpdateToIdentityTraits() + 1);
				stats.setNumberOfVetRecordsIgnoredForPendingUpdateToIdentityTraits(stats
								.getNumberOfVetRecordsIgnoredForPendingUpdateToIdentityTraits() + 1);
			}

		} catch (Exception e) {
			stats.setNumberOfErrorRecords(stats.getNumberOfErrorRecords() + 1);
			stats.setNumberOfErrorVetRecords(stats
							.getNumberOfErrorVetRecords() + 1);

			String errorMessage = "Error while executing Request SSN Verification batch process for veterans:"
					+ " Reason: " + e.getMessage();
			context.getExceptionData().add(errorMessage);

			if (logger.isWarnEnabled())
				logger.warn(errorMessage, e);
		}
        finally {

        	RequestSSNVerificationProcess.adjustTaskCount(context, -1);
			Object threadCreator = getThreadCreator(context);
			synchronized (threadCreator) {
				threadCreator.notifyAll();
			}
			/*
			 * force release of context as thay will hold the ThreadPool(->Threads)
			 * this is necessary to GC ThreadPool threads at end
			 */
			context = null;
	        if ( logger.isDebugEnabled())
	        {
	        	logger.debug("+++++ Leaving RequestSSNVerificationProcessSpawnedThreadTask.processVeteran() finally block");
	        }
        }



	}


	private Object getThreadCreator(SSNVerificationProcessExecutionContext context) {
		return context.getContextData().get(RequestSSNVerificationProcess.CONTEXT_THREAD_CREATOR);
	}


    private void handleVeteranError(SSNVerificationProcessExecutionContext context, RequestSSNVerificationStatistics stats, String errorMessage)
    {
    	stats.setNumberOfErrorRecords(stats.getNumberOfErrorRecords()+1 );
        stats.setNumberOfErrorVetRecords(stats.getNumberOfErrorVetRecords() +1);
        context.getExceptionData().add(errorMessage);

        if (logger.isWarnEnabled())
            logger.warn(errorMessage);
    }


    private SSASSNVerificationData convertIdentityTraitToOutputFileData(
			String personId, String vpidKey, PersonIdentityTraits identityTraits) {

		SSASSNVerificationData ssnVerificationData = new SSASSNVerificationData();
		ssnVerificationData.setVpidValue(vpidKey);

		try {
			ssnVerificationData.setHECInternalID(generateControlIdentifier());

			ssnVerificationData.setSsn(identityTraits.getSsn().getSsnText());
			ssnVerificationData.setLastName(identityTraits.getLegalName()
					.getFamilyName());
			ssnVerificationData.setFirstName(identityTraits.getLegalName()
					.getGivenName());
			ssnVerificationData.setMiddleInitial(identityTraits.getLegalName()
					.getMiddleName());
			ssnVerificationData
					.setDateOfBirth(identityTraits.getBirthRecord() == null ? null
							: identityTraits.getBirthRecord().getBirthDate());
			ssnVerificationData
					.setGender(identityTraits.getGender() == null ? null
							: identityTraits.getGender().getCode());
			ssnVerificationData.setPersonId(personId);

		} catch (Exception e) {
			logger.error(
					"Error converting to putput data for veteran with vpid key "
							+ vpidKey, e);
		}
		return ssnVerificationData;
	}

}

