com.sfs.whichdoctor.dao.AddressDAOImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.sfs.whichdoctor.dao.AddressDAOImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2009 David Harrison.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl-3.0.html
 *
 * Contributors:
 *     David Harrison - initial API and implementation
 ******************************************************************************/
package com.sfs.whichdoctor.dao;

import com.sfs.beans.ObjectTypeBean;
import com.sfs.beans.PrivilegesBean;
import com.sfs.beans.UserBean;
import com.sfs.dao.ObjectTypeDAO;
import com.sfs.dao.SFSDaoException;
import com.sfs.whichdoctor.beans.AddressBean;
import com.sfs.whichdoctor.beans.IsbTransactionBean;
import com.sfs.whichdoctor.beans.PreferencesBean;
import com.sfs.whichdoctor.beans.WhichDoctorBean;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.net.URL;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.codehaus.xfire.client.Client;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.RowMapper;

/**
 * The Class AddressDAOImpl.
 */
public class AddressDAOImpl extends WhichDoctorBaseDAOImpl implements AddressDAO {

    /** The data logger. */
    private static Logger dataLogger = Logger.getLogger(AddressDAOImpl.class);

    /** The postcode url. */
    private String postcodeUrl;

    /** The object type dao. */
    @Resource
    private ObjectTypeDAO objectTypeDAO;

    /** The isb transaction dao. */
    @Resource
    private IsbTransactionDAO isbTransactionDAO;

    /** The address verification dao. */
    @Resource
    private AddressVerificationDAO addressVerificationDAO;

    /** The person dao. */
    @Resource
    private PersonDAO personDAO;

    /** The preferences dao. */
    @Resource
    private PreferencesDAO preferencesDAO;

    /** The organisation dao. */
    @Resource
    private OrganisationDAO organisationDAO;

    /** The search index dao. */
    @Resource
    private SearchIndexDAO searchIndexDAO;

    /** The Constant MAX_ADDRESSES. */
    private static final int MAXADDRESSLINES = 7;

    /**
     * Sets the postcode url.
     *
     * @param postcodeUrlVal the new postcode url
     */
    public final void setPostcodeUrl(final String postcodeUrlVal) {
        this.postcodeUrl = postcodeUrlVal;
    }

    /**
     * Get a collection of AddressBeans for a specified GUID.
     *
     * @param guid the guid
     * @param allAddresses the all addresses
     * @param addressClass the address class
     * @param addressType the address type
     *
     * @return the collection< address bean>
     *
     * @throws com.sfs.whichdoctor.dao.WhichDoctorDaoException * @throws
     *             WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    public final Collection<AddressBean> load(final int guid, final boolean allAddresses, final String addressClass,
            final String addressType) throws WhichDoctorDaoException {

        dataLogger.info("Addresses for GUID: " + guid + " requested");

        boolean specificAddress = false;

        String sql = getSQL().getValue("address/load")
                + " WHERE address.Active = true AND address.ReferenceGUID = ?";

        Collection<Object> variables = new ArrayList<Object>();
        /* The GUID value is the first variable */
        variables.add(guid);

        if (addressClass != null) {
            if (addressClass.compareTo("") != 0 && addressClass.compareTo("Preferred") != 0) {
                sql += " AND addresstype.Class = ?";
                variables.add(addressClass);
                specificAddress = true;
            }
        }
        if (addressType != null) {
            if (addressType.compareTo("") != 0 && addressType.compareTo("Preferred") != 0) {
                sql += " AND addresstype.Name = ?";
                variables.add(addressType);
                specificAddress = true;
            }
        }
        sql += " ORDER BY PrimaryAddress DESC";
        if (!allAddresses) {
            sql += " LIMIT 1";
        }

        Collection<AddressBean> addresses = new ArrayList<AddressBean>();

