/*******************************************************************************
 * Copyright © 2004-2006 VHA. All rights reserved
 ******************************************************************************/
package gov.va.med.esr.service.impl;

// Java Classes
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.Validate;

import gov.va.med.esr.common.clock.Clock.Type;
import gov.va.med.esr.common.model.comms.CommsLogEntry;
import gov.va.med.esr.common.model.comms.CommsLogSearchQueryInfo;
import gov.va.med.esr.common.model.comms.UndeliverableMailInfo;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.persistent.comms.CommsLogEntryDAO;
import gov.va.med.esr.service.CommsLetterRequestService;
import gov.va.med.esr.service.CommsLogService;
import gov.va.med.esr.service.DemographicService;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.pagination.SearchQueryInfo;

/**
 * Implementation for Comms Log Services.
 *
 * @author ESR Team
 * @author Andrew Pach
 * @version 3.0
 */
//3.6 10960 Removed all references to Handbook. They have been moved to the Handbook Service

public class CommsLogServiceImpl extends AbstractRuleAwareServiceImpl implements CommsLogService
{
    /**
     * An instance of serialVersionUID
     */
    private static final long serialVersionUID = -4817235230296107829L;

    private CommsLogEntryDAO dao = null;
    private DemographicService demographicService = null;
    private CommsLetterRequestService letterRequestService = null;
    
    
    public void afterPropertiesSet() throws Exception {
    	super.afterPropertiesSet();
    	Validate.notNull(dao, "dao is required");
    	Validate.notNull(letterRequestService, "letterRequestService is required");
   }

    /**
     * Construct a CommsLogServiceImpl object.
     *
     * @param dao The CommsLogEntryDAO
     */
    public CommsLogServiceImpl(CommsLogEntryDAO dao)
    {
        super();
        Validate.notNull(dao, "CommsLogEntryDAO is required.");
        this.dao = dao;
    }

    /**
     * Gets a specific CommsLogEntry based on an entity key.
     *
     * @param key The key of the CommsLogEntry to retrieve.
     *
     * @return The CommsLogEntry based on the specified entity key.
     * @throws ServiceException if any problems were encountered.
     */
    public CommsLogEntry getCommsLogEntry(EntityKey key) throws ServiceException
    {
        try
        {
            return (CommsLogEntry)dao.getByKey(key);
        }
        catch (DAOException ex)
        {
            throw new ServiceException("Error getting CommsLogEntry using key: " + key, ex);
        }
    }

    /**
     * Finds a CommsLogEntry by it's barcode.  This is different from the entity key.
     * @param barcode The barcode to lookup.
     * @return The CommsLogEntry that matches the passed in barcode.
     * @throws ServiceException if any problems were encountered.
     */
    public CommsLogEntry findByBarcode(String barcode) throws ServiceException
    {
        try
        {
            return dao.findCommsLogEntryByBarcode(barcode);
        }
        catch (Exception ex)
        {
            throw new ServiceException("Failed to find CommsLogEntry for barcode: " + barcode, ex);
        }
    }

    public void update(CommsLogEntry logEntry) throws ServiceException
    {
        try
        {
            dao.update(logEntry);
        }
        catch (Exception ex)
        {
            throw new ServiceException("Failed to update CommsLogEntry.", ex);
        }
    }

    public void insert(CommsLogEntry logEntry) throws ServiceException
    {
        try
        {
            dao.insert(logEntry);
        }
        catch (Exception ex)
        {
            throw new ServiceException("Failed to insert CommsLogEntry.", ex);
        }
    }

    /*
      * public void updateMailingStatus (BigDecimal logId, String
      * mailingStatusCode) { }
      */
    public List findLogEntriesByPersonId(String personId) throws ServiceException
    {
        try
        {
            return dao.findCommsLogListByPersonId(personId);
        }
        catch (Exception ex)
        {
            throw new ServiceException("Failed to find CommsLogEntries by Person Id: " + personId, ex);
        }
    }
    /**
     * Gets an UndeliverableMailInfo object based on a barcode String.
     *
     * @param barcode The scanned or manually entered barcode from an undeliverable letter.
     *
     * @return The UndeliverableMailInfo
     * @throws ServiceException if any problems were encountered.
     */
    public UndeliverableMailInfo findUndeliverableMailByBarcode(String barcode)
        throws ServiceException
    {
        UndeliverableMailInfo mailInfo = null;
        CommsLogEntry commsLogEntry = findByBarcode(barcode);
        
        // for undeliverable mail needs, only care about those in status ComMailingStatusType.MAILED_BY_AAC
        if (commsLogEntry != null && commsLogEntry.isMailedByAAC())
        {
            mailInfo = new UndeliverableMailInfo();
            mailInfo.setCommsLogEntry(commsLogEntry);
            mailInfo.setUpdatedAddress(
                getDemographicService().getUndeliverableMailUpdatedLetterAddress(mailInfo.getCommsLogEntry()));
        }
        return mailInfo;
    }

