// Package
package gov.va.med.esr.ui.demographic.action;

// Java Classes
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
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.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.util.MessageResources;

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.RelationFinancials;
import gov.va.med.esr.common.model.financials.SpouseFinancials;
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.id.VPIDEntityKey;
import gov.va.med.esr.service.SystemParameterService;
import gov.va.med.esr.service.impl.ChangeEvent;
import gov.va.med.esr.service.impl.HistoricalInfo;
import gov.va.med.esr.service.impl.SystemParameterServiceImpl;
import gov.va.med.esr.ui.ApplicationConstants.MessageKeys;
import gov.va.med.esr.ui.common.action.AddressForm;
import gov.va.med.esr.ui.common.action.PersonAbstractAction;
import gov.va.med.esr.ui.common.util.DateUtils;
import gov.va.med.fw.service.ServiceConfigurationException;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.esr.ui.common.action.AddressValidationAction;
import gov.va.med.esr.ui.util.SessionManager;

/**
 * This struts action is used to support the Demographics Identity Traits page.
 *
 * @author Andrew Pach
 * @version 3.0
 */
// public class DemographicIdentityTraitsAction extends PersonAbstractAction
public class DemographicIdentityTraitsAction extends AddressValidationAction
{
    // Struts forwards
    public static final String FORWARD_DEMOGRAPHIC_IDENTITY_TRAITS = "demographicIdentityTraits";
    public static final String FORWARD_DEMOGRAPHIC_OVERVIEW = "demographicOverview";
    public static final String FORWARD_DEMOGRAPHIC_IDENTITY_TRAITS_SUBMITTED = "submitted";
    public static final String FORWARD_CANCEL = "cancel";
    public static final String INVALID_NAME = "errors.invalidMaidenName";

    public static final String FIELD_NAME_SSN = "ssn";
    public static final String LABEL_SSN = "label.ssn.ssn";
    public static final String MESSAGE_KEY_VETERAN_SSN_USED = "errors.veteranSsnUsed";

    public static final String SUBMITTED_IDENTITY_TRAITS_CHANGE_EVENTS = "Submitted_Change_Events";
    public static final String SUBMITTED_IDENTITY_TRAITS_CHANGE_EVENT_KEYS = "Submitted_Change_Event_Keys";

    public static final String BIRTH_CITY_FIELD = "birthCity";
    public static final String BIRTH_STATE_FIELD = "birthState";

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

