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

Java tutorial

Introduction

Here is the source code for com.sfs.whichdoctor.dao.RotationDAOImpl.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.DataFilter;
import com.sfs.Formatter;
import com.sfs.beans.BuilderBean;
import com.sfs.beans.ObjectTypeBean;
import com.sfs.beans.PrivilegesBean;
import com.sfs.beans.UserBean;
import com.sfs.dao.SFSDaoException;
import com.sfs.whichdoctor.beans.AccreditationBean;
import com.sfs.whichdoctor.beans.AssessmentBean;
import com.sfs.whichdoctor.beans.GroupBean;
import com.sfs.whichdoctor.beans.ItemBean;
import com.sfs.whichdoctor.beans.PersonBean;
import com.sfs.whichdoctor.beans.OrganisationBean;
import com.sfs.whichdoctor.beans.ReportBean;
import com.sfs.whichdoctor.beans.RotationBean;
import com.sfs.whichdoctor.beans.SearchBean;
import com.sfs.whichdoctor.beans.SearchResultsBean;
import com.sfs.whichdoctor.beans.SupervisorBean;
import com.sfs.whichdoctor.formatter.OutputFormatter;
import com.sfs.whichdoctor.search.WhichDoctorSearchDaoException;

import java.sql.Date;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.TreeMap;

import javax.annotation.Resource;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

/**
 * The Class RotationDAOImpl.
 */
public class RotationDAOImpl extends WhichDoctorCoreObjectDAOImpl implements RotationDAO {

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

    /** The committee name. */
    private String committeeName;

    /** The accreditation dao. */
    @Resource
    private AccreditationDAO accreditationDAO;

    /** The assessment dao. */
    @Resource
    private AssessmentDAO assessmentDAO;

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

    /** The membership dao. */
    @Resource
    private MembershipDAO membershipDAO;

    /** The supervisor dao. */
    @Resource
    private SupervisorDAO supervisorDAO;

    /** The report dao. */
    @Resource
    private ReportDAO reportDAO;

    /** The relationship dao. */
    @Resource
    private RelationshipDAO relationshipDAO;

    /** The online tools dao. */
    @Resource
    private OnlineToolDAO onlineToolDAO;

    /** The Constant DEFAULT_ROTATION. */
    private static final int DEFAULT_ROTATION = 0;

    /** The Constant CONTINUING_ROTATION. */
    private static final int CONTINUING_ROTATION = 1;

    /** The Constant INTERRUPTED_ROTATION. */
    private static final int INTERRUPTED_ROTATION = 2;

    /**
     * The generic committee name for a rotation. e.g. Specialist Training Committee
     *
     * @param committeeNameVal the committee name
     */
    public final void setCommitteeName(final String committeeNameVal) {
        this.committeeName = committeeNameVal;
    }

    /**
     * Gets the committee name.
     *
     * @return the committee name
     */
    public final String getCommitteeName() {
        return this.committeeName;
    }

