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

// Java classes

// Library classes
import gov.va.med.esr.common.model.financials.DependentFinancials;
import gov.va.med.esr.common.model.financials.FinancialStatement;
import gov.va.med.esr.common.model.financials.SpouseFinancials;
import gov.va.med.esr.common.model.lookup.CancelDeclineReason;
import gov.va.med.esr.common.model.person.Dependent;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.Spouse;
//import gov.va.med.esr.ui.comms.action.ValueList;
import gov.va.med.fw.ui.struts.ValueListActionUtils;
import net.mlw.vlh.ValueList;
import gov.va.med.esr.ui.util.SessionManager;
import gov.va.med.fw.conversion.ConversionService;
import gov.va.med.fw.service.ServiceConfigurationException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.Validate;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

/**
 * This struts action is used to support the financials dependent overview page.
 *
 * @author Andrew Pach
 * @version 3.0
 */
public class FinancialsDependentOverviewAction extends FinancialsDependentAction
{
    // Struts forwards
    public static final String FORWARD_FINANCIALS_DEPENDENT_OVERVIEW = "financialsDependentOverview";
    public static final String FORWARD_FINANCIALS_DEPENDENT_ADD_SPOUSE = "financialsDependentAddSpouse";
    public static final String FORWARD_FINANCIALS_DEPENDENT_ADD_CHILD = "financialsDependentAddChild";

    // Message bundle keys
    public static final String ERRORS_NO_PREVIOUS_DEPENDENT_INFO_MESSAGE_KEY = "errors.no.previous.dependent.information";
    public static final String ERRORS_NO_PREVIOUS_DEPENDENT_IN_YEAR_INFO_MESSAGE_KEY =
        "errors.no.previous.dependent.information.in.year";
    public static final String SUCCESS_COPY_DEPENDENT_INFO_MESSAGE_KEY = "success.copy.dependent.information";
    
    /**
     * Default constructor.
     */
    public FinancialsDependentOverviewAction()
    {
        super();
    }