    /**
     * Displays the Demographics Identity Traits 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
    {
    	 boolean isAddAPerson = false;
         isAddAPerson = SessionManager.isAddAPerson(request);
         DemographicIdentityTraitsForm ssnForm = getIdentityTraitsForm(form);
         ssnForm.setAddAPerson(isAddAPerson);
         conversionService.convert(getSelectedPerson(request), ssnForm);

         // Check system flag to see if MVI has implemented Self-Identified Gender Identity
         // This will determine if the SIGI dropdown is hidden or not on the screen
         Boolean isSigiAvailable = super.getSystemParameterService().getEsSidIndicator();
         ssnForm.setDisableSelfIdentifiedGenderIdentity(isSigiAvailable);


         if (isAddAPerson && (StringUtils.isEmpty(ssnForm.getMultipleBirth()) || "nd".equalsIgnoreCase(ssnForm.getMultipleBirth())) )
        	ssnForm.setDisabledMultipleBirthIndicator(false);
         else
        	ssnForm.setDisabledMultipleBirthIndicator(true);
        // conversionService.convert(getSelectedPerson(request), getIdentityTraitsForm(form));
         return mapping.findForward(FORWARD_DEMOGRAPHIC_IDENTITY_TRAITS);
    }

    /**
     * Updates the identity traits information.
     *
     * @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
    {
    	DemographicIdentityTraitsForm ssnForm = getIdentityTraitsForm(form);
        Person selectedPerson = (Person)getSelectedPerson(request);
        MessageResources messageResources = ssnForm.getResources(request);
        ActionMessages errors = ssnForm.getActionMessages(request);
        if (isVeteranSSNUsed(ssnForm, selectedPerson))
        {
           // MessageResources messageResources = ssnForm.getResources(request);
           // ActionMessages errors = ssnForm.getActionMessages(request);
            errors.add(FIELD_NAME_SSN, new ActionMessage(MESSAGE_KEY_VETERAN_SSN_USED, messageResources.getMessage(
                LABEL_SSN)));
            return mapping.findForward(FORWARD_DEMOGRAPHIC_IDENTITY_TRAITS);
        }

        // Create some action forwards
        boolean isAddAPerson = false;
        isAddAPerson = SessionManager.isAddAPerson(request);
        ssnForm.setAddAPerson(isAddAPerson);

        if (isAddAPerson){
        	ActionForward overviewSuccessForward =
        		new ActionForward(mapping.findForward(FORWARD_DEMOGRAPHIC_IDENTITY_TRAITS));
        	ActionForward samePageForward = mapping.findForward(FORWARD_DEMOGRAPHIC_IDENTITY_TRAITS);

        	// Validate the state, has to been US ADDRESS
        	if (!stateValid(ssnForm, DemographicIdentityTraitsForm.class, BIRTH_STATE_FIELD, overviewSuccessForward,
            request))
        		return samePageForward;

        	boolean requiredFieldNotEntered = false;
        	// validate required fields last name, gender, ssn, dob
        	if (ssnForm.getLastName()== null || StringUtils.isEmpty(ssnForm.getLastName())){
        		requiredFieldNotEntered = true;
        		errors.add("LastName", new ActionMessage(MessageKeys.ERRORS_REQUIRED, "Last Name"));
        	}
        	if (ssnForm.getSsn()== null || StringUtils.isEmpty(ssnForm.getSsn())){
        		requiredFieldNotEntered = true;
       		 	errors.add("Ssn", new ActionMessage(MessageKeys.ERRORS_REQUIRED, "SSN"));
        	}
        	if (ssnForm.getGender()== null || StringUtils.isEmpty(ssnForm.getGender())){
        		requiredFieldNotEntered = true;
        		errors.add("Gender", new ActionMessage(MessageKeys.ERRORS_REQUIRED, "Gender"));
        	}
        	if (ssnForm.getDateOfBirth()== null || StringUtils.isEmpty(ssnForm.getDateOfBirth())){
        		requiredFieldNotEntered = true;
        		errors.add("DateOfBirth", new ActionMessage(MessageKeys.ERRORS_REQUIRED, "Date Of Birth"));
        	}
        	//CCR 13890, maiden name cannot be unk or unknown;  or APTF will fail
        	if (ssnForm.getMothersMaidenName().trim().equalsIgnoreCase("UNK") || ssnForm.getMothersMaidenName().trim().equalsIgnoreCase("UNKNOWN")) {
        		requiredFieldNotEntered = true;
        		errors.add("MothersMaidenName", new ActionMessage(INVALID_NAME, "Value of Mother's Maiden Name"));
        	}
        	if (requiredFieldNotEntered)
        		return samePageForward;

        	// clone the person
            Person updatedPerson = (Person)selectedPerson.clone();

            //convert
            conversionService.convert(getIdentityTraitsForm(form), updatedPerson);

            //save the person back to session
            updateSelectedPerson(request, updatedPerson);
            return mapping.findForward(FORWARD_DEMOGRAPHIC_OVERVIEW);
        }
        //clone the person
        Person updatedPerson = (Person)selectedPerson.clone();

        //convert
        conversionService.convert(getIdentityTraitsForm(form), updatedPerson);

       // if (! isAddAPerson){
        //update when business/rule services are ready
        updatedPerson = getDemographicService().updateIdentityTraits(updatedPerson);

        //save the person back to session
        updateSelectedPerson(request, updatedPerson);
     //   }

        return mapping.findForward(FORWARD_DEMOGRAPHIC_OVERVIEW);
    }

    protected ActionForward handleOptimisticLockException(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        form.reset(mapping, request);
        return display(mapping, form, request, response);
    }

    /**
     * Cancels this page and goes to the demographics overview screen.
     *
     * @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_CANCEL);
    }

    public ActionForward displaySubmittedTraits(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
    	SubmittedIdentityTraitsForm actionForm = (SubmittedIdentityTraitsForm) form;

    	Set changeEventSet = null;

    	// CCR10471 -- Add a Person: Do not look up history.
    	boolean isAddAPerson = false;
        isAddAPerson = SessionManager.isAddAPerson(request);
        if (!isAddAPerson) {
        	VPIDEntityKey vpid = this.getSelectedPerson(request).getVPIDEntityKey();
     		changeEventSet = this.getDemographicService().getSubmittedIdentityTraitsChangeTimes(vpid);
    	}
    	if(changeEventSet == null || changeEventSet.size() == 0) {
            request.getSession().setAttribute(SUBMITTED_IDENTITY_TRAITS_CHANGE_EVENTS, null);
            request.getSession().setAttribute(SUBMITTED_IDENTITY_TRAITS_CHANGE_EVENT_KEYS, null);
    	} else {
            // Comparator specific to ChangeEvent defined as in inner class
            Comparator comparator = new Comparator()
            {
                public int compare(Object pObject1, Object pObject2)
                {
                    ChangeEvent event1 = (ChangeEvent)pObject1;
                    ChangeEvent event2 = (ChangeEvent)pObject2;
                    if (event1 == null || event1.getTimeStamp() == null) return -1;
                    if (event2 == null || event2.getTimeStamp() == null) return 1;
                    return (event2.getTimeStamp().compareTo(event1.getTimeStamp()));
                }
            };

            List orderedChangeEvents = new ArrayList(changeEventSet);
            Collections.sort(orderedChangeEvents, comparator);

	    	request.getSession().setAttribute(SUBMITTED_IDENTITY_TRAITS_CHANGE_EVENTS, orderedChangeEvents);

	        List eventKeys = new ArrayList();
	        for (Iterator iter = orderedChangeEvents.iterator(); iter.hasNext();)
	        {
	            Timestamp time = ((ChangeEvent)iter.next()).getTimeStamp();
	            eventKeys.add(DateUtils.formatWithTime(time, null));
	        }
	        request.getSession().setAttribute(SUBMITTED_IDENTITY_TRAITS_CHANGE_EVENT_KEYS, eventKeys);

	        // Get the first change event to display the data
	        ChangeEvent changeEvent = (ChangeEvent) orderedChangeEvents.iterator().next();
	        String key = DateUtils.formatWithTime(changeEvent.getTimeStamp(), null);
	        actionForm.setChangeEventKey(key);
	        return displaySubmittedTraitsForChangeEvent(mapping, form, request, response);
    	}

        return mapping.findForward(FORWARD_DEMOGRAPHIC_IDENTITY_TRAITS_SUBMITTED);
    }

    public ActionForward displaySubmittedTraitsForChangeEvent(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        // Get change events from session
        List changeEvents = (List) request.getSession().getAttribute(SUBMITTED_IDENTITY_TRAITS_CHANGE_EVENTS);

        // Get the selected change event key from the form
        SubmittedIdentityTraitsForm actionForm = (SubmittedIdentityTraitsForm) form;
        String key = actionForm.getChangeEventKey();

    	if(StringUtils.isNotBlank(key)) {
	        // Get the selected change event
	        for (Iterator iter = changeEvents.iterator(); iter.hasNext();)
	        {
	            ChangeEvent selectedEvent = (ChangeEvent)iter.next();
	            if (key.equals(DateUtils.formatWithTime(selectedEvent.getTimeStamp(), null)))
	            {
	                //Get the history information for the selected event
	                HistoricalInfo historicalInfo = this.getDemographicService().getSubmittedIdentityTraitsHistoryByChangeTime(selectedEvent);

	                Person personWithTargetTraits = (Person) historicalInfo.getEntity();

	                // convert PersonIdentityTraits to form data
	                conversionService.convert(personWithTargetTraits, actionForm);
	                break;
	            }
	        }
    	}
    	return mapping.findForward(FORWARD_DEMOGRAPHIC_IDENTITY_TRAITS_SUBMITTED);
    }

    /**
     * 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 DemographicSocialSecurityForm
     * @throws gov.va.med.fw.service.ServiceConfigurationException if the form is null or of an incorrect type.
     */
    protected DemographicIdentityTraitsForm getIdentityTraitsForm(ActionForm form) throws ServiceConfigurationException
    {
        DemographicIdentityTraitsForm identityTraitsForm =
            (form instanceof DemographicIdentityTraitsForm) ? (DemographicIdentityTraitsForm)form : null;
        if (identityTraitsForm == null)
        {
            throw new ServiceConfigurationException("DemographicIdentityTraitsForm not properly configured.");
        }
        return identityTraitsForm;
    }