    /**
     * Load a RotationBean for a specified rotationId.
     *
     * @param rotationId the rotation id
     *
     * @return the rotation bean
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final RotationBean load(final int rotationId) throws WhichDoctorDaoException {
        return load(rotationId, new BuilderBean(), false);
    }

    /**
     * Load a RotationBean for a specified rotationId and supplied load details.
     *
     * @param rotationId the rotation id
     * @param loadDetails the load details
     *
     * @return the rotation bean
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final RotationBean load(final int rotationId, final BuilderBean loadDetails)
            throws WhichDoctorDaoException {
        return load(rotationId, loadDetails, false);
    }

    /**
     * Load a RotationBean for a specified rotationId and supplied load details.
     * A boolean parameter identifies whether to use the default reader
     * connection or optional writer connection datasource.
     *
     * @param rotationId the rotation id
     * @param loadDetails the load details
     * @param useWriterConn the use writer conn
     *
     * @return the rotation bean
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    private RotationBean load(final int rotationId, final BuilderBean loadDetails, final boolean useWriterConn)
            throws WhichDoctorDaoException {

        RotationBean rotation = null;

        final String loadRotationId = getSQL().getValue("rotation/load") + " AND rotation.RotationId = ?";

        JdbcTemplate jdbcTemplate = this.getJdbcTemplateReader();
        if (useWriterConn) {
            jdbcTemplate = this.getJdbcTemplateWriter();
        }

        try {
            rotation = (RotationBean) jdbcTemplate.queryForObject(loadRotationId, new Object[] { rotationId },
                    new RowMapper() {
                        public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                            return loadRotation(rs, loadDetails);
                        }
                    });

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

    /**
     * Load a RotationBean for a specified name.
     *
     * @param strRotation the str rotation
     *
     * @return the rotation bean
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final RotationBean load(final String strRotation) throws WhichDoctorDaoException {
        return load(strRotation, new BuilderBean());
    }

    /**
     * Load a RotationBean for a specified name and supplied load details.
     *
     * @param strRotation the str rotation
     * @param loadDetails the load details
     *
     * @return the rotation bean
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final RotationBean load(final String strRotation, final BuilderBean loadDetails)
            throws WhichDoctorDaoException {

        dataLogger.info("Rotation Name: " + strRotation + " requested");

        int rotationGUID = 0;

        final String loadSQL = getSQL().getValue("rotation/loadName");

        try {
            rotationGUID = this.getJdbcTemplateReader().queryForInt(loadSQL, new Object[] { strRotation });
        } catch (DataAccessException de) {
            dataLogger.error("Error getting guid for supplied rotation: " + de.getMessage());
        }
        if (rotationGUID > 0) {
            return loadGUID(rotationGUID, loadDetails);
        } else {
            throw new WhichDoctorDaoException("Sorry no rotation matching " + "those details could be identified");
        }
    }

    /**
     * Load a RotationBean for a specified GUID.
     *
     * @param guid the guid
     *
     * @return the rotation bean
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final RotationBean loadGUID(final int guid) throws WhichDoctorDaoException {
        return loadGUID(guid, new BuilderBean());
    }

    /**
     * Load a RotationBean for a specified GUID and supplied load details.
     *
     * @param guid the guid
     * @param loadDetails the load details
     *
     * @return the rotation bean
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    public final RotationBean loadGUID(final int guid, final BuilderBean loadDetails)
            throws WhichDoctorDaoException {

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

        RotationBean rotation = null;

        try {
            rotation = (RotationBean) this.getJdbcTemplateReader().queryForObject(loadGUID, new Object[] { guid },
                    new RowMapper() {
                        public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                            return loadRotation(rs, loadDetails);
                        }
                    });

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

    /**
     * Load the current rotations for the supplied person GUID.
     *
     * @param personGUID the person guid
     * @return the collection
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final Collection<RotationBean> loadCurrentForPerson(final int personGUID)
            throws WhichDoctorDaoException {
        return loadCurrentForPerson(personGUID, new BuilderBean());
    }

    /**
     * Load all active rotations.
     *
     * @return the collection< rotation bean>
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final Collection<RotationBean> loadActiveRotations() throws WhichDoctorDaoException {

        Collection<RotationBean> rotations = new ArrayList<RotationBean>();

        SearchBean search = this.getSearchDAO().initiate("rotation", null);
        search.setLimit(0);

        Collection<Object> results = null;
        try {
            results = this.getSearchDAO().search(search).getSearchResults();
        } catch (WhichDoctorSearchDaoException wse) {
            dataLogger.error("Error searching for active rotations: " + wse.getMessage());
            throw new WhichDoctorDaoException("Error searching for active people: " + wse.getMessage());
        }

        if (results != null) {
            for (Object objRotation : results) {
                if (objRotation != null) {
                    rotations.add((RotationBean) objRotation);
                }
            }
        }
        return rotations;
    }

    /**
     * Load the current rotations for the supplied person GUID.
     *
     * @param personGUID the person guid
     * @param loadDetails the load details
     * @return the collection
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    public final Collection<RotationBean> loadCurrentForPerson(final int personGUID, final BuilderBean loadDetails)
            throws WhichDoctorDaoException {

        Collection<RotationBean> rotations = new ArrayList<RotationBean>();

        Date currentTime = new Date(Calendar.getInstance().getTimeInMillis());

        final String loadCurrent = getSQL().getValue("rotation/load")
                + " AND rotation.Active = true AND people.Active = true "
                + " AND people.GUID = ? AND rotation.StartDate < ? AND rotation.EndDate > ?";

        try {
            rotations = this.getJdbcTemplateReader().query(loadCurrent,
                    new Object[] { personGUID, currentTime, currentTime }, new RowMapper() {
                        public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                            return loadRotation(rs, loadDetails);
                        }
                    });

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

        return rotations;
    }

    /**
     * Calculates and updates the accreditation based on a Rotation's GUID value.
     *
     * @param rotationGUID the rotation guid
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final void recalculateAccreditationForRotation(final int rotationGUID) throws WhichDoctorDaoException {

        if (rotationGUID > 0) {
            try {
                RotationBean rotation = loadGUID(rotationGUID);
                if (rotation != null) {
                    recalculateAccreditationForPerson(rotation.getPersonId());
                }
            } catch (WhichDoctorDaoException wde) {
                throw new WhichDoctorDaoException(wde.getMessage());
            }
        }
    }

    /**
     * Calculates and updates the accreditation for a person based on their GUID value.
     *
     * @param personGUID the person guid
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final void recalculateAccreditationForPerson(final int personGUID) throws WhichDoctorDaoException {

        if (personGUID == 0) {
            throw new WhichDoctorDaoException(
                    "Cannot update accreditation " + "summary for person with GUID of zero");
        }

        int total = 0;

        Collection<Integer> changeToDefault = new ArrayList<Integer>();
        Collection<Integer> changeToExcess = new ArrayList<Integer>();

        int defaultTrainingTypeId = 0;
        int excessTrainingTypeId = 0;

        try {
            ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Training Type", "", "Standard training");
            defaultTrainingTypeId = object.getObjectTypeId();
        } catch (SFSDaoException sfe) {
            dataLogger.error("Error loading objecttype for the training type: " + sfe.getMessage());
        }

        try {
            ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Training Type", "",
                    "Continuing training");
            excessTrainingTypeId = object.getObjectTypeId();
        } catch (SFSDaoException sfe) {
            dataLogger.error("Error loading objecttype for the training type: " + sfe.getMessage());
        }

        Collection<String> accreditationTypes = this.membershipDAO.getTrainingTypes();

        for (String type : accreditationTypes) {
            /* Delete the existing search index entry */
            try {
                this.getSearchIndexDAO().delete(personGUID, type);
            } catch (Exception e) {
                dataLogger.error("Error removing search index (" + type + "): " + e.getMessage());
            }

            int runningTotal = 0;
            boolean excessSet = false;

            int accreditationLimit = this.membershipDAO.getTrainingLimit(type);

            // Build a map to hold the accreditation summary
            Collection<HashMap<String, Integer>> accreditationSummary = buildAccreditationSummary(personGUID, type);

            // Holds the accreditation type count
            HashMap<Integer, Integer> accreditationTypeMap = new HashMap<Integer, Integer>();
            // Holds specialty accreditation count
            HashMap<Integer, Integer> specialtyMap = new HashMap<Integer, Integer>();
            // Holds the count of the accreditation and specialty.
            HashMap<String, Integer> accredSpecialtyMap = new HashMap<String, Integer>();

            for (HashMap<String, Integer> summary : accreditationSummary) {
                final int trainingId = summary.get("TrainingId");
                if (!excessSet) {

                    final int value = summary.get("Accreditation");
                    final int accreditationTypeId = summary.get("AccreditationTypeId");
                    final int specialtyId = summary.get("SpecialtyId");

                    // Check if the value has changed for a valid accreditation/specialty
                    if (value > 0 && accreditationTypeId > 0 && specialtyId > 0) {

                        // Add accreditation value to running total
                        runningTotal += value;

                        // This is a continuing rotation, but it needs to be a default
                        if (trainingId == CONTINUING_ROTATION) {
                            changeToDefault.add(summary.get("GUID"));
                        }

                        if (accreditationTypeMap.containsKey(accreditationTypeId)) {
                            Integer existingValue = accreditationTypeMap.get(accreditationTypeId);
                            accreditationTypeMap.put(accreditationTypeId, existingValue + value);
                        } else {
                            accreditationTypeMap.put(accreditationTypeId, value);
                        }
                        if (specialtyMap.containsKey(specialtyId)) {
                            Integer existingValue = specialtyMap.get(specialtyId);
                            specialtyMap.put(specialtyId, existingValue + value);
                        } else {
                            specialtyMap.put(specialtyId, value);
                        }
                        final String key = String.valueOf(accreditationTypeId) + "_" + String.valueOf(specialtyId);
                        if (accredSpecialtyMap.containsKey(specialtyId)) {
                            Integer existingValue = accredSpecialtyMap.get(key);
                            accredSpecialtyMap.put(key, existingValue + value);
                        } else {
                            accredSpecialtyMap.put(key, value);
                        }

                        if (accreditationLimit != 0 && runningTotal >= accreditationLimit) {
                            excessSet = true;
                        }
                    }
                } else {
                    // Accreditation is beyond limit, add rotation guid if a default
                    if (trainingId == DEFAULT_ROTATION) {
                        changeToExcess.add(summary.get("GUID"));
                    }
                }
            }
            // Add running total to total accreditation
            total += runningTotal;