        try {
            addresses = this.getJdbcTemplateReader().query(sql, variables.toArray(), new RowMapper() {
                public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                    return loadAddress(rs);
                }
            });

        } catch (IncorrectResultSizeDataAccessException ie) {
            dataLogger.debug("No results found for search: " + ie.getMessage());
        }

        if (specificAddress && addresses.size() == 0) {
            /**
             * Specific address type defined but no result found Try getting a
             * more generic address
             */
            if (addressType != null) {
                if (addressType.compareTo("") != 0) {
                    addresses = load(guid, allAddresses, addressClass, null);
                }
            }
            if (addresses.size() == 0) {
                if (addressClass != null) {
                    if (addressClass.compareTo("") != 0) {
                        addresses = load(guid, allAddresses, null, null);
                    }
                }
            }
        }
        return addresses;
    }

    /**
     * Load and AddressBean based on its id.
     *
     * @param addressId the address id
     * @return the address bean
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    public final AddressBean load(final int addressId) throws WhichDoctorDaoException {

        dataLogger.info("Getting addressId:" + addressId);

        final String loadId = this.getSQL().getValue("address/load") + " WHERE address.AddressId = ?";

        AddressBean address = null;
        try {
            address = (AddressBean) this.getJdbcTemplateReader().queryForObject(loadId, new Object[] { addressId },
                    new RowMapper() {
                        public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                            return loadAddress(rs);
                        }
                    });

        } catch (IncorrectResultSizeDataAccessException ie) {
            dataLogger.debug("No results found for search: " + ie.getMessage());
        }
        return address;
    }

    /**
     * Load and AddressBean based on its guid.
     *
     * @param guid the guid
     * @return the address bean
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    public final AddressBean loadGUID(final int guid) throws WhichDoctorDaoException {

        dataLogger.info("Getting guid:" + guid);

        final String loadGUID = getSQL().getValue("address/load") + " WHERE address.GUID = ? AND Active = true";

        AddressBean address = null;
        try {
            address = (AddressBean) this.getJdbcTemplateReader().queryForObject(loadGUID, new Object[] { guid },
                    new RowMapper() {
                        public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                            return loadAddress(rs);
                        }
                    });

        } catch (IncorrectResultSizeDataAccessException ie) {
            dataLogger.debug("No results found for search: " + ie.getMessage());
        }
        return address;
    }

    /**
     * Load all the active AddressBeans.
     *
     * @return the collection
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    public final Collection<AddressBean> loadActive() throws WhichDoctorDaoException {

        final String loadActive = getSQL().getValue("address/load") + " WHERE address.Active = true";

        Collection<AddressBean> addresses = new ArrayList<AddressBean>();
        try {
            addresses = this.getJdbcTemplateReader().query(loadActive, new RowMapper() {
                public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                    return loadAddress(rs);
                }
            });

        } catch (IncorrectResultSizeDataAccessException ie) {
            dataLogger.debug("No results found for search: " + ie.getMessage());
        }
        return addresses;
    }

    /**
     * Create the AddressBean.
     *
     * @param address the address
     * @param checkUser the check user
     * @param privileges the privileges
     * @return the int
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final int create(final AddressBean address, final UserBean checkUser, final PrivilegesBean privileges)
            throws WhichDoctorDaoException {
        // Get the geocode for the address
        address.setGeocode(getGeocode(address));
        address.setActive(true);

        int id = save(address, checkUser, privileges, "create");

        AddressBean newAddress = this.load(id);
        performAddressVerification(null, newAddress);

        return id;
    }

    /**
     * Modify the AddressBean.
     *
     * @param address the address
     * @param checkUser the check user
     * @param privileges the privileges
     * @return the int
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final int modify(final AddressBean address, final UserBean checkUser, final PrivilegesBean privileges)
            throws WhichDoctorDaoException {

        AddressBean oldAddress = this.loadGUID(address.getGUID());

        if (oldAddress.compare(address, true)) {
            // The address has been changed, get the geocode for the address
            address.setGeocode(getGeocode(address));
            address.setVerificationStatus("Unverified address");
        } else {
            // The address has not been changed, carry over the geocode and verification
            address.setGeocode(oldAddress.getGeocode());
            address.setVerificationStatus(oldAddress.getVerificationStatus());
        }
        // If the address has been verified set the appropriate status
        if (StringUtils.equalsIgnoreCase(address.getLogMessage("modify"),
                "Automatic address verification update")) {
            address.setVerificationStatus("Verified address");
        }
        address.setActive(true);

        int id = save(address, checkUser, privileges, "modify");

        AddressBean newAddress = this.load(id);

        if (!StringUtils.equalsIgnoreCase(address.getLogMessage("modify"),
                "Automatic address verification update")) {
            performAddressVerification(oldAddress, newAddress);
        }
        return id;
    }

    /**
     * Delete the AddressBean.
     *
     * @param address the address
     * @param checkUser the check user
     * @param privileges the privileges
     * @return true, if successful
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final boolean delete(final AddressBean address, final UserBean checkUser,
            final PrivilegesBean privileges) throws WhichDoctorDaoException {
        address.setActive(false);
        int deleted = save(address, checkUser, privileges, "delete");

        boolean success = false;

        if (deleted > 0) {
            success = true;
            performAddressVerification(address, null);
        }

        return success;
    }

    /**
     * Save the AddressBean.
     *
     * @param address the address
     * @param checkUser the check user
     * @param privileges the privileges
     * @param action the action
     *
     * @return the int
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    private int save(final AddressBean address, final UserBean checkUser, final PrivilegesBean privileges,
            final String action) throws WhichDoctorDaoException {

        // Check required information within address bean is present
        if (address.getContactClass() == null) {
            throw new WhichDoctorDaoException("Contact class cannot be null");
        }
        if (address.getContactClass().compareTo("") == 0) {
            throw new WhichDoctorDaoException("Contact class cannot be an empty string");
        }
        if (address.getContactType() == null) {
            throw new WhichDoctorDaoException("Contact type cannot be null");
        }
        if (address.getContactType().compareTo("") == 0) {
            throw new WhichDoctorDaoException("Contact type cannot be an empty string");
        }
        if (address.getState() == null) {
            address.setState("");
        }
        if (address.getCountry() == null) {
            throw new WhichDoctorDaoException("Addresses' country field cannot be null");
        }
        if (address.getCountry().compareTo("") == 0) {
            throw new WhichDoctorDaoException("Addresses' country field cannot be an empty string");
        }
        if (address.getReferenceGUID() == 0) {
            throw new WhichDoctorDaoException("Address requires a valid Reference GUID number");
        }
        if (!privileges.getPrivilege(checkUser, "addresses", action)) {
            throw new WhichDoctorDaoException("Insufficient user credentials to " + action + " address entry");
        }

        /* Identify the AddressTypeId */
        int addressTypeId = 0;
        try {
            ObjectTypeBean object = this.getObjectTypeDAO().load("Address Type", address.getContactType(),
                    address.getContactClass());
            addressTypeId = object.getObjectTypeId();
        } catch (SFSDaoException sfe) {
            dataLogger.error("Error loading objecttype for address type: " + sfe.getMessage());
            throw new WhichDoctorDaoException("Address type not found");
        }

        /* Identify the VerificationStatusId */
        int verificationStatusId = 0;
        try {
            ObjectTypeBean object = this.getObjectTypeDAO().load("Address Verification Status", "",
                    address.getVerificationStatus());
            verificationStatusId = object.getObjectTypeId();
        } catch (SFSDaoException sfe) {
            dataLogger.error("Error loading address verification status for address: " + sfe.getMessage());
            throw new WhichDoctorDaoException("Address requires a valid address verification status");
        }

        /* Identify the StateId */
        int stateId = 0;
        try {
            ObjectTypeBean object = this.getObjectTypeDAO().load("State/Country", address.getState(),
                    address.getCountry());
            stateId = object.getObjectTypeId();
        } catch (SFSDaoException sfe) {
            dataLogger.error("Error loading state/country for address: " + sfe.getMessage());
            throw new WhichDoctorDaoException("Address requires a valid country/state combination");
        }

        /* Identify the RegionId */
        if (StringUtils.isBlank(address.getRegion())) {
            address.setRegion(getRegion(address.getCity(), address.getState(), address.getCountry()));
        }

        int regionId = 0;
        try {
            ObjectTypeBean object = this.getObjectTypeDAO().load("Region", "", address.getRegion());
            regionId = object.getObjectTypeId();
        } catch (SFSDaoException sfe) {
            dataLogger.error(
                    "Error loading objecttype for region: " + address.getRegion() + " - " + sfe.getMessage());
        }

        int addressId = 0;

        /* Perform a postcode lookup if none is defined */
        boolean postCodeExists = false;

        if (address.getPostCode() != null) {
            if (address.getPostCode().compareTo("") != 0) {
                // PostCode exists
                postCodeExists = true;
            }
        }
        if (!postCodeExists) {
            boolean doLookup = false;
            if (address.getCountry().compareTo("New Zealand") == 0) {
                doLookup = true;
            }
            if (address.getCountry().compareTo("Australia") == 0) {
                doLookup = true;
            }
            if (doLookup) {
                // Perform PostCode lookup
                address.setPostCode(this.getPostcode(address));
            }
        }

        // The parameters for inserting into the database
        final ArrayList<Object> parameters = setParameters(address, addressTypeId, stateId, regionId,
                verificationStatusId, checkUser, action);

        /* Begin the ISB transaction */
        IsbTransactionBean isbTransaction = this.isbTransactionDAO.begin(address.getReferenceGUID());

        try {
            Integer[] result = this.performUpdate("address", address.getGUID(), parameters, "Address", checkUser,
                    action);
            /* Set the returned guid and id values */
            address.setGUID(result[0]);
            addressId = result[1];
        } catch (Exception e) {
            dataLogger.error("Error processing accreditation record: " + e.getMessage());
            throw new WhichDoctorDaoException("Error processing accreditation record: " + e.getMessage());
        }

        if (addressId > 0) {

            // Update person city/region/primary address details
            // to reflect modification
            updatePrimary(address, action);

            /* Update the region and resident country indexes */
            updateIndexes(address.getReferenceGUID());

            /* Commit the ISB transaction */
            this.isbTransactionDAO.commit(isbTransaction);
        }
        return addressId;
    }

    /**
     * Gets the postcode.
     *
     * @param address the address
     *
     * @return the postcode
     */
    private String getPostcode(final AddressBean address) {
        String postCode = "";

        String addressField = "";
        for (int i = 0; i < address.getAddressFieldCount(); i++) {
            addressField += address.getAddressField(i);
            if (i + 1 < address.getAddressFieldCount()) {
                addressField += ",";
            }
        }
        String stateField = address.getState();
        String countryField = address.getCountry();

        /* Test that none of these fields are null */
        if (stateField == null) {
            stateField = "";
        }
        if (countryField == null) {
            countryField = "";
        }

        dataLogger.info("Performing postcode lookup: " + addressField + "," + stateField + "," + countryField);

        /* Perform a web service call using XFire libraries */
        try {
            Client client = new Client(new URL(this.postcodeUrl));

            Object[] results = client.invoke("lookup", new Object[] { addressField, stateField, countryField });
            postCode = (String) results[0];

            dataLogger.info("Postcode returned: " + (String) results[0]);
        } catch (Exception e) {
            dataLogger.error("Error performing postcode web service lookup: " + e.getMessage());
        }

        return postCode;
    }

    /**
     * Gets the geocode.
     *
     * @param address the address
     *
     * @return the geocode
     */
    private String getGeocode(final AddressBean address) {
        String geoCode = "";

        String addressField = "";
        for (int i = 0; i < address.getAddressFieldCount(); i++) {
            addressField += address.getAddressField(i);
            if (i + 1 < address.getAddressFieldCount()) {
                addressField += ",";
            }
        }
        String stateField = address.getState();
        String countryField = address.getCountry();

        // Test that none of these fields are null
        if (stateField == null) {
            stateField = "";
        }
        if (countryField == null) {
            countryField = "";
        }

        dataLogger.info("Performing geocode lookup: " + addressField + "," + stateField + "," + countryField);

        /* Perform a web service call using XFire libraries */
        try {
            Client client = new Client(new URL(this.postcodeUrl));

            Object[] results = client.invoke("geocode", new Object[] { addressField, stateField, countryField });
            geoCode = (String) results[0];

            dataLogger.info("Geocode returned: " + (String) results[0]);
        } catch (Exception e) {
            dataLogger.error("Error performing geocode web service lookup: " + e.getMessage());
        }

        return geoCode;
    }

    /**
     * Gets the state based on the supplied state abbreviation.
     *
     * @param stateAbbreviation the state abbreviation
     * @return the state
     */
    public final String getStateFromAbbreviation(final String stateAbbreviation) {

        String state = "";

        if (StringUtils.isNotBlank(stateAbbreviation)) {
            try {
                state = this.getJdbcTemplateReader().queryForObject(
                        this.getSQL().getValue("address/findStateFromAbbreviation"),
                        new Object[] { stateAbbreviation }, String.class);
            } catch (DataAccessException dae) {
                dataLogger.error("Error loading state: " + dae.getMessage());
            }

            if (StringUtils.isBlank(state)) {
                state = stateAbbreviation;
            }
        }
        return state;
    }

    /**
     * Gets the country based on the supplied country abbreviation.
     *
     * @param countryAbbreviation the country abbreviation
     * @return the country
     */
    public final String getCountryFromAbbreviation(final String countryAbbreviation) {

        String country = "";

        if (StringUtils.isNotBlank(countryAbbreviation)) {
            try {
                country = this.getJdbcTemplateReader().queryForObject(
                        this.getSQL().getValue("address/findCountryFromAbbreviation"),
                        new Object[] { countryAbbreviation }, String.class);
            } catch (DataAccessException dae) {
                dataLogger.error("Error loading country: " + dae.getMessage());
            }

            if (StringUtils.isBlank(country)) {
                country = countryAbbreviation;
            }
        }
        return country;
    }

    /**
     * Gets the state based on the supplied city and country values.
     *
     * @param city the city
     * @param country the country
     * @return the state
     */
    public final String getState(final String city, final String country) {

        String state = "";

        if (StringUtils.isNotBlank(city) && StringUtils.isNotBlank(country)) {
            try {
                state = this.getJdbcTemplateReader().queryForObject(this.getSQL().getValue("address/findState"),
                        new Object[] { city, country }, String.class);
            } catch (DataAccessException dae) {
                dataLogger.error("Error loading state: " + dae.getMessage());
            }
        }
        return state;
    }

    /**
     * Gets the region based on the supplied city, state and country values.
     *
     * @param city the city
     * @param state the state
     * @param country the country
     * @return the region
     */
    public final String getRegion(final String city, final String state, final String country) {

        // By default the region is outside New Zealand
        String region = "Outside N.Z.";

        if (StringUtils.equalsIgnoreCase(country, "New Zealand")) {
            region = "Unknown";
            try {
                region = this.getJdbcTemplateReader().queryForObject(this.getSQL().getValue("address/findRegion"),
                        new Object[] { city, state, country }, String.class);
            } catch (DataAccessException dae) {
                dataLogger.error("Error loading region: " + dae.getMessage());
            }
        }
        return region;
    }

    /**
     * If the AddressBean is primary ensure no other primary entry exists for
     * the ReferenceGUID.
     *
     * @param address the address
     * @param action the action
     *
     * @throws WhichDoctorDaoException the whichdoctor dao exception
     */
    private void updatePrimary(final AddressBean address, final String action) throws WhichDoctorDaoException {

        if (address.getPrimary()) {

            if (action.compareTo("delete") != 0) {
                /* Find old primary address and turn off flag */

                this.getJdbcTemplateWriter().update(this.getSQL().getValue("address/updatePrimary"),
                        new Object[] { false, address.getReferenceGUID(), address.getGUID(), true });

            }
            updateAddressIndexes(address, action);
        }
    }

    /**
     * Update the person/organisation City index field to match the new address.
     *
     * @param address the AddressBean
     * @param action the action
     *
     * @return boolean result
     *
     * @throws WhichDoctorDaoException the whichdoctor dao exception
     */
    public final boolean updateAddressIndexes(final AddressBean address, final String action)
            throws WhichDoctorDaoException {

        String city = "";
        String country = "";
        int stateId = 0;

        // Delete the existing indexes
        try {
            this.searchIndexDAO.delete(address.getReferenceGUID(), "City");
            this.searchIndexDAO.delete(address.getReferenceGUID(), "Country");
        } catch (WhichDoctorDaoException wde) {
            dataLogger.error("Error deleting address indexes: " + wde.getMessage());
        }

        // Update the index if the action is not a delete
        if (!StringUtils.equalsIgnoreCase(action, "delete")) {

            if (StringUtils.isNotBlank(address.getCity())) {
                city = address.getCity();
            }

            try {
                ObjectTypeBean countryObject = this.objectTypeDAO.load("State/Country", address.getState(),
                        address.getCountry());

                country = countryObject.getClassName();
                stateId = countryObject.getObjectTypeId();
            } catch (SFSDaoException e) {
                dataLogger.error("Error loading state/country object: " + e.getMessage());
            }

            try {
                this.searchIndexDAO.update(address.getReferenceGUID(), "City", 0, 0, city);
                this.searchIndexDAO.update(address.getReferenceGUID(), "Country", stateId, 0, country);
            } catch (WhichDoctorDaoException wde) {
                dataLogger.error("Error updating address indexes: " + wde.getMessage());
            }
        }

        return true;
    }

    /**
     * Update the address geocode.
     *
     * @param address the address
     * @return true, if successful
     */
    public final boolean updateGeocode(final AddressBean address) {

        boolean success = false;

        String geocode = getGeocode(address, 0);

        if (geocode == null) {
            geocode = "";
        }

        try {
            final int updateCount = this.getJdbcTemplateWriter().update(
                    this.getSQL().getValue("address/updateGeocode"), new Object[] { geocode, address.getId() });

            if (updateCount > 0) {
                success = true;
                dataLogger.info("Successfully updated geocode for address Id: " + address.getId());
            }

        } catch (Exception e) {
            dataLogger.error("Error updating geocode for address Id: " + address.getId() + ", " + e.getMessage());
        }
        return success;
    }

    /**
     * Perform a geocode lookup.
     *
     * @param address the address
     * @param ignoreField the ignore field
     * @return the geocode
     */
    public final String getGeocode(final AddressBean address, final int ignoreField) {

        String geoCode = "";

        String addressField = "";
        for (int i = 0; i < address.getAddressFieldCount(); i++) {
            addressField += address.getAddressField(i);
            if (i + 1 < address.getAddressFieldCount()) {
                addressField += ",";
            }
        }
        String stateField = address.getState();
        String countryField = address.getCountry();

        /* Test that none of these fields are null */
        if (stateField == null) {
            stateField = "";
        }
        if (countryField == null) {
            countryField = "";
        }

        /* Perform a web service call using XFire libraries */
        try {
            Client client = new Client(new URL(this.postcodeUrl));

            Object[] results = client.invoke("geocode", new Object[] { addressField, stateField, countryField });
            geoCode = (String) results[0];

            dataLogger.info("Geocode returned: " + (String) results[0]);
        } catch (Exception e) {
            dataLogger.error("Error performing geocode web service lookup: " + e.getMessage());
        }

        return geoCode;
    }

    /**
     * Updates the verification status of the supplied address guid.
     *
     * @param status the address verification status
     * @param guid the address guid
     */
    public void updateVerificationStatus(final String status, final int guid) {

        /* Identify the VerificationStatusId */
        int verificationStatusId = 0;
        try {
            ObjectTypeBean object = this.getObjectTypeDAO().load("Address Verification Status", "", status);
            verificationStatusId = object.getObjectTypeId();
        } catch (SFSDaoException sfe) {
            dataLogger.error("Error loading address verification status for address: " + sfe.getMessage());
        }

        if (verificationStatusId > 0) {
            this.getJdbcTemplateWriter().update(this.getSQL().getValue("address/updateVerificationStatus"),
                    new Object[] { verificationStatusId, guid });
        }
    }

    /**
     * Update postcode and geocode.
     *
     * @param countryVal the country
     * @param user the user
     * @param privileges the privileges
     * @return the hash map
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    public final HashMap<String, Collection<Integer>> updatePostcodeAndGeocode(final String countryVal,
            final UserBean user, final PrivilegesBean privileges) throws WhichDoctorDaoException {
        /**
         * Load the addresses based on the country and update their postcode.
         * Returns a hashmap containing the GUIDs of addresses 'updated' and
         * 'not updated'
         **/
        HashMap<String, Collection<Integer>> results = new HashMap<String, Collection<Integer>>();

        Collection<Integer> updated = new ArrayList<Integer>();
        Collection<Integer> notUpdated = new ArrayList<Integer>();

        String country = "";
        if (StringUtils.isNotBlank(countryVal)) {
            country = countryVal;
        }

        Collection<AddressBean> addresses = new ArrayList<AddressBean>();

        final String loadCountrySQL = getSQL().getValue("address/load")
                + " WHERE address.Active = true AND loc_state.Class = ?";

        try {
            addresses = this.getJdbcTemplateReader().query(loadCountrySQL, new Object[] { country },
                    new RowMapper() {
                        public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                            return loadAddress(rs);
                        }
                    });

        } catch (IncorrectResultSizeDataAccessException ie) {
            dataLogger.debug("No results found for this search: " + ie.getMessage());
        }

        for (AddressBean address : addresses) {

            try {
                String existingPostcode = address.getPostCode();
                String existingGeocode = address.getGeocode();
                if (existingPostcode == null) {
                    existingPostcode = "";
                }
                if (existingGeocode == null) {
                    existingGeocode = "";
                }

                String newPostcode = this.getPostcode(address);
                String newGeocode = this.getGeocode(address);
                if (newPostcode == null) {
                    newPostcode = "";
                }
                if (newGeocode == null) {
                    newGeocode = "";
                }

                boolean updateAddress = false;

                if (newPostcode.compareTo("") != 0) {
                    if (newPostcode.compareTo(existingPostcode) != 0) {
                        // A postcode was found update
                        address.setPostCode(newPostcode);
                        updateAddress = true;
                    }
                }
                if (newGeocode.compareTo("") != 0) {
                    if (newGeocode.compareTo(existingGeocode) != 0) {
                        // A geocode was found update
                        address.setGeocode(newGeocode);
                        updateAddress = true;
                    }
                }
                if (updateAddress) {
                    address.setLogMessage("Refreshed postcode/geocode");

                    modify(address, user, privileges);
                    updated.add(address.getGUID());
                    dataLogger.error("Updated postcode/geocode for address GUID: " + address.getGUID());
                } else {
                    dataLogger.error("Postcode/geocode not updated for address GUID: " + address.getGUID());
                    notUpdated.add(address.getGUID());
                }
            } catch (Exception e) {
                dataLogger.error("Error updating postcode/geocode for address GUID " + address.getGUID() + ": "
                        + e.getMessage());
                notUpdated.add(address.getGUID());
            }
        }
        dataLogger.error("Postcode/geocode update process complete, " + updated.size() + " addresses changed, "
                + notUpdated.size() + " not updated");

        results.put("updated", updated);
        results.put("not updated", notUpdated);

        return results;
    }

    /**
     * Gets the region id for the supplied GUID.
     * Returns the id for "Unknown" region if no valid entries are found.
     *
     * @param referenceGUID the reference GUID
     *
     * @return the regionId for the supplied reference GUID
     */
    public final int getRegionId(final int referenceGUID) {

        int regionId = 0;

        Collection<AddressBean> addresses = null;
        try {
            addresses = this.load(referenceGUID, true, null, null);
        } catch (WhichDoctorDaoException wde) {
            dataLogger.error("Error loading addresses for GUID: " + wde.getMessage());
        }

        HashMap<Integer, String> regions = new HashMap<Integer, String>();

        if (addresses != null) {
            for (AddressBean address : addresses) {
                if (!address.getReturnedMail() && !StringUtils.equalsIgnoreCase(address.getRegion(), "Unknown")) {

                    int x = 0;

                    if (address.getRequestNoMail()) {
                        x = 1;
                    }
                    if (address.getPrimary()) {
                        x = 2;
                    }
                    regions.put(x, address.getRegion());
                }
            }
        }

        String region = "Unknown";

        for (int x : regions.keySet()) {
            region = regions.get(x);
        }

        try {
            ObjectTypeBean object = this.getObjectTypeDAO().load("Region", "", region);
            regionId = object.getObjectTypeId();
        } catch (Exception e) {
            dataLogger.error("Error loading objecttype for region: " + e.getMessage());
        }
        return regionId;
    }

    /**
     * Gets the state/country id for the supplied GUID.
     * Returns the id for "Unknown Country" if no valid entries are found.
     *
     * @param referenceGUID the reference GUID
     *
     * @return the stateCountryId for the supplied reference GUID
     */
    public final int getStateCountryId(final int referenceGUID) {

        int stateCountryId = 0;

        Collection<AddressBean> addresses = null;
        try {
            addresses = this.load(referenceGUID, true, null, null);
        } catch (WhichDoctorDaoException wde) {
            dataLogger.error("Error loading addresses for GUID: " + wde.getMessage());
        }

        HashMap<Integer, AddressBean> countries = new HashMap<Integer, AddressBean>();

        if (addresses != null) {
            for (AddressBean address : addresses) {
                if (!address.getReturnedMail() && !StringUtils.equalsIgnoreCase(address.getRegion(), "Unknown")) {

                    int x = 0;

                    if (address.getRequestNoMail()) {
                        x = 1;
                    }
                    if (address.getPrimary()) {
                        x = 2;
                    }
                    countries.put(x, address);
                }
            }
        }

        String state = "";
        String country = "Unknown Country";

        for (int x : countries.keySet()) {
            AddressBean address = countries.get(x);
            state = address.getState();
            country = address.getCountry();
        }

        try {
            ObjectTypeBean object = this.getObjectTypeDAO().load("State/Country", state, country);
            stateCountryId = object.getObjectTypeId();
        } catch (Exception e) {
            dataLogger.error("Error loading objecttype for state/country: " + e.getMessage());
        }
        return stateCountryId;
    }

    /**
     * Update region.
     *
     * @param referenceGUID the reference guid
     */
    private void updateIndexes(final int referenceGUID) {

        /* Load the WhichDoctor bean of this referenceGUID */
        WhichDoctorBean wdObject = null;
        try {
            wdObject = this.getWhichDoctorDAO().load(referenceGUID);
        } catch (Exception e) {
            dataLogger.error("Error loading WhichDoctor object: " + e.getMessage());
        }

        if (wdObject != null) {
            if (wdObject.getObjectType().compareToIgnoreCase("Person") == 0) {
                /* Update the person's region to reflect change */
                try {
                    this.personDAO.updateRegion(referenceGUID);
                } catch (Exception e) {
                    dataLogger.error("Error updating region for person (" + referenceGUID + "): " + e.getMessage());
                }
                try {
                    this.personDAO.updateResidentCountry(referenceGUID);
                } catch (Exception e) {
                    dataLogger.error("Error updating resident country for person (" + referenceGUID + "): "
                            + e.getMessage());
                }
            }
            if (wdObject.getObjectType().compareToIgnoreCase("Organisation") == 0) {
                /* Update this organisation's region to reflect change */
                try {
                    this.organisationDAO.updateRegion(referenceGUID);
                } catch (Exception e) {
                    dataLogger.error(
                            "Error updating region for organisation (" + referenceGUID + "): " + e.getMessage());
                }
                try {
                    this.organisationDAO.updateResidentCountry(referenceGUID);
                } catch (Exception e) {
                    dataLogger.error("Error updating resident country for organisation (" + referenceGUID + "): "
                            + e.getMessage());
                }
            }
        } else {
            dataLogger.error("Region not updated WhichDoctorBean was null for GUID: " + referenceGUID);
        }
    }

    /**
     * Perform the address verification (if applicable).
     *
     * @param oldAddress the old address
     * @param newAddress the new address
     */
    private void performAddressVerification(final AddressBean oldAddress, final AddressBean newAddress) {

        boolean verifyAddress = false;

        if (oldAddress == null && newAddress != null) {
            // New address
            verifyAddress = true;
        }

        if (oldAddress != null && newAddress != null && oldAddress.compare(newAddress, true)) {
            // Modified address
            verifyAddress = true;
        }

        if (verifyAddress) {
            // New or edited address that does not match the old one
            try {
                boolean submitForVerification = false;

                PreferencesBean pref = preferencesDAO.load();
                if (pref != null
                        && StringUtils.equalsIgnoreCase("true", pref.getOption("system", "addressverification"))) {
                    submitForVerification = true;
                }
                if (oldAddress != null && StringUtils.equalsIgnoreCase(oldAddress.getVerificationStatus(),
                        "Pending verification")) {
                    submitForVerification = true;
                }

                if (submitForVerification) {
                    // Submit the address for automatic verification
                    this.addressVerificationDAO.create(newAddress);

                    // Update the address verification status
                    updateVerificationStatus("Pending verification", newAddress.getGUID());
                }
            } catch (WhichDoctorDaoException wde) {
                dataLogger.error("Error performing address verification check: " + wde.getMessage());
            }
        }
    }

    /**
     * Load the address bean.
     *
     * @param rs the rs
     *
     * @return the address bean
     *
     * @throws SQLException the SQL exception
     */
    private AddressBean loadAddress(final ResultSet rs) throws SQLException {
        AddressBean address = new AddressBean();

        address.setId(rs.getInt("AddressId"));
        address.setGUID(rs.getInt("GUID"));
        address.setReferenceGUID(rs.getInt("ReferenceGUID"));
        address.setContactClass(rs.getString("ContactClass"));
        address.setContactType(rs.getString("ContactType"));
        address.setDescription(rs.getString("Description"));
        address.setAddressField(rs.getString("Address1"));
        address.setAddressField(rs.getString("Address2"));
        address.setAddressField(rs.getString("Address3"));
        address.setAddressField(rs.getString("Address4"));
        address.setAddressField(rs.getString("Address5"));
        address.setAddressField(rs.getString("Address6"));
        address.setAddressField(rs.getString("Address7"));

        address.setState(rs.getString("State"));
        address.setStateAbbreviation(rs.getString("StateAbbreviation"));
        address.setCountry(rs.getString("Country"));
        address.setCountryAbbreviation(rs.getString("CountryAbbreviation"));
        address.setRegion(rs.getString("Region"));

        address.setPrimary(rs.getBoolean("PrimaryAddress"));
        address.setReturnedMail(rs.getBoolean("ReturnedMail"));
        address.setRequestNoMail(rs.getBoolean("RequestNoMail"));
        address.setPostCode(rs.getString("PostCode"));
        address.setGeocode(rs.getString("Geocode"));
        address.setVerificationStatus(rs.getString("VerificationStatus"));

        address.setActive(rs.getBoolean("Active"));
        try {
            address.setCreatedDate(rs.getTimestamp("CreatedDate"));
        } catch (SQLException sqe) {
            dataLogger.debug("Error parsing CreatedDate: " + sqe.getMessage());
        }
        address.setCreatedBy(rs.getString("CreatedBy"));
        try {
            address.setModifiedDate(rs.getTimestamp("ModifiedDate"));
        } catch (SQLException sqe) {
            dataLogger.debug("Error parsing ModifiedDate: " + sqe.getMessage());
        }
        address.setModifiedBy(rs.getString("ModifiedBy"));
        try {
            address.setExportedDate(rs.getTimestamp("ExportedDate"));
        } catch (SQLException sqe) {
            dataLogger.debug("Error parsing ExportedDate: " + sqe.getMessage());
        }
        address.setExportedBy(rs.getString("ExportedBy"));

        return address;
    }

    /**
     * Sets the parameters for the object array that is inserted into the database.
     *
     * @param address the address
     * @param addressTypeId the address type id
     * @param stateId the state id
     * @param regionId the region id
     * @param checkUser the check user
     * @param action the action
     * @return the array list
     */
    private ArrayList<Object> setParameters(final AddressBean address, final int addressTypeId, final int stateId,
            final int regionId, final int verificationStatusId, final UserBean checkUser, final String action) {

        final ArrayList<Object> parameters = new ArrayList<Object>();

        Timestamp sqlTimeStamp = new Timestamp(Calendar.getInstance().getTimeInMillis());

        parameters.add(address.getReferenceGUID());
        parameters.add(addressTypeId);
        parameters.add(address.getDescription());

        for (int x = 0; x < MAXADDRESSLINES; x++) {
            parameters.add(address.getAddressField(x));
        }
        parameters.add(address.getCity());
        parameters.add(address.getPrimary());
        parameters.add(address.getReturnedMail());
        parameters.add(address.getRequestNoMail());
        parameters.add(stateId);
        parameters.add(regionId);
        parameters.add(address.getPostCode());
        parameters.add(address.getGeocode());
        parameters.add(verificationStatusId);
        parameters.add(address.getActive());
        parameters.add(sqlTimeStamp);
        parameters.add(checkUser.getDN());
        parameters.add(address.getLogMessage(action));

        return parameters;
    }
}