    private boolean isVeteranSSNUsed(DemographicIdentityTraitsForm form, Person person)
    {
        if (StringUtils.isNotEmpty(form.getSsn()))
        {
            String vetSsn = SSN.formatSSN(form.getSsn());
            Collection finStmts = person.getFinancialStatements().values();

            for (Iterator finStmtIter = finStmts.iterator(); finStmtIter.hasNext();)
            {
                FinancialStatement finStmt = (FinancialStatement)finStmtIter.next();

                // Check Spouses
                Set spouseFins = finStmt.getSpouseFinancials();
                for (Iterator iterator = spouseFins.iterator(); iterator.hasNext();)
                {
                    String ssn = getRelationSSN((SpouseFinancials)iterator.next());
                    if (StringUtils.equals(vetSsn, ssn))
                    {
                        return true;
                    }
                }

                // Check Dependents
                Set depFins = finStmt.getDependentFinancials();
                for (Iterator depIter = depFins.iterator(); depIter.hasNext();)
                {
                    String ssn = getRelationSSN((DependentFinancials)depIter.next());
                    if (StringUtils.equals(vetSsn, ssn))
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    protected String getRelationSSN(RelationFinancials relFinancial)
    {
        if (relFinancial instanceof SpouseFinancials)
        {
            SpouseFinancials spouseFin = (SpouseFinancials)relFinancial;
            SSN ssn = (spouseFin != null && spouseFin.getReportedOn() != null) ?
                spouseFin.getReportedOn().getOfficialSsn() : null;
            return ssn == null ? null : ssn.getFormattedSsnText();
        }

        if (relFinancial instanceof DependentFinancials) {
            DependentFinancials depFin = (DependentFinancials)relFinancial;
            SSN ssn =
                (depFin != null && depFin.getReportedOn() != null) ? depFin.getReportedOn().getOfficialSsn() : null;
            return ssn == null ? null : ssn.getFormattedSsnText();
        }

        return null;
    }

    /**
     * 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.update", "update");
        map.put("button.continue", "update");
        map.put("button.cancel", "cancel");
        map.put("text.subMenu.identityTraits", "display");

        map.put("button.identityTraits.viewSubmittedData", "displaySubmittedTraits");
        map.put("button.identityTraits.viewSubmittedDataForChangeEvent", "displaySubmittedTraitsForChangeEvent");

        return map;
    }

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub

	}
}