            // Enter running total into index
            try {
                this.getSearchIndexDAO().update(personGUID, type, 0, 0, runningTotal);
            } catch (Exception e) {
                dataLogger.error("Error updating " + type + " index: " + e.getMessage());
            }

            // Cycle through each divisionId, submitting totals to index
            for (Integer accreditationTypeId : accreditationTypeMap.keySet()) {
                try {
                    final Integer value = accreditationTypeMap.get(accreditationTypeId);
                    this.getSearchIndexDAO().update(personGUID, type, accreditationTypeId, 0, value);
                } catch (Exception e) {
                    dataLogger.error("Error updating " + type + " search index: " + e.getMessage());
                }
            }
            // Cycle through each specialtyId, submitting totals to index
            for (Integer specialtyId : specialtyMap.keySet()) {
                try {
                    final Integer value = specialtyMap.get(specialtyId);
                    this.getSearchIndexDAO().update(personGUID, type, 0, specialtyId, value);
                } catch (Exception e) {
                    dataLogger.error("Error updating " + type + " search index: " + e.getMessage());
                }
            }
            // Cycle through each divisionId/specialtyId, submitting totals to index
            for (String key : accredSpecialtyMap.keySet()) {
                // Break up the accreditation/specialty id pair
                final String strAccreditationId = key.substring(0, key.indexOf("_"));
                final String strSpecialtyId = key.substring(key.indexOf("_") + 1);

                try {
                    final Integer value = accredSpecialtyMap.get(key);
                    this.getSearchIndexDAO().update(personGUID, type, Integer.valueOf(strAccreditationId),
                            Integer.valueOf(strSpecialtyId), value);
                } catch (Exception e) {
                    dataLogger.error("Error updating " + type + " search index: " + e.getMessage());
                }
            }
        }

        for (Integer guid : changeToExcess) {
            updateExcessLevel(guid, excessTrainingTypeId);
        }

        for (Integer guid : changeToDefault) {
            updateExcessLevel(guid, defaultTrainingTypeId);
        }

        try {
            this.getSearchIndexDAO().update(personGUID, "Total Training", 0, 0, total);
        } catch (Exception e) {
            dataLogger.error("Error updating total training index: " + e.getMessage());
        }
    }

    /**
     * Recalculate all of the rotation years.
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final void recalculateAllRotationYears() throws WhichDoctorDaoException {

        // Load all of the rotations
        Collection<RotationBean> rotations = new ArrayList<RotationBean>();
        try {
            rotations = this.loadActiveRotations();
        } catch (WhichDoctorDaoException wde) {
            dataLogger.error("Error loading all rotations: " + wde.getMessage());
        }

        if (rotations != null) {
            for (RotationBean rotation : rotations) {
                try {
                    this.getJdbcTemplateWriter().update(this.getSQL().getValue("rotation/updateYear"),
                            new Object[] { getRotationYear(rotation.getStartDate(), rotation.getEndDate()),
                                    rotation.getGUID() });

                } catch (DataAccessException de) {
                    dataLogger.error("Error updating the year for the rotation guid: " + rotation.getGUID() + ", "
                            + de.getMessage());
                }
            }
        }
    }

    /**
     * Creates the RotationBean.
     *
     * @param rotation the rotation
     * @param checkUser the check user
     * @param privileges the privileges
     *
     * @return the rotation bean
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final RotationBean create(final RotationBean rotation, final UserBean checkUser,
            final PrivilegesBean privileges) throws WhichDoctorDaoException {

        rotation.setActive(true);
        int rotationId = save(rotation, checkUser, privileges, "create");

        RotationBean newRotation = null;
        if (rotationId > 0) {
            BuilderBean loadDetails = new BuilderBean();
            loadDetails.setParameter("SUPERVISORS", true);

            newRotation = load(rotationId, loadDetails, true);

            if (newRotation != null) {
                // Create any reports
                Collection<ReportBean> autoReports = this.reportDAO
                        .getReportsToCreate(newRotation.getRotationType());

                for (ReportBean auto : autoReports) {
                    ReportBean newReport = new ReportBean();
                    newReport.setReferenceGUID(newRotation.getGUID());
                    newReport.setReportType(auto.getReportType());
                    newReport.setReportStatus(auto.getReportStatus());

                    if (StringUtils.equals(auto.getReportGrouping(), "Supervisors")) {
                        // Set the supervisors as the author
                        if (newRotation.getSupervisors() != null) {
                            for (SupervisorBean spvr : newRotation.getSupervisors()) {
                                if (spvr.getPerson() != null) {
                                    newReport.addAuthor(spvr.getPerson());
                                }
                            }
                        }
                    } else {
                        // Set the trainee as the author
                        newReport.addAuthor(newRotation.getPerson());
                    }

                    try {
                        this.reportDAO.create(newReport, checkUser, privileges);
                    } catch (WhichDoctorDaoException wde) {
                        dataLogger.error("Error creating report: " + wde.getMessage());
                    }
                }
            }
        }

        return newRotation;
    }

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

        rotation.setActive(true);
        int rotationId = save(rotation, checkUser, privileges, "modify");

        return load(rotationId, new BuilderBean(), true);
    }

    /**
     * Delete the RotationBean.
     *
     * @param rotation the rotation
     * @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 RotationBean rotation, final UserBean checkUser,
            final PrivilegesBean privileges) throws WhichDoctorDaoException {

        boolean success = false;

        if (privileges.getPrivilege(checkUser, "rotations", "delete")) {
            // Before deleting the rotation remove its child objects
            final BuilderBean loadDetails = new BuilderBean();
            loadDetails.setParameter("LOAD_ALL", true);
            try {
                final RotationBean deleteObj = this.loadGUID(rotation.getGUID(), loadDetails);
                deleteAssociatedObjects(deleteObj, checkUser, privileges);

            } catch (WhichDoctorDaoException wde) {
                dataLogger.error("Error deleting children: " + wde.getMessage(), wde);
                throw new WhichDoctorDaoException("Error deleting children objects: " + wde.getMessage());
            }
        }

        rotation.setActive(false);
        int rotationId = save(rotation, checkUser, privileges, "delete");
        if (rotationId > 0) {
            success = true;
        }
        return success;
    }

    /**
     * Rebuild the workplace index for all rotations.
     *
     * @param user the user
     * @param privileges the privileges
     */
    public final void rebuildWorkplaceReferences(final UserBean user, final PrivilegesBean privileges) {

        // Delete the existing linked workplace details as this process will recreate them
        try {
            // Delete the corresponding GUID entries for these workplace entries
            this.getJdbcTemplateWriter().update(this.getSQL().getValue("rotation/deleteWorkplaceGUIDEntries"),
                    new Object[] {});

            // Delete item entries with a ReferenceGUID > 0
            this.getJdbcTemplateWriter().update(this.getSQL().getValue("rotation/deleteWorkplaceEntries"),
                    new Object[] {});

        } catch (DataAccessException dae) {
            dataLogger.error("Error removing existing rotation linked workplaces: " + dae.getMessage());
        }

        SearchBean search = this.getSearchDAO().initiate("rotation", new UserBean());
        search.setLimit(0);
        SearchResultsBean results = null;
        try {
            final BuilderBean loadDetails = new BuilderBean();
            loadDetails.setParameter("SUPERVISORS", true);
            results = this.getSearchDAO().search(search, loadDetails);
        } catch (WhichDoctorSearchDaoException wse) {
            dataLogger.error("Error performing rotation search: " + wse.getMessage());
        }

        if (results != null) {
            for (Object objRotation : results.getSearchResults()) {
                RotationBean rotation = (RotationBean) objRotation;
                try {
                    this.updateWorkplace(rotation, new ArrayList<Integer>(), "modify", user, privileges);
                    dataLogger.error("Refreshed workplace for rotation: " + rotation.getGUID());
                } catch (WhichDoctorDaoException wde) {
                    dataLogger.error("Error refreshing workplace for rotation:" + rotation.getGUID() + ": "
                            + wde.getMessage());
                }
            }
        }
    }

    /**
     * Gets the rotation year.
     *
     * @param date the start date
     * @return the rotation year
     */
    public final int getRotationYear(final java.util.Date date) {
        return this.getRotationYear(date, null);
    }

    /**
     * Gets the rotation year.
     *
     * @param startDate the start date
     * @param endDate the end date
     * @return the rotation year
     */
    public final int getRotationYear(final java.util.Date startDate, final java.util.Date endDate) {

        int year = 0;

        if (startDate != null && endDate == null) {
            Calendar time = Calendar.getInstance();
            time.setTime(startDate);

            year = time.get(Calendar.YEAR);
        }

        if (startDate == null && endDate != null) {
            Calendar time = Calendar.getInstance();
            time.setTime(endDate);

            year = time.get(Calendar.YEAR);
        }

        if (startDate != null && endDate != null) {
            Calendar start = Calendar.getInstance();
            Calendar end = Calendar.getInstance();

            start.setTime(startDate);
            end.setTime(endDate);

            year = start.get(Calendar.YEAR);

            String yearEndString = "31/12/" + String.valueOf(year);
            Calendar yearEnd = Calendar.getInstance();
            yearEnd.setTime(DataFilter.parseDate(yearEndString, true));

            double timeBefore = yearEnd.getTimeInMillis() - start.getTimeInMillis();
            double duration = end.getTimeInMillis() - start.getTimeInMillis();

            if ((timeBefore / duration) <= 0.33 && start.get(Calendar.MONTH) > 9) {
                // If more than 33% of the rotation occurred in the following year
                // and the start month is after September, add one to the year.
                year++;
            }
        }

        return year;
    }

    /**
     * Save the RotationBean.
     *
     * @param rotation the rotation
     * @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 RotationBean rotation, final UserBean checkUser, final PrivilegesBean privileges,
            final String action) throws WhichDoctorDaoException {

        /* Create rotation requires all the essential rotation information */
        if (StringUtils.isBlank(rotation.getDescription())) {
            throw new NullPointerException("Rotation description field cannot be an empty string");
        }
        if (StringUtils.isBlank(rotation.getRotationType())) {
            throw new WhichDoctorDaoException("Rotation type field cannot be an empty string");
        }
        if (rotation.getStartDate() == null) {
            throw new WhichDoctorDaoException("Rotation requires a start date");
        }
        if (rotation.getEndDate() == null) {
            throw new WhichDoctorDaoException("Rotation requires an end date");
        }
        if (rotation.getPersonId() == 0) {
            throw new WhichDoctorDaoException("Rotation requires a valid person GUID");
        }
        if (!privileges.getPrivilege(checkUser, "rotations", action)) {
            throw new WhichDoctorDaoException("Insufficient user credentials to " + action + " rotation");
        }

        int rotationTypeId = 0;
        int trainingTypeId = 0;
        int organisation1TypeId = 0;
        int organisation2TypeId = 0;

        if (StringUtils.isNotBlank(rotation.getOrganisation1Type())) {
            try {
                ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Site Type", "",
                        rotation.getOrganisation1Type());
                organisation1TypeId = object.getObjectTypeId();
            } catch (SFSDaoException sfe) {
                dataLogger.error("Error loading objecttype for the rotation site type: " + sfe.getMessage());
            }
        }

        if (StringUtils.isNotBlank(rotation.getTrainingClass())) {
            try {
                ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Training Type",
                        rotation.getTrainingType(), rotation.getTrainingClass());
                trainingTypeId = object.getObjectTypeId();
            } catch (SFSDaoException sfe) {
                dataLogger.error("Error loading objecttype for the training type: " + sfe.getMessage());
            }
        }

        try {
            ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Type", "", rotation.getRotationType());
            rotationTypeId = object.getObjectTypeId();
        } catch (Exception e) {
            dataLogger.error("Error loading objecttype for rotation type: " + e.getMessage());
            throw new WhichDoctorDaoException("Rotation requires a valid type");
        }

        if (StringUtils.isNotBlank(rotation.getOrganisation2Type())) {
            try {
                ObjectTypeBean object = this.getObjectTypeDAO().load("Rotation Site Type", "",
                        rotation.getOrganisation2Type());
                organisation2TypeId = object.getObjectTypeId();
            } catch (SFSDaoException sfe) {
                dataLogger.error("Error loading objecttype for the rotation site type: " + sfe.getMessage());
            }
        }

        /* Load the current rotation to get the existing organisations */
        Collection<Integer> existingOrganisations = new ArrayList<Integer>();
        if (rotation.getGUID() > 0) {
            try {
                RotationBean existing = this.loadGUID(rotation.getGUID());
                if (existing.getOrganisation1Id() > 0) {
                    existingOrganisations.add(existing.getOrganisation1Id());
                }
                if (existing.getOrganisation2Id() > 0) {
                    existingOrganisations.add(existing.getOrganisation2Id());
                }
            } catch (WhichDoctorDaoException wde) {
                dataLogger.error("Error loading existing rotation: " + wde.getMessage());
            }
        }

        int rotationId = 0;

        Timestamp sqlTimeStamp = new Timestamp(Calendar.getInstance().getTimeInMillis());
        Date startDate = new Date(Calendar.getInstance().getTimeInMillis());
        if (rotation.getStartDate() != null) {
            startDate = new Date(rotation.getStartDate().getTime());
        }
        Date endDate = new Date(Calendar.getInstance().getTimeInMillis());
        if (rotation.getEndDate() != null) {
            endDate = new Date(rotation.getEndDate().getTime());
        }
        String organisation1Name = "";
        String organisation2Name = "";
        if (rotation.getOrganisation1() == null) {
            organisation1Name = rotation.getOrganisation1Name();
        }
        if (rotation.getOrganisation2() == null) {
            organisation2Name = rotation.getOrganisation2Name();
        }

        ArrayList<Object> parameters = new ArrayList<Object>();
        parameters.add(rotation.getDescription());
        parameters.add(rotationTypeId);
        parameters.add(trainingTypeId);
        parameters.add(startDate);
        parameters.add(endDate);
        parameters.add(getRotationYear(rotation.getStartDate(), rotation.getEndDate()));
        parameters.add(rotation.getOrganisation1Id());
        parameters.add(rotation.getOrganisation2Id());
        parameters.add(organisation1TypeId);
        parameters.add(organisation2TypeId);
        parameters.add(organisation1Name);
        parameters.add(organisation2Name);
        parameters.add(rotation.getPersonId());
        parameters.add(rotation.getLeaveDays());
        parameters.add(rotation.getTrainingTime());
        parameters.add(rotation.getCommitteeName());
        parameters.add(rotation.getActive());
        parameters.add(sqlTimeStamp);
        parameters.add(checkUser.getDN());
        parameters.add(rotation.getLogMessage(action));

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

        if (rotationId > 0) {
            dataLogger.info(checkUser.getDN() + " created rotationId: " + String.valueOf(rotationId));

            postProcessRotationChange(action, checkUser, privileges, rotation, existingOrganisations);
        }

        return rotationId;
    }

    /**
     * Delete the objects associated with the supplied RotationBean.
     *
     * @param deleteObjects the delete objects
     * @param checkUser the check user
     * @param privileges the privileges
     */
    private void deleteAssociatedObjects(final RotationBean deleteObjects, final UserBean checkUser,
            final PrivilegesBean privileges) {

        if (deleteObjects.getAccreditation() != null) {
            for (AccreditationBean accreditation : deleteObjects.getAccreditation()) {
                try {
                    accreditation.setLogMessage(accreditation.getLogMessage("delete"));
                    this.accreditationDAO.delete(accreditation, checkUser, privileges);
                } catch (WhichDoctorDaoException wde) {
                    dataLogger.error("Error deleting accreditation: " + wde.getMessage());
                }
            }
        }

        if (deleteObjects.getSupervisors() != null) {
            for (SupervisorBean supervisor : deleteObjects.getSupervisors()) {
                try {
                    supervisor.setLogMessage(supervisor.getLogMessage("delete"));
                    this.supervisorDAO.delete(supervisor, checkUser, privileges);
                } catch (WhichDoctorDaoException wde) {
                    dataLogger.error("Error deleting supervisor: " + wde.getMessage());
                }
            }
        }

        if (deleteObjects.getReports() != null) {
            for (ReportBean report : deleteObjects.getReports()) {
                try {
                    report.setLogMessage(report.getLogMessage("delete"));
                    this.reportDAO.delete(report, checkUser, privileges);
                } catch (WhichDoctorDaoException wde) {
                    dataLogger.error("Error deleting report: " + wde.getMessage());
                }
            }
        }

        if (deleteObjects.getAssessment() != null) {
            for (AssessmentBean assessment : deleteObjects.getAssessment()) {
                try {
                    assessment.setLogMessage(assessment.getLogMessage("delete"));
                    this.assessmentDAO.delete(assessment, checkUser, privileges);
                } catch (WhichDoctorDaoException wde) {
                    dataLogger.error("Error deleting assessment: " + wde.getMessage());
                }
            }
        }

        deleteMemos(deleteObjects, checkUser, privileges);
        deleteGroups(deleteObjects, checkUser, privileges);
    }

    /**
     * Update the workplace.
     *
     * @param rotation the rotation
     * @param existingOrganisationGUIDs the existing organisation gui ds
     * @param parentAction the parent action
     * @param checkUser the check user
     * @param privileges the privileges
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    private void updateWorkplace(final RotationBean rotation, final Collection<Integer> existingOrganisationGUIDs,
            final String parentAction, final UserBean checkUser, final PrivilegesBean privileges)
            throws WhichDoctorDaoException {

        ItemBean workplace = null;

        final int defaultWeighting = 10;

        Collection<Integer> newOrganisationGUIDs = new ArrayList<Integer>();
        if (rotation.getOrganisation1Id() > 0) {
            newOrganisationGUIDs.add(rotation.getOrganisation1Id());
        }
        if (rotation.getOrganisation2Id() > 0) {
            newOrganisationGUIDs.add(rotation.getOrganisation2Id());
        }

        /* Determine what workplaces need creating/modifying/deleting */
        HashMap<Integer, String> organisations = new HashMap<Integer, String>();

        for (Integer organisationGUID : existingOrganisationGUIDs) {
            organisations.put(organisationGUID, "delete");
        }
        if (!StringUtils.equals(parentAction, "delete")) {
            // If the rotation is not being deleted add the new workplaces
            for (Integer organisationGUID : newOrganisationGUIDs) {
                if (organisations.containsKey(organisationGUID)) {
                    organisations.put(organisationGUID, "modify");
                } else {
                    organisations.put(organisationGUID, "create");
                }
            }
        }

        for (Integer organisationGUID : organisations.keySet()) {
            final String action = organisations.get(organisationGUID);

            if (!StringUtils.equals(action, "create")) {
                // Load the workplace object
                workplace = this.getItemDAO().loadReference(rotation.getGUID(), organisationGUID, "Employer");
            }
            if (workplace == null && !StringUtils.equals(action, "delete")) {
                workplace = new ItemBean();
            }

            if (workplace != null) {
                workplace.setTitle(rotation.getDescription());
                workplace.setObject1GUID(organisationGUID);
                workplace.setObject2GUID(rotation.getPersonId());
                workplace.setReferenceGUID(rotation.getGUID());
                workplace.setStartDate(rotation.getStartDate());
                workplace.setEndDate(rotation.getEndDate());
                workplace.setWeighting(defaultWeighting);

                StringBuffer info = new StringBuffer();
                if (rotation.getSupervisors() != null && rotation.getSupervisors().size() > 0) {
                    int i = 1;
                    for (SupervisorBean supervisor : rotation.getSupervisors()) {
                        if (supervisor != null && supervisor.getPerson() != null) {
                            if (info.length() > 0) {
                                if (i == rotation.getSupervisors().size()) {
                                    info.append(" and ");
                                } else {
                                    info.append(", ");
                                }
                            }
                            info.append(OutputFormatter.toCasualName(supervisor.getPerson()));
                            i++;
                        }
                    }
                    if (info.length() > 0) {
                        info.insert(0, "Supervised by ");
                        info.append("\n");
                    }
                }

                info.append(rotation.getTotalDays());
                info.append(" approximate days training (");
                info.append(Formatter.toPercent(rotation.getTrainingTime(), 0, "%"));
                info.append(" time");
                if (rotation.getLeaveDays() > 0) {
                    info.append(", ");
                    info.append(rotation.getLeaveDays());
                    info.append(" days on leave");
                }
                info.append(")");

                workplace.setComment(info.toString());

                workplace.setItemType("Employer");

                updateWorkplace(workplace, action, checkUser, privileges);
            }
        }
    }

    /**
     * Update workplace.
     *
     * @param workplace the workplace
     * @param action the action
     * @param checkUser the check user
     * @param privileges the privileges
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    private void updateWorkplace(final ItemBean workplace, final String action, final UserBean checkUser,
            final PrivilegesBean privileges) throws WhichDoctorDaoException {

        if (StringUtils.equals(action, "delete")) {
            // Deleting the rotation so remove the workplace entry
            workplace.setLogMessage("Workplace linked to rotation " + "automatically deleted");
            this.getItemDAO().delete(workplace, checkUser, privileges, null);
        } else {
            if (workplace.getGUID() > 0) {
                // The workplace has a GUID, modify
                workplace.setLogMessage("Workplace linked to rotation " + "automatically modified");
                this.getItemDAO().modify(workplace, checkUser, privileges, null);
            } else {
                // The workplace lacks a GUID so create an entry
                workplace.setLogMessage("Workplace linked to rotation " + "automatically created");
                this.getItemDAO().create(workplace, checkUser, privileges, null);
            }
        }
    }

    /**
     * Update excess level.
     *
     * @param guid the guid
     * @param trainingTypeId the training type id
     */
    private void updateExcessLevel(final int guid, final int trainingTypeId) {
        try {
            this.getJdbcTemplateWriter().update(this.getSQL().getValue("rotation/updateRotationExcess"),
                    new Object[] { trainingTypeId, guid });

        } catch (DataAccessException de) {
            dataLogger.error("Error updating excess flag of rotation guid: " + guid + ", " + de.getMessage());
        }
    }

    /**
     * Post process rotation change.
     *
     * @param action the action
     * @param checkUser the check user
     * @param privileges the privileges
     * @param rotation the rotation
     * @param existingOrganisations the existing organisations
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    private void postProcessRotationChange(final String action, final UserBean checkUser,
            final PrivilegesBean privileges, final RotationBean rotation,
            final Collection<Integer> existingOrganisations) throws WhichDoctorDaoException {

        UserBean user = this.getSystemUser("Rotation", "Change");

        // Clone the user and give them super privileges to perform any changes.
        try {
            user = (UserBean) BeanUtils.cloneBean(checkUser);
            user.setOverridePrivileges(true);
        } catch (Exception e) {
            dataLogger.error("Cannot clone user: " + e.getMessage());
        }

        /* update the supervisor details */
        try {
            this.supervisorDAO.update(rotation.getGUID(), action, rotation.getSupervisors(), rotation.getPersonId(),
                    user, privileges);
        } catch (Exception e) {
            dataLogger.error("Error updating supervisor details: " + e.getMessage());
        }

        /* Update the accreditation excess levels */
        try {
            this.recalculateAccreditationForPerson(rotation.getPersonId());
        } catch (Exception e) {
            dataLogger.error("Error updating excess accreditation levels " + "for person GUID "
                    + rotation.getPersonId() + ": " + e.getMessage());
        }

        /* Update the work place details */
        try {
            updateWorkplace(rotation, existingOrganisations, action, user, privileges);
        } catch (WhichDoctorDaoException wde) {
            dataLogger.error("Error updating rotation workplace: " + wde.getMessage());
        }

        /* Update the relationships for the supplied person GUID */
        try {
            this.relationshipDAO.rebuildRelationships(rotation.getPersonId(), "Person");
        } catch (Exception e) {
            dataLogger.error("Error rebuilding relationships: " + e.getMessage());
        }

        /* Check whether the online tools relationships need to be updated */
        this.onlineToolDAO.rebuildRotationRelationships(rotation.getPersonId(), user, privileges);

        /* Check whether the training status needs to be updated */
        this.membershipDAO.updateTrainingStatus(rotation.getPersonId(), user, privileges);

    }

    /**
     * Load the RotationBean data.
     *
     * @param rs the result set
     * @param loadDetails the load details
     *
     * @return the rotation bean
     *
     * @throws SQLException the SQL exception
     */
    private RotationBean loadRotation(final ResultSet rs, final BuilderBean loadDetails) throws SQLException {

        RotationBean rotation = new RotationBean();

        rotation.setId(rs.getInt("RotationId"));
        rotation.setGUID(rs.getInt("GUID"));
        rotation.setDescription(rs.getString("Description"));
        rotation.setRotationType(rs.getString("Type"));
        rotation.setRotationTypeAbbreviation(rs.getString("TypeAbbreviation"));
        rotation.setTrainingClass(rs.getString("TrainingClass"));
        rotation.setTrainingType(rs.getString("TrainingType"));
        rotation.setTrainingMapping(rs.getString("TrainingMapping"));
        rotation.setOrganisation1Name(rs.getString("OtherOrganisation1Name"));
        rotation.setOrganisation2Name(rs.getString("OtherOrganisation2Name"));
        rotation.setOrganisation1Type(rs.getString("Organisation1Type"));
        rotation.setOrganisation1TypeMapping(rs.getString("Organisation1TypeMapping"));
        rotation.setOrganisation2Type(rs.getString("Organisation2Type"));
        rotation.setOrganisation2TypeMapping(rs.getString("Organisation2TypeMapping"));
        rotation.setYear(rs.getInt("RotationYear"));
        try {
            rotation.setStartDate(rs.getDate("StartDate"));
        } catch (SQLException sqe) {
            dataLogger.debug("Error loading StartDate: " + sqe.getMessage());
        }
        try {
            rotation.setEndDate(rs.getDate("EndDate"));
        } catch (SQLException sqe) {
            dataLogger.debug("Error loading StartDate: " + sqe.getMessage());
        }

        rotation.setLeaveDays(rs.getInt("LeaveDays"));
        rotation.setTrainingTime(rs.getDouble("TrainingTime"));
        rotation.setCommitteeName(rs.getString("CommitteeName"));

        // Load the supervisors for this rotation
        try {
            rotation.setSupervisors(loadSupervisors(rotation.getGUID(), loadDetails));
        } catch (WhichDoctorDaoException wde) {
            dataLogger.error("Error loading supervisors: " + wde.getMessage());
        }

        rotation.setPersonId(rs.getInt("PersonId"));
        if (rotation.getPersonId() > 0) {
            rotation.setPerson(loadPerson(rotation.getPersonId(), loadDetails, rs));
        }

        rotation.setOrganisation1Id(rs.getInt("Organisation1Id"));
        if (rotation.getOrganisation1Id() > 0) {
            OrganisationBean organisation = new OrganisationBean();
            organisation.setId(rotation.getOrganisation1Id());
            organisation.setName(rs.getString("Organisation1Name"));
            organisation.setGUID(rs.getInt("Organisation1GUID"));
            rotation.setOrganisation1(organisation);
        }
        rotation.setOrganisation2Id(rs.getInt("Organisation2Id"));
        if (rotation.getOrganisation2Id() > 0) {
            OrganisationBean organisation = new OrganisationBean();
            organisation.setId(rotation.getOrganisation2Id());
            organisation.setName(rs.getString("Organisation2Name"));
            organisation.setGUID(rs.getInt("Organisation2GUID"));
            rotation.setOrganisation2(organisation);
        }

        try {
            rotation.setReports(reportDAO.load(rotation.getGUID(), loadDetails.getBoolean("REPORTS_FULL")));
        } catch (WhichDoctorDaoException wde) {
            dataLogger.error("Error loading reports: " + wde.getMessage());
        }

        if (loadDetails.getBoolean("ASSESSMENTS")) {
            try {
                rotation.setAssessment(this.assessmentDAO.load(rotation.getGUID()));
            } catch (Exception e) {
                dataLogger.error("Error loading assessment (" + rotation.getGUID() + "): " + e.getMessage());
            }
        }

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

        if (loadDetails.getBoolean("ACCREDITATIONS")) {
            try {
                rotation.setAccreditation(this.accreditationDAO.load(rotation.getGUID(),
                        loadDetails.getBoolean("ACCREDITATION_FULL")));
            } catch (Exception e) {
                dataLogger.error(
                        "Error loading accreditation details (" + rotation.getGUID() + "): " + e.getMessage());
            }
        }

        if (loadDetails.getBoolean("ONLINETOOLS")) {
            try {
                rotation.setOnlineTools(this.onlineToolDAO.loadRotation(rotation.getGUID()));
            } catch (Exception e) {
                dataLogger.error("Error loading online tools for rotation: " + e.getMessage());
            }
        }

        if (loadDetails.getBoolean("TAGS")) {
            try {
                rotation.setTags(this.getTagDAO().load(rotation.getGUID(), loadDetails.getString("USERDN"), true));
            } catch (Exception e) {
                dataLogger.error("Error loading tags for rotation: " + e.getMessage());
            }
        }

        if (loadDetails.getBoolean("MEMO")) {
            try {
                rotation.setMemo(this.getMemoDAO().load(rotation.getGUID(), loadDetails.getBoolean("MEMO_FULL")));
            } catch (Exception e) {
                dataLogger.error("Error loading memos for rotation: " + e.getMessage());
            }
        }

        if (loadDetails.getBoolean("GROUPS")) {
            rotation.setGroups(loadGroups(rotation.getGUID()));
        }

        if (loadDetails.getBoolean("CREATED")) {
            UserBean user = new UserBean();
            user.setDN(rs.getString("CreatedBy"));
            user.setPreferredName(rs.getString("CreatedFirstName"));
            user.setLastName(rs.getString("CreatedLastName"));
            rotation.setCreatedUser(user);
        }
        if (loadDetails.getBoolean("MODIFIED")) {
            UserBean user = new UserBean();
            user.setDN(rs.getString("ModifiedBy"));
            user.setPreferredName(rs.getString("ModifiedFirstName"));
            user.setLastName(rs.getString("ModifiedLastName"));
            rotation.setModifiedUser(user);
        }
        if (loadDetails.getBoolean("EXPORTED")) {
            UserBean user = new UserBean();
            user.setDN(rs.getString("ExportedBy"));
            user.setPreferredName(rs.getString("ExportedFirstName"));
            user.setLastName(rs.getString("ExportedLastName"));
            rotation.setExportedUser(user);
        }
        return rotation;
    }

    /**
     * Gets the person.
     *
     * @param personGUID the person guid
     * @param loadDetails the load details
     * @param rs the rs
     *
     * @return the person
     *
     * @throws SQLException the SQL exception
     */
    private PersonBean loadPerson(final int personGUID, final BuilderBean loadDetails, final ResultSet rs)
            throws SQLException {

        PersonBean person = null;

        if (loadDetails.getBoolean("LOAD_MEMBER")) {
            try {
                BuilderBean personDetails = new BuilderBean();
                personDetails.setParameter("MEMBERSHIP", true);
                personDetails.setParameter("MEMBERSHIP_FULL", true);
                personDetails.setParameter("EMAIL", true);
                personDetails.setParameter("ADDRESS", true);
                personDetails.setParameter("ADDRESS_CLASS", loadDetails.getString("ADDRESS_CLASS"));
                personDetails.setParameter("ADDRESS_TYPE", loadDetails.getString("ADDRESS_TYPE"));
                personDetails.setParameter("SPECIALTY", true);
                personDetails.setParameter("TRAINING_ADVANCED", true);
                personDetails.setParameter("TRAINING_POSTFRACP", true);
                personDetails.setParameter("TRAINING_BASIC", true);

                person = this.personDAO.loadGUID(personGUID, personDetails);

            } catch (Exception e) {
                dataLogger.error("ERROR loading rotation person: " + e.getMessage());
            }

        } else {
            person = new PersonBean();
            person.setId(rs.getInt("pPersonId"));
            person.setPersonIdentifier(rs.getInt("PersonIdentifier"));
            person.setPreferredName(rs.getString("PreferredName"));
            person.setFirstName(rs.getString("FirstName"));
            person.setLastName(rs.getString("LastName"));
            person.setGUID(rs.getInt("PersonGUID"));
            person.setTitle(rs.getString("Title"));
            person.setGender(rs.getString("Gender"));

            if (loadDetails.getBoolean("ADDRESS")) {
                try {
                    person.setAddress(this.getAddressDAO().load(person.getGUID(), false,
                            loadDetails.getString("ADDRESS_CLASS"), loadDetails.getString("ADDRESS_TYPE")));
                } catch (Exception e) {
                    dataLogger.error("Error loading address for credit: " + e.getMessage());
                }
            }
        }

        return person;
    }

    /**
     * Load supervisors.
     *
     * @param rotationGUID the rotation guid
     * @param loadDetails the load details
     *
     * @return the collection< supervisor bean>
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    private Collection<SupervisorBean> loadSupervisors(final int rotationGUID, final BuilderBean loadDetails)
            throws WhichDoctorDaoException {

        BuilderBean supervisorDetails = new BuilderBean();

        supervisorDetails.setParameter("SUPERVISOR_PERSONOBJ", loadDetails.getBoolean("SUPERVISORS"));
        supervisorDetails.setParameter("EMAIL", loadDetails.getBoolean("SUPERVISORS_EMAIL"));

        Collection<SupervisorBean> supervisors = this.supervisorDAO.load(rotationGUID, supervisorDetails);

        return supervisors;
    }

    /**
     * Load groups.
     *
     * @param guid the guid
     *
     * @return the collection< group bean>
     */
    private Collection<GroupBean> loadGroups(final int guid) {

        /* Create new SearchBean of type Rotation and default values */
        SearchResultsBean results = new SearchResultsBean();
        SearchBean groupSearch = this.getSearchDAO().initiate("group", null);
        groupSearch.setLimit(0);

        GroupBean searchCriteria = (GroupBean) groupSearch.getSearchCriteria();
        searchCriteria.setObjectType("Rotations");
        ItemBean item = new ItemBean();
        item.setObject2GUID(guid);
        TreeMap<String, ItemBean> items = new TreeMap<String, ItemBean>();
        items.put("Rotation", item);
        searchCriteria.setItems(items);

        groupSearch.setSearchCriteria(searchCriteria);

        try {
            BuilderBean loadGroup = new BuilderBean();
            loadGroup.setParameter("ITEMS", true);
            loadGroup.setParameter("REFERENCEID", String.valueOf(guid));
            results = this.getSearchDAO().search(groupSearch, loadGroup);
        } catch (Exception e) {
            dataLogger.error("Error loading groups for rotation: " + e.getMessage());
        }

        ArrayList<GroupBean> groups = new ArrayList<GroupBean>();
        for (Object group : results.getSearchResults()) {
            groups.add((GroupBean) group);
        }

        return groups;
    }

    /**
     * Builds the accreditation summary.
     *
     * @param personGUID the person guid
     * @param type the type
     * @return the collection
     */
    @SuppressWarnings("unchecked")
    private Collection<HashMap<String, Integer>> buildAccreditationSummary(final int personGUID,
            final String type) {

        // Build a map to hold the accreditation summary
        Collection<HashMap<String, Integer>> accreditationSummary = new ArrayList<HashMap<String, Integer>>();

        try {
            accreditationSummary = this.getJdbcTemplateWriter().query(
                    this.getSQL().getValue("rotation/accreditationSummary"), new Object[] { personGUID, type },
                    new RowMapper() {
                        public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                            HashMap<String, Integer> summary = new HashMap<String, Integer>();

                            summary.put("Accreditation", rs.getInt("Accreditation"));
                            summary.put("GUID", rs.getInt("GUID"));
                            summary.put("AccreditationTypeId", rs.getInt("AccreditationTypeId"));
                            summary.put("SpecialtyId", rs.getInt("SpecialtyId"));

                            int trainingId = DEFAULT_ROTATION;
                            String type = rs.getString("TrainingClass");

                            if (StringUtils.contains(type, "ontinuing")) {
                                trainingId = CONTINUING_ROTATION;
                            }
                            if (StringUtils.contains(type, "nterrupt")) {
                                trainingId = INTERRUPTED_ROTATION;
                            }
                            summary.put("TrainingId", trainingId);

                            return summary;
                        }
                    });

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

        return accreditationSummary;
    }
}