/********************************************************************
 * Copyright © 2005-2006 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.ui.comms.action;

// Java Classes
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

// Libraries Classes
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;

// Framework Classes
import gov.va.med.fw.ui.struts.ValueListActionUtils;
import gov.va.med.fw.ui.valuelist.SelectableResult;
import gov.va.med.fw.ui.valuelist.DefaultSelectableResult;
import gov.va.med.fw.ui.valuelist.SelectableSearchValueListAdapter;
import gov.va.med.fw.util.StringUtils;

// ESR Classes
import gov.va.med.esr.common.model.comms.UndeliverableMailInfo;
import gov.va.med.esr.service.CommsLogService;

/**
 * This struts action is used to support the Undeliverable Mail Barcode Scanning page.
 *
 * @author Andrew Pach
 * @version 3.0
 */
public class UndeliverableMailBarcodeScanningAction extends UndeliverableMailAction
{
    // Session key to store the cached scanned results
    public static final String SCANNED_RESULTS_SESSION_KEY =
        "undeliverableMailScannedResultsSessionKey";

    // The request attribute key for the selected items
    public static final String SELECTED_REQUEST_ATTRIBUTE_KEY =
        SelectableSearchValueListAdapter.SELECTED_REQUEST_ATTRIBUTE_KEY;

    /**
     * Default constructor.
     */
    public UndeliverableMailBarcodeScanningAction()
    {
        super();
    }