    /**
     * Displays the Financials Dependents Overview 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
    {   
    	FinancialsDependentOverviewForm dependentForm = getFinancialsDependentOverviewForm(form);
        
    	boolean isAddAPerson = false;
        isAddAPerson = SessionManager.isAddAPerson(request);
        dependentForm.setAddAPerson(isAddAPerson);
        
		// Get the Person object from the cache
        Person person = getSelectedPerson(request);
        
        // Get selected income year from cache
        Integer incomeYear = getSelectedIncomeYear(request);
        
        //get spouse and dependent info
        getDependentList(person, dependentForm, incomeYear);
        
        List ls = dependentForm.getDependentList();
        
        // Get the value list information from the future EGT Settings list
        ValueList valueList = ValueListActionUtils.getValueList(form,
            request, "financialDependentTableId", "financialDependentAdapter", ls);

        // Backup the ValueListInfo into session and store the resultant ValueList on the request
        ValueListActionUtils.setValueList(request, valueList, "vlhlist");

        return mapping.findForward(FORWARD_FINANCIALS_DEPENDENT_OVERVIEW);
    }

    /**
     * Goes to the Financials Dependent Add Child 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 gotoAddChild(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        return mapping.findForward(FORWARD_FINANCIALS_DEPENDENT_ADD_CHILD);
    }

    /**
     * Goes to the Financials Dependent Add Spouse 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 gotoAddSpouse(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        return mapping.findForward(FORWARD_FINANCIALS_DEPENDENT_ADD_SPOUSE);
    }

    /**
     * Goes to the Financials Overview 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 cancel(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        return mapping.findForward(FORWARD_FINANCIALS_OVERVIEW);
    }

    /**
     * Copies the dependents defined on the previous financial statement to the current financial statement.
     *
     * @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 copyDependents(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        // TODO: Might want to move this method and supporting methods into a helper class (e.g. FinancialsDependentHelper.java).

        // Get the Person object from the cache
        Person originalPerson = getSelectedPerson(request);
        Person person = (Person)originalPerson.clone();

        // Get the selected income year from cache
        Integer currentIncomeYear = getSelectedIncomeYear(request);

        // Get the previous income year to the selected in come year (if one exists)
        Integer prevIncomeYear = getPreviousIncomeYear(person, currentIncomeYear);

        // Get the previous spouse/dependent financial information
        FinancialStatement prevStatement = null;
        SpouseFinancials prevSpouseFinancials = null;
        Set prevDependentFinancialsSet = null;
        if (prevIncomeYear != null)
        {
            prevStatement = person.getFinancialStatement(prevIncomeYear);
            if (prevStatement != null)
            {
                prevSpouseFinancials = prevStatement.getActiveSpouseFinancials();
                prevDependentFinancialsSet = prevStatement.getDependentFinancials();
            }
        }

        // If no previous income year exists (i.e. no financial statement for a prior year), display
        // an error message to the user and return
        if (prevIncomeYear == null)
        {
            addActionMessage(request, ERRORS_NO_PREVIOUS_DEPENDENT_INFO_MESSAGE_KEY, String.valueOf(currentIncomeYear));
            return mapping.findForward(FORWARD_FINANCIALS_DEPENDENT_OVERVIEW);
        }

        // If no financial spouse or dependent information exists for the previous year,
        // display an error message to the user and return
        if ((prevSpouseFinancials == null) &&
            ((prevDependentFinancialsSet == null) || (prevDependentFinancialsSet.isEmpty())))
        {
            addActionMessage(request, ERRORS_NO_PREVIOUS_DEPENDENT_IN_YEAR_INFO_MESSAGE_KEY, String.valueOf(prevIncomeYear));
            return mapping.findForward(FORWARD_FINANCIALS_DEPENDENT_OVERVIEW);
        }

        // Get the current financial statement or create one if necessary
        FinancialStatement currentStatement = person.getFinancialStatement(currentIncomeYear);
        if (currentStatement == null)
        {
            currentStatement = new FinancialStatement();
            currentStatement.setNumberOfDependentChildren(prevStatement.getNumberOfDependentChildren());
            currentStatement.setMarriedLastCalendarYear(prevStatement.getMarriedLastCalendarYear());
            currentStatement.setIsPost2005Format(Boolean.TRUE);
            currentStatement.setContributionToSpouse(prevStatement.getContributionToSpouse());
            person.setFinancialStatement(currentIncomeYear, currentStatement);
            
            // contributed to spouse indicator.            
            currentStatement.setContributedToSpouseInd(prevStatement.getContributedToSpouseInd());
        }

        // Remove all existing dependent information from the current financial statement
        currentStatement.removeSpouseFinancials();
        currentStatement.removeAllDependentFinancials();

        // Copy over the spouse financials
        if (prevSpouseFinancials != null)
        {
            SpouseFinancials currentSpouseFinancials = new SpouseFinancials();
            currentStatement.addSpouseFinancials(currentSpouseFinancials);

            Spouse prevSpouse = prevSpouseFinancials.getReportedOn();
            if (prevSpouse != null)
            {
                Spouse currentSpouse = new Spouse();
                getCopyService().copy(prevSpouse, currentSpouse);
                getMergeRuleService().mergeSSN(prevSpouse, currentSpouse);
                currentSpouseFinancials.setReportedOn(currentSpouse); // Must be after copy to set back reference properly
            }
        }

        // Copy over the dependent financials
        for (Iterator iterator = prevDependentFinancialsSet.iterator(); iterator.hasNext();)
        {
            DependentFinancials prevDependentFinancials = (DependentFinancials)iterator.next();
            DependentFinancials currentDependentFinancials = new DependentFinancials();
            currentStatement.addDependentFinancials(currentDependentFinancials);

            Dependent prevDependent = prevDependentFinancials.getReportedOn();
            if (prevDependent != null)
            {
                Dependent currentDependent = new Dependent();
                getCopyService().copy(prevDependent, currentDependent);
                getMergeRuleService().mergeSSN(prevDependent, currentDependent);
                currentDependentFinancials.setReportedOn(currentDependent); // Must be after copy to set back reference properly
            }
        }

        // Update the dependent information for the given income year
        person = getFinancialsService().updateDependents(currentIncomeYear, person);

        // Add a success message
        addInformationMessage(request, SUCCESS_COPY_DEPENDENT_INFO_MESSAGE_KEY, String.valueOf(prevIncomeYear));

        // Store updated person in the cache
        updateSelectedPerson(request, person);

        // Return back to the same dependents overview page
        return display(mapping, form, request, response);
    }

   /**
     * Checks to ensure the passed in ActionForm is not null and of the correct type.
     *
     * @param form The struts form to check
     * @return The passed in form type-casted to a FinancialsDependentOverviewForm
     * @throws gov.va.med.fw.service.ServiceConfigurationException if the form is null or of an incorrect type.
     */
    protected FinancialsDependentOverviewForm getFinancialsDependentOverviewForm(ActionForm form) throws ServiceConfigurationException
    {
    	FinancialsDependentOverviewForm personalForm =
            (form instanceof FinancialsDependentOverviewForm) ? (FinancialsDependentOverviewForm)form : null;
        if (personalForm == null)
        {
            throw new ServiceConfigurationException("FinancialsDependentOverviewForm not properly configured.");
        }
        return personalForm;
    }