    /**
     * Searchs and returns a list of UndeliverableMailInfo objects based on the passed in search
     * criteria.  Note this generic search method currently only servers UndeliverableMail needs.
     *
     * @param searchQueryInfo The search criteria
     *
     * @return The list of UndeliverableMailInfo objects
     * @throws ServiceException if any problems were encountered.
     */
    public List search(SearchQueryInfo searchQueryInfo) throws ServiceException
    {
        // Ensure we have the correct type of query information object
        if (!(searchQueryInfo instanceof CommsLogSearchQueryInfo))
        {
            throw new ServiceException("searchQueryInfo is an instance of '"
                + searchQueryInfo.getClass().getName()
                + "' and must be an instance of 'CommsLogSearchQueryInfo'.");
        }
        CommsLogSearchQueryInfo commsLogSearchQueryInfo = (CommsLogSearchQueryInfo)searchQueryInfo;

        // First get the list of CommsLogEntry objects
        List commsLogEntries = null;
        try
        {
            commsLogEntries = dao.find(commsLogSearchQueryInfo);
        }
        catch (DAOException ex)
        {
            throw new ServiceException("Failed to find CommsLogEntry objects based on the " +
                "selected search criteria.", ex);
        }

        // For each CommsLogEntry result, wrap it in an UndeliverableMailInfo object and
        // populate any new Address that can now be used if a new one exists.
        ArrayList undeliverableMailEntries = new ArrayList();
        if (commsLogEntries == null)
            return undeliverableMailEntries;

        for (Iterator iterator = commsLogEntries.iterator(); iterator.hasNext();)
        {
            CommsLogEntry commsLogEntry = (CommsLogEntry)iterator.next();
            
            UndeliverableMailInfo undeliverableMailInfo = new UndeliverableMailInfo();
            undeliverableMailInfo.setCommsLogEntry(commsLogEntry);
            undeliverableMailInfo
                .setUpdatedAddress(getDemographicService().getUndeliverableMailUpdatedLetterAddress(commsLogEntry));
            undeliverableMailEntries.add(undeliverableMailInfo);
        }

        // Return the final results
        return undeliverableMailEntries;
    }

    /**
     * Processes the undeliverable mail based on a list of CommsLogEntry objects.
     *
     * @param commsLogEntries The list of CommsLogEntry objects to process.
     *
     * @throws ServiceException if any problems were encountered.
     */
    public void processUndeliverableMail(List commsLogEntries)
        throws ServiceException
    {
        this.getCommunicationRuleService().handleUndeliverableMail(commsLogEntries);
    }

    /**
     * @see gov.va.med.esr.service.CommsLogService#updateCommunicationLog(gov.va.med.esr.common.model.comms.CommsLogEntry)
     */
    public CommsLogEntry updateCommunicationLog(CommsLogEntry log) throws ServiceException
    {
        CommsLogEntry onFile = null;
        try
        {
        	EntityKey key = log.getEntityKey();
            if (key!= null)
            {
                onFile = (CommsLogEntry)dao.getByKey(key);
            }
        }
        catch (DAOException e)
        {
            throw new ServiceException("Failed to find CommsLogEntry by entity key: " + log.getEntityKey().getKeyValueAsString(), e);
        }

        if (onFile == null)
        {
            // For case where no existing log
            onFile = (CommsLogEntry)log.clone();
        }

        this.getCommunicationRuleService().manageCommunicationsLog(log, onFile);

        this.update(onFile);
        
        // if this is cancelled, delete any print requests
        if(onFile.isCancelledByHec())
        	this.letterRequestService.cancelLetterRequest(onFile);
        return onFile;
    }
    
    
    /**
     * @see gov.va.med.esr.service.CommsLogService#processAutomaticLetterRequests(gov.va.med.esr.common.model.person.Person, gov.va.med.esr.common.clock.Clock.Type, java.lang.String)
     */
    public void processAutomaticLetterRequests(Person person, Type clockType, String subject) throws ServiceException {
        this.getCommunicationRuleService().triggerAutomaticLetters(person, clockType, subject);
    }

    /**
     * Handles a mailing response.
     *
     * @param responses the list of responses
     * @throws ServiceException if an error was encountered.
     */
    public void handleMailingResponses(List responses) throws ServiceException {
        this.getCommunicationRuleService().handleMailingResponses(responses);
    }
    
    public void handleMailingResponses(CommsLogEntry log) throws ServiceException {
        this.getCommunicationRuleService().handleMailingResponses(log);
    }
    
    public DemographicService getDemographicService()
    {
        return demographicService;
    }

    public void setDemographicService(DemographicService demographicService)
    {
        this.demographicService = demographicService;
    }

	/**
	 * @return Returns the letterRequestService.
	 */
	public CommsLetterRequestService getLetterRequestService() {
		return letterRequestService;
	}

	/**
	 * @param letterRequestService The letterRequestService to set.
	 */
	public void setLetterRequestService(
			CommsLetterRequestService letterRequestService) {
		this.letterRequestService = letterRequestService;
	}
}