    /**
     * Displays the main page.
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward display(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        // Create a new array of selected items for the new page
        List selectedItems = new ArrayList();

        // Get the mail items from session.
        List results = getResultsFromSession(request.getSession());

        // Itereate through the results
        for (int i = 0; i < results.size(); i++)
        {
            // Get a selectable result & add it's state to the list
            SelectableResult selectableResult = (SelectableResult)results.get(i);
            selectedItems.add(selectableResult.isSelected() ? "checked" : "");
        }

        // Set the selected items in the request
        request.setAttribute(SELECTED_REQUEST_ATTRIBUTE_KEY, selectedItems);

        // Return to the display
        return mapping.findForward(FORWARD_DISPLAY);
    }

    /**
     * Performs an undeliverable mail search based on the bar code entered.
     *
     * @param mapping An action mapping
     * @param form A form bean
     * @param request A http request from an search.jsp page
     * @param response A http response to stream data to a next page
     *
     * @return An action forward class encapsulating information about a next page
     * @throws Exception if any errors occurred while trying to process the person search.
     */
    public ActionForward search(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception
    {
        // Update the currently selected items from the UI
        updateSelectedItems(request);

        // Ensure we have a valid search form
        UndeliverableMailBarcodeScanningForm scanForm =
            getUndeliverableMailBarcodeScanningForm(form);

        // Get the entered bar code
        String barCode = scanForm.getBarcode();

        // Ensure a bar code was submitted
        if (StringUtils.isEmpty(barCode))
        {
            // The bar code parameter wasn't found
            addActionMessage(request, new ActionMessage(BARCODE_REQUIRED));
            return display(mapping, form, request, response);
        }
        else
        {
            barCode = barCode.trim();
        }

        // Get the undeliverable mail
        CommsLogService commsLogService = getCommsLogService();
        UndeliverableMailInfo mailInfo =
            commsLogService.findUndeliverableMailByBarcode(barCode);

        // Ensure that the bar code exists
        if (mailInfo == null)
        {
            // The bar code parameter wasn't found
            addActionMessage(request, new ActionMessage(BARCODE_NOT_FOUND));
            return display(mapping, form, request, response);
        }

        // Check to see if the bar code has already been scanned on this page.
        List results = getResultsFromSession(request.getSession());
        for (Iterator iterator = results.iterator(); iterator.hasNext();)
        {
            SelectableResult selectableResult = (SelectableResult)iterator.next();
            if (barCode.equals(((UndeliverableMailInfo)selectableResult.getResult()).getCommsLogEntry().
                getBarcode()))
            {
                // The bar code has already been scanned
                addActionMessage(request, new ActionMessage(DUPLICATE_BARCODE));
                return display(mapping, form, request, response);
            }
        }

        // Create a SelectableResult item from the undeliverable mail info so we can track
        // whether it is selected or not from the UI.
        SelectableResult selectableResult = new DefaultSelectableResult();
        selectableResult.setResult(mailInfo);
        selectableResult.setSelected(true);

        // Add the newly scanned entry into the results in session
        results.add(selectableResult);

        // Clear out the barcode so a new one can be entered next time
        scanForm.setBarcode(null);

        // Forward to the display page
        return display(mapping, form, request, response);
    }

    /**
     * Resets the data to its original state.
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward reset(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        // Clear out the previously cached results
        setResultsInSession(request.getSession(), new ArrayList());

        // Re-display the screen
        return display(mapping, form, request, response);
    }

    /**
     * Updates the status of the selected entries as "returned from post office".
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward update(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        // Update the currently selected items from the UI
        updateSelectedItems(request);

        // Get the selected results from the cached list of results
        List selectedResults = ValueListActionUtils.getSelectableResults(
            getResultsFromSession(request.getSession()), new Boolean(true));

        // Check if the user selected any items
        if ((selectedResults == null) || (selectedResults.size() == 0))
        {
            // The user didn't select any results so display an error message
            addActionMessage(request, new ActionMessage(NO_RESULTS_MESSAGE_KEY));
            return display(mapping, form, request, response);
        }

        // Create a list of CommsLogEntry objects for the processUndeliverableMail method.
        ArrayList commsLogEntryList = new ArrayList();
        for (Iterator iterator = selectedResults.iterator(); iterator.hasNext();)
        {
            SelectableResult selectableResult = (SelectableResult)iterator.next();
            UndeliverableMailInfo undeliverableMailInfo =
                (UndeliverableMailInfo)selectableResult.getResult();
            commsLogEntryList.add(undeliverableMailInfo.getCommsLogEntry());
        }

        // Process the selected entries
        getCommsLogService().processUndeliverableMail(commsLogEntryList);

        // Add a success message
        addInformationMessage(request, SUCCESSFUL_STATUS_UPDATE);

        // Return to the results display after clearing out the cached results
        return reset(mapping, form, request, response);
    }

    /**
     * Updates the currently selected items in the session cache
     *
     * @param request The HttpServletRequest
     */
    protected void updateSelectedItems(HttpServletRequest request)
    {
        // Add the newly scanned entry into the results in session
        List results = getResultsFromSession(request.getSession());

        // Get the list of selected items from the request
        String[] selectedItems = request.getParameterValues(SELECTED_REQUEST_ATTRIBUTE_KEY);

        // Create a map of the selected items
        Map selectedItemMap = new HashMap();
        if (selectedItems != null)
        {
            for (int i = 0; i < selectedItems.length; i++)
            {
                String selectedItemIndex = (String)selectedItems[i];
                selectedItemMap.put(new Integer(selectedItemIndex), "true");
            }
        }

        // Loop through the results and mark the appropriate ones as selected
        for (int i = 0; i < results.size(); i++)
        {
            SelectableResult selectableResult = (SelectableResult)results.get(i);
            selectableResult.setSelected(selectedItemMap.get(new Integer(i)) != null);
        }
    }

    /**
     * Sets an error message bundle key to display an error message to the user.
     *
     * @param session The HttpSession
     * @param results the list of SelectableEntry objects which each contain an undeliverable mail
     * info object.
     */
    protected void setResultsInSession(HttpSession session, List results)
    {
        session.setAttribute(SCANNED_RESULTS_SESSION_KEY, results);
    }

    /**
     * Gets the result list of SelectableEntry objects.
     *
     * @param session The HttpSession
     *
     * @return The results.
     */
    protected List getResultsFromSession(HttpSession session)
    {
        List results = (List)session.getAttribute(SCANNED_RESULTS_SESSION_KEY);
        if (results == null)
        {
            results = new ArrayList();
            setResultsInSession(session, results);
        }
        return results;
    }

    /**
     * Initialize and get the Struts lookup dispatch method map hashmap.
     *
     * @return the method map
     * @see org.apache.struts.actions.LookupDispatchAction#getKeyMethodMap()
     */
    protected Map getKeyMethodMap()
    {
        Map map = new HashMap();
        map.put("button.display", "display");
        map.put("button.search", "search");
        map.put("button.update", "update");
        map.put("button.clear", "reset");
        return map;
    }
}