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

import gov.va.med.fw.ui.struts.AbstractForm;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.esr.common.model.lookup.Country;
import gov.va.med.esr.ui.ApplicationConstants.MessageKeys;

import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.util.MessageResources;

import javax.servlet.http.HttpServletRequest;
import java.util.Iterator;
import java.util.ArrayList;

/**
 * Action form for all the Addresses.  All classes that require Address fields should extend this class.
 *
 * @author Muddaiah Ranga
 * @author Andrew Pach
 * @version 3.0
 */
public class AddressForm extends AbstractForm 
{
    private static final long serialVersionUID = -8872170937416822150L;

    // Constants for some of the fields
    public static final String ADDRESS_LINE1 = "addressLine1";
    public static final String CITY = "city";
    public static final String COUNTY = "county";
    public static final String STATE = "state";
    public static final String ZIP_CODE = "zipCode";
    public static final String ZIP_PLUS_4 = "zipPlus4";
    public static final String PROVINCE = "province";
    public static final String POSTAL_CODE = "postalCode";
    
    public static final String LABEL_ADDRESS_LINE1 = "label.addresses.addressLine1";
    public static final String LABEL_ZIP_CODE = "label.addresses.zipCode";
    public static final String LABEL_CITY = "label.addresses.city";
    public static final String LABEL_STATE = "label.addresses.state";
    public static final String LABEL_PROVINCE = "label.addresses.province";
    public static final String LABEL_POSTAL_CODE = "label.addresses.postalCode";

    private static final ArrayList US_FIELDS = new ArrayList();
    private static final ArrayList NON_US_FIELDS = new ArrayList();

    // Initialize the US and non-US fields
    static
    {
        US_FIELDS.add(COUNTY);
        US_FIELDS.add(STATE);
        US_FIELDS.add(ZIP_CODE);
        US_FIELDS.add(ZIP_PLUS_4);

        NON_US_FIELDS.add(PROVINCE);
        NON_US_FIELDS.add(POSTAL_CODE);
    }

	protected String addressLine1;
	protected String addressLine2;
	protected String addressLine3;
	protected String city;
	protected String county;
	protected String state;
    protected String prevZip;
	protected String zipCode;
	protected String zipPlus4;
    protected String country;
	protected String province;
    protected String postalCode;

    /**
     * Initializes the data on this form.
     */
    protected void initialize()
    {
        addressLine1 = null;
        addressLine2 = null;
        addressLine3 = null;
        zipCode = null;
        prevZip = null;
        zipPlus4 = null;
        city = null;
        state = null;
        county = null;
        country = null;
        province = null;
        postalCode = null;
    }

    public void clearForm() {
    	this.initialize();
    }
    
	public String getAddressLine1()
	{
		return addressLine1;
	}
	
	public void setAddressLine1(String addressLine1) 
	{
		this.addressLine1 = addressLine1;
	}
	
	public String getAddressLine2() 
	{
		return addressLine2;
	}
	
	public void setAddressLine2(String addressLine2) 
	{
		this.addressLine2 = addressLine2;
	}
	
	public String getAddressLine3() 
	{
		return addressLine3;
	}
	
	public void setAddressLine3(String addressLine3) 
	{
		this.addressLine3 = addressLine3;
	}
	
	public String getCity() 
	{
		return city;
	}
	public void setCity(String city) 
	{
		this.city = city;
	}

    public String getCounty() 
    {
        return county;
    }

    public void setCounty(String county) 
    {
        this.county = county;
    }
    
	public String getState() 
	{
		return state;
	}
	
	public void setState(String state) 
	{
		this.state = state;
	}

    public String getPrevZip()
    {
        return prevZip;
    }

    public void setPrevZip(String prevZip)
    {
        this.prevZip = (prevZip != null) ? prevZip.trim() : "";
    }

    public String getZipCode()
	{
		return zipCode;
	}
	
	public void setZipCode(String zipCode) 
	{
		this.zipCode = (zipCode != null) ? zipCode.trim() : "";
	}
	
	public String getZipPlus4() 
	{
		return zipPlus4;
	}
	
	public void setZipPlus4(String zipPlus4) 
	{
		this.zipPlus4 = (zipPlus4 != null) ? zipPlus4.trim() : "";
	}

    public int getZipCodeLength()
    {
        return zipCode != null ? zipCode.length() : 0;
    }

    public int getZipPlus4Length()
    {
        return zipPlus4 != null ? zipPlus4.length() : 0;
    }

	public String getCountry()
	{
		return country;
	}
	
	public void setCountry(String country) 
	{
		this.country = country;
	}

    public String getProvince()
    {
        return province;
    }

    public void setProvince(String province)
    {
        this.province = province;
    }

    public String getPostalCode()
    {
        return postalCode;
    }