    /**
     * Gets the list of dependents and sets them on the form.
     * @param person The person
     * @param form The form
     * @param incomeYear The income year
     * @throws Exception if any problems were encountered
     */
    private void getDependentList(Person person, FinancialsDependentOverviewForm form, Integer incomeYear)
        throws Exception
    {
        FinancialStatement ftmt = person.getFinancialStatement(incomeYear);
        if (ftmt == null)
        {
            ftmt = new FinancialStatement();
        }
        
        Validate.isTrue(getConversionService() instanceof FinancialDetailsConversionService,"conversionService should be of type FinancialDetailsConversionService.");
		List list = ((FinancialDetailsConversionService)getConversionService()).getDependentInfoList(ftmt);
		form.setDependentList(list);
		
		SpouseFinancials sf = ftmt.getActiveSpouseFinancials();
        if (sf != null)
        	form.setSpouseAvaliableInd(true);        
 	}

    /**
     * Gets the previous income year to the currently selected income year
     *
     * @param person The person
     * @param selectedIncomeYear The currently selected income year
     * @return The previous income year or null if no previous income year exists
     */
    private Integer getPreviousIncomeYear(Person person, Integer selectedIncomeYear)
    {
        // Get the map of financial statements, keyed by income year
        Map financialStatementMap = person.getFinancialStatements();

        // Get the list of years that we have financial statements and sort them
        ArrayList yearList = new ArrayList(financialStatementMap.keySet());
        Collections.sort(yearList);

        // Loop through the income years backwards to search for the previous income year to the selected income year
        Integer prevIncomeYear = null;
        for (int i=yearList.size()-1; ((i >=0) && (prevIncomeYear == null)); i--)
        {
            // Get the next income year
            Integer incomeYear = (Integer)yearList.get(i);
            if (selectedIncomeYear.compareTo(incomeYear) >= 0)
            {
                if (selectedIncomeYear.equals(incomeYear))
                {
                    // The current income year in the loop is equal to the selected income year so look to see if there
                    // is a previous one at the previous index in the loop
                    int prevIncomeYearIndex = i-1;
                    if (prevIncomeYearIndex >= 0)
                    {
                        prevIncomeYear = (Integer)yearList.get(prevIncomeYearIndex);
                    }
                }
                else
                {
                    // The current income year in the loop is > the selected income year so use it.
                    prevIncomeYear = incomeYear;
                }
            }
        }

        // Return the previous income year or null if one wasn't found
        return prevIncomeYear;
    }

    /**
     * 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.cancel", "cancel");
        map.put("button.addDepChild", "gotoAddChild");
        map.put("button.addDepSpouse", "gotoAddSpouse");
        map.put("button.copyDependents", "copyDependents");
        map.put("link.button.viewEditDeps", "display");
        return map;
    }

 }