    public void setPostalCode(String postalCode)
    {
        this.postalCode = postalCode;
    }

    public boolean isAnyAddressFieldFilled() {
        if(isUSAddress()) {
            if(StringUtils.isNotEmpty(addressLine1) || StringUtils.isNotEmpty(addressLine2) || StringUtils.isNotEmpty(addressLine3) ||
               StringUtils.isNotEmpty(city) || StringUtils.isNotEmpty(county) || StringUtils.isNotEmpty(state) || 
               StringUtils.isNotEmpty(zipCode) || StringUtils.isNotEmpty(zipPlus4)) {
                    return true;
            }
        } else {
            if(StringUtils.isNotEmpty(addressLine1) || StringUtils.isNotEmpty(addressLine2) || StringUtils.isNotEmpty(addressLine3) ||
               StringUtils.isNotEmpty(city) || StringUtils.isNotEmpty(province) || StringUtils.isNotEmpty(postalCode)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Returns whether the address is a US Address.
     * @return True if the country is United States or false if not.
     */
    public boolean isUSAddress()
    {
        return Country.isUSAddress(country);
    }

    /**
     * Calls the super declarative validation first and then filters out error messages that are not
     * associated with the selected country.
     *
     * @param mapping
     * @param request
     * @return The list of filtered validation errors
     */
    public ActionErrors validate(ActionMapping mapping, HttpServletRequest request)
    {
        // Get the list of validation errors from the declarative validation
        ActionErrors validationErrors = super.validate(mapping, request);

        // Initialize a new return set of errors
        ActionErrors returnErrors = new ActionErrors();

        // Iterate through the fields that have declarative errors
        for (Iterator fieldIterator = validationErrors.properties(); fieldIterator.hasNext();)
        {
            // Get one field
            String field = (String)fieldIterator.next();
            if (((isUSAddress()) && (!NON_US_FIELDS.contains(field))) ||
                ((!isUSAddress()) && (!US_FIELDS.contains(field))))
            {
                // If the field is associated with the country, add the list of messages associated with that field
                // to our return list
                for (Iterator messageIter = validationErrors.get(field); messageIter.hasNext();)
                {
                    ActionMessage message = (ActionMessage)messageIter.next();
                    returnErrors.add(field, message);
                }
            }
        }

        // Return the updated error list
        return returnErrors;
    }
    
    protected ActionErrors validateOptionalAddress(ActionMapping mapping, HttpServletRequest request, ActionErrors errors) {
        MessageResources messageResources = this.getResources(request);
        if(isAnyAddressFieldFilled()) {
            if(StringUtils.isEmpty(this.getAddressLine1())) {
                errors.add(ADDRESS_LINE1,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_ADDRESS_LINE1)));
            }
            if(isUSAddress()) {
                if(StringUtils.isEmpty(this.getZipCode())) {
                    errors.add(ZIP_CODE,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_ZIP_CODE)));
                }
                if(StringUtils.isEmpty(this.getCity())) {
                    errors.add(CITY,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_CITY)));
                }
                if(StringUtils.isEmpty(this.getState())) {
                    errors.add(STATE,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_STATE)));
                }
            } else {
                if(StringUtils.isEmpty(this.getProvince())) {
                    errors.add(PROVINCE,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_PROVINCE)));
                }
                if(StringUtils.isEmpty(this.getPostalCode())) {
                    errors.add(POSTAL_CODE,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_POSTAL_CODE)));
                }
            }
        }
        return errors;
    }
    
    protected ActionErrors validateOptionalAddressIncludingCountry(ActionMapping mapping, HttpServletRequest request, ActionErrors errors) {
        MessageResources messageResources = this.getResources(request);
        
        if(isAnyAddressFieldFilled() || (StringUtils.isNotEmpty(country)) ) {
            if(StringUtils.isEmpty(this.getAddressLine1())) {
                errors.add(ADDRESS_LINE1,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_ADDRESS_LINE1)));
            }
            if(isUSAddress()) {
                if(StringUtils.isEmpty(this.getZipCode())) {
                    errors.add(ZIP_CODE,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_ZIP_CODE)));
                }
                if(StringUtils.isEmpty(this.getCity())) {
                    errors.add(CITY,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_CITY)));
                }
                if(StringUtils.isEmpty(this.getState())) {
                    errors.add(STATE,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_STATE)));
                }
            } else {
                if(StringUtils.isEmpty(this.getProvince())) {
                    errors.add(PROVINCE,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_PROVINCE)));
                }
                if(StringUtils.isEmpty(this.getPostalCode())) {
                    errors.add(POSTAL_CODE,new ActionMessage(MessageKeys.ERRORS_REQUIRED,messageResources.getMessage(LABEL_POSTAL_CODE)));
                }
            }
        }
        return errors;
    }
}
