com.sfs.whichdoctor.webservice.RotationServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.sfs.whichdoctor.webservice.RotationServiceImpl.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.webservice;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.sfs.DataFilter;
import com.sfs.beans.BuilderBean;
import com.sfs.beans.ObjectTypeBean;
import com.sfs.beans.UserBean;
import com.sfs.beans.PrivilegesBean;
import com.sfs.dao.ObjectTypeDAO;
import com.sfs.dao.PrivilegesDAO;
import com.sfs.dao.SFSDaoException;
import com.sfs.whichdoctor.beans.AddressBean;
import com.sfs.whichdoctor.beans.MembershipBean;
import com.sfs.whichdoctor.beans.PersonBean;
import com.sfs.whichdoctor.beans.OrganisationBean;
import com.sfs.whichdoctor.beans.RotationBean;
import com.sfs.whichdoctor.beans.SearchBean;
import com.sfs.whichdoctor.beans.SearchResultsBean;
import com.sfs.whichdoctor.beans.SpecialtyBean;
import com.sfs.whichdoctor.beans.SupervisorBean;
import com.sfs.whichdoctor.dao.MembershipDAO;
import com.sfs.whichdoctor.dao.PersonDAO;
import com.sfs.whichdoctor.dao.RotationDAO;
import com.sfs.whichdoctor.dao.WhichDoctorDaoException;
import com.sfs.whichdoctor.search.SearchDAO;
import com.sfs.whichdoctor.search.WhichDoctorSearchDaoException;
import com.sfs.whichdoctor.webservice.helper.PersonsRotations;

/**
 * The Class RotationServiceImpl.
 */
public class RotationServiceImpl extends WebserviceBase implements RotationService {

    /** The logger. */
    private static Logger logger = Logger.getLogger(RotationServiceImpl.class);

    /** The Constant EDUCATION_ORDER. */
    private static final int EDUCATION_ORDER = 998;

    /** The Constant PDA_ORDER. */
    private static final int PDA_ORDER = 999;

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

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

    /** The privileges dao. */
    @Resource
    private PrivilegesDAO privilegesDAO;

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

    /** The rotation dao. */
    @Resource
    private RotationDAO rotationDAO;

    /** The rotation XML outputter. */
    @Resource
    private RotationXmlOutput rotationXmlOutput;

    /** The search dao. */
    @Resource
    private SearchDAO searchDAO;

    /** The user that will perform any write operations. **/
    private UserBean user;

    /**
     * Sets the user for write operations.
     *
     * @param userRef the user that will undertake write operations
     */
    public final void setUser(final UserBean userRef) {
        this.user = userRef;
    }

    /**
     * Get a list of relevant rotations for people for the specified date range.
     *
     * @param PEOsysids - the unique person identifers (as a CSV list of numbers)
     * @param periodFrom - the start date to retrieve rotations from
     * @param periodTo - the end date to retrieve rotations from
     *
     * @return the trainee rotations
     */
    public final String getRotations(final String PEOsysids, final Calendar periodFrom, final Calendar periodTo) {

        StringBuilder results = new StringBuilder();

        if (this.getAllowedAddress() && StringUtils.isNotBlank(PEOsysids)) {
            List<Integer> identifiers = parseIdentifiers(PEOsysids);

            for (int identifier : identifiers) {

                PersonsRotations pr = loadRotations(identifier, periodFrom, periodTo);

                results.append(this.rotationXmlOutput.getSecondGenRotations(pr.getRotations(), identifier,
                        pr.getDivision(), pr.getCurrentRotations()));
            }
        }

        if (results.length() > 0) {
            results.insert(0, "<trainees>");
            results.append("</trainees>");
        } else {
            results.append("<trainees />");
        }

        return results.toString();
    }

    /**
     * Get a list of relevant rotations for a person for the specified year.
     *
     * @param PEOsysids the PEOsysids
     * @param year the year
     * @param program the program
     * @param training_site_country_code the training_site_country_code
     * @param state the state
     * @param primary_site the primary_site
     * @param training_site the training_site
     * @param division the division
     * @param keyword the keyword
     * @param incl_prep the incl_prep
     * @param incl_non_prep the incl_non_prep
     * @return the rotations by year
     */
    public String getRotationsByYear(final int year, final String program, final String training_site_country_code,
            final String state, final String primary_site, final String training_site, final String division,
            final String keyword, final int incl_prep, final int incl_non_prep) {

        StringBuilder results = new StringBuilder();

        if (this.getAllowedAddress()) {

            Calendar periodFrom = Calendar.getInstance();
            Calendar periodTo = Calendar.getInstance();

            periodFrom.set(year, 1, 1, 0, 0);
            periodTo.set(year, 12, 31, 23, 59);

            List<Integer> identifiers = findPeople(year, program, training_site_country_code, state, primary_site,
                    training_site, division, keyword, incl_prep, incl_non_prep);

            for (int identifier : identifiers) {

                PersonsRotations pr = loadRotations(identifier, periodFrom, periodTo);

                results.append(this.rotationXmlOutput.getSecondGenRotations(pr.getRotations(), identifier,
                        pr.getDivision(), pr.getCurrentRotations()));
            }
        }

        if (results.length() > 0) {
            results.insert(0, "<trainees>");
            results.append("</trainees>");
        } else {
            results.append("<trainees />");
        }

        return results.toString();
    }

    /**
     * Get a list of relevant basic rotations for a person for the specified date range.
     *
     * @param PEOsysid - the unique person identifer (as a double)
     * @param periodFrom - the start date to retrieve rotations from
     * @param periodTo - the end date to retrieve rotations from
     * @return the trainee rotations
     */
    public final String getTraineeRotations(final double PEOsysid, final Calendar periodFrom,
            final Calendar periodTo) {

        String results = "";

        if (this.getAllowedAddress() && PEOsysid > 0) {
            PersonsRotations prts = loadRotations((int) PEOsysid, periodFrom, periodTo);

            results = this.rotationXmlOutput.getFirstGenRotations(prts.getRotations(), (int) PEOsysid,
                    prts.getDivision());
        }

        if (StringUtils.isBlank(results)) {
            results = "<rotations min=\"" + PEOsysid + "\" />";
        }

        return results;
    }

    /**
     * Gets a list of relevant trainee rotations for a person for the specified
     * date range and training type.
     *
     * @param PEOsysids the PEOsysids
     * @param periodFrom the period from
     * @param periodTo the period to
     * @param trainingType the training type
     * @return the trainee rotations
     */
    public final String GetTraineeRotations(final String PEOsysids, final Calendar periodFrom,
            final Calendar periodTo, final String trainingType) {

        StringBuilder results = new StringBuilder();

        if (this.getAllowedAddress() && StringUtils.isNotBlank(PEOsysids)) {
            List<Integer> identifiers = parseIdentifiers(PEOsysids);

            for (int identifier : identifiers) {

                PersonsRotations pr = loadRotations(identifier, periodFrom, periodTo);

                results.append(this.rotationXmlOutput.getThirdGenRotations(
                        orderThirdGenRotations(pr.getRotations()), identifier, pr.getDivision(), trainingType));
            }
        }

        if (results.length() > 0) {
            results.insert(0, "<Trainees>");
            results.append("</Trainees>");
        } else {
            results.append("<Trainees />");
        }

        return results.toString();
    }

    /**
     * Get a list of relevant basic rotations for a person for the specified year.
     *
     * @param PEOsysid - the unique person identifer (as a double)
     * @param year - the year to retrieve rotations for
     * @return the XML string of the trainee rotations
     */
    public final String getTraineeRotationsByYear(final double PEOsysid, final int year) {

        String result = "";

        if (this.getAllowedAddress() && PEOsysid > 0) {

            final Calendar periodFrom = Calendar.getInstance();
            final Calendar periodTo = Calendar.getInstance();

            periodFrom.set(year, 1, 1, 0, 0);
            periodTo.set(year, 12, 31, 23, 59);

            PersonsRotations prts = loadRotations((int) PEOsysid, periodFrom, periodTo);

            result = this.rotationXmlOutput.getFirstGenRotations(prts.getRotations(), (int) PEOsysid,
                    prts.getDivision());
        }

        if (StringUtils.isBlank(result)) {
            result = "<rotations min=\"" + PEOsysid + "\" />";
        }

        return result;
    }

    /**
     * Update the educational and PDA supervisors for a specific rotation.
     *
     * @param PEOsysid the PEOsysid of the trainee (MIN)
     * @param rotationId the unique ID of the rotation
     * @param educationMIN the MIN number of the educational supervisor
     *        - if 0 then the rotation has no educational supervisor
     * @param pdaMIN the MIN number of the PDA supervisor
     *        - if 0 then the rotation has no PDA supervisor
     * @return the result string (SUCCESS/ERROR)
     */
    public final String updateRotationSupervisors(final double PEOsysid, final double rotationId,
            final double educationMIN, final double pdaMIN) {

        String result = "ERROR: Changes are not permitted from this IP address";

        if (this.getAllowedAddress()) {
            try {
                final boolean success = processRotationUpdate((int) PEOsysid, (int) rotationId, (int) educationMIN,
                        (int) pdaMIN);

                if (success) {
                    result = "SUCCESS";
                } else {
                    result = "ERROR: The rotation's supervisors could not be updated";
                }
            } catch (NullPointerException npe) {
                logger.error("Null pointer exception", npe);
                result = "ERROR: Null pointer exception";
            } catch (Exception e) {
                result = "ERROR: " + e.getMessage();
            }
        }
        return result;
    }

    /**
     * Gets the tool counts for a specific MIN (person identifier).
     *
     * @param PEOsysid the PEOsysid
     * @param trainingType the training type
     * @return the tool counts
     */
    public final String getToolCounts(final double PEOsysid, final String trainingType) {

        String result = "";

        if (this.getAllowedAddress() && PEOsysid > 0) {
            result = loadToolCounts(PEOsysid, trainingType);
        }

        if (StringUtils.isBlank(result)) {
            result = "<ToolCountsInfo />";
        }
        return result;
    }

    /**
     * Gets the training requirement years for a specific MIN (person identifier).
     *
     * @param PEOsysid the pE osysid
     * @param trainingType the training type
     * @return the training requirement years
     */
    public final String getTrainingRequirementYears(final double PEOsysid, final String trainingType) {

        String result = "";

        if (this.getAllowedAddress() && PEOsysid > 0) {
            result = loadTrainingRequirementYears(PEOsysid, trainingType);
        }

        if (StringUtils.isBlank(result)) {
            result = "<Trainings type=\"" + DataFilter.getHtml(trainingType) + "\" />";
        }
        return result;
    }

    /**
     * Load rotations.
     *
     * @param identifier the identifier
     * @param periodFrom the period from
     * @param periodTo the period to
     * @return an XML string of rotation data
     */
    private PersonsRotations loadRotations(final int identifier, final Calendar periodFrom,
            final Calendar periodTo) {

        SearchBean search = searchDAO.initiate("rotation", new UserBean());
        RotationBean criteria = (RotationBean) search.getSearchCriteria();
        RotationBean constraints = (RotationBean) search.getSearchConstraints();

        // Load the person based on the supplied identifier to get their division
        String division = "";
        int personGUID = 0;

        try {
            BuilderBean loadDetails = new BuilderBean();
            loadDetails.setParameter("MEMBERSHIP", true);

            PersonBean loadPerson = personDAO.loadIdentifier(identifier, loadDetails);

            personGUID = loadPerson.getGUID();

            if (StringUtils.isNotBlank(loadPerson.getMembershipField("Division"))) {
                division = loadPerson.getMembershipField("Division").substring(0, 1).toUpperCase();
            }
        } catch (WhichDoctorDaoException wde) {
            logger.error("Error loading person (" + identifier + "): " + wde.getMessage());
        } catch (NullPointerException npe) {
            logger.error("Error person found (" + identifier + "): " + npe.getMessage());
        }

        PersonBean person = new PersonBean();
        person.setPersonIdentifier(identifier);

        criteria.setPersonSearch(person);

        Date dateTo = DataFilter.parseDate("31/12/2037", false);
        Date dateFrom = DataFilter.parseDate("1/1/1900", false);

        if (periodTo != null) {
            dateTo = new Date(periodTo.getTime().getTime());
        }
        if (periodFrom != null) {
            dateFrom = new Date(periodFrom.getTime().getTime());
        }

        criteria.setStartDate(dateTo);
        constraints.setStartDate(DataFilter.parseDate("1/1/1900", false));

        criteria.setEndDate(dateFrom);
        constraints.setEndDate(DataFilter.parseDate("31/12/2037", false));

        search.setSearchCriteria(criteria);
        search.setSearchConstraints(constraints);
        search.setLimit(0);

        BuilderBean loadDetails = new BuilderBean();
        loadDetails.setParameter("ACCREDITATIONS", true);
        loadDetails.setParameter("ASSESSMENTS", true);
        loadDetails.setParameter("SUPERVISORS", true);

        // Load the list of relevant rotations
        SearchResultsBean results = null;
        try {
            results = searchDAO.search(search, loadDetails);
        } catch (WhichDoctorSearchDaoException wse) {
            logger.error("Error performing search for rotations: " + wse.getMessage());
        }

        List<RotationBean> rotations = new ArrayList<RotationBean>();
        if (results != null && results.getSearchResults() != null) {
            for (Object obj : results.getSearchResults()) {
                RotationBean rotation = (RotationBean) obj;
                rotations.add(rotation);
            }
        }

        List<RotationBean> currentRotations = new ArrayList<RotationBean>();
        try {
            Collection<RotationBean> crtns = this.rotationDAO.loadCurrentForPerson(personGUID);
            if (crtns != null) {
                for (RotationBean rtn : crtns) {
                    if (rtn != null) {
                        currentRotations.add(rtn);
                    }
                }
            }

        } catch (WhichDoctorDaoException wde) {
            logger.error("Error loading current rotations: " + wde.getMessage());
        }

        return new PersonsRotations(division, rotations, currentRotations);
    }

    /**
     * Load tool counts as an XML string.
     *
     * @param PEOsysid the pE osysid
     * @param trainingType the training type
     * @return the string
     */
    private String loadToolCounts(final double PEOsysid, final String trainingType) {

        String xml = "";

        // Load the person with all rotations and project data
        PersonBean person = null;
        BuilderBean loadDetails = new BuilderBean();
        loadDetails.setParameter("PROJECTS", true);
        loadDetails.setParameter("TRAINING_ROTATIONS", true);

        try {
            person = personDAO.loadIdentifier((int) PEOsysid, loadDetails);
        } catch (WhichDoctorDaoException wde) {
            logger.error("Error loading person: " + wde.getMessage());
        }

        if (person != null) {
            xml = this.rotationXmlOutput.getToolCount(person, trainingType);
        }
        return xml;
    }

    /**
     * Load training requirement years as an XML string.
     *
     * @param PEOsysid the pE osysid
     * @param trainingType the training type
     * @return the string
     */
    private String loadTrainingRequirementYears(final double PEOsysid, final String trainingType) {

        String xml = "";

        // Load the person with all rotations and specialty data
        PersonBean person = null;
        BuilderBean loadDetails = new BuilderBean();
        loadDetails.setParameter("SPECIALTY", true);
        loadDetails.setParameter("TRAINING_ROTATIONS", true);

        try {
            person = personDAO.loadIdentifier((int) PEOsysid, loadDetails);
        } catch (WhichDoctorDaoException wde) {
            logger.error("Error loading person: " + wde.getMessage());
        }

        if (person != null) {
            xml = this.rotationXmlOutput.getTrainingRequirementYears(person, trainingType);
        }

        return xml;
    }

    /**
     * Find people based on the supplied parameters.
     *
     * @param year the year
     * @param program the program
     * @param training_site_country_code the training_site_country_code
     * @param state the state
     * @param primary_site the primary_site
     * @param training_site the training_site
     * @param division the division
     * @param keyword the keyword
     * @param incl_prep the incl_prep
     * @param incl_non_prep the incl_non_prep
     * @return the string
     */
    private List<Integer> findPeople(final int year, final String program, final String training_site_country_code,
            final String state, final String primary_site, final String training_site, final String division,
            final String keyword, final int incl_prep, final int incl_non_prep) {

        List<Integer> personIdentifiers = new ArrayList<Integer>();
        TreeMap<Integer, Integer> people = new TreeMap<Integer, Integer>();

        SearchBean search = initiateSearch(year, program, training_site_country_code, state, primary_site,
                training_site, division, keyword);

        // Load the list of relevant rotations to find the person identifiers
        SearchResultsBean results = null;
        try {
            results = searchDAO.search(search, new BuilderBean());
        } catch (WhichDoctorSearchDaoException wse) {
            logger.error("Error performing search for rotations: " + wse.getMessage());
        }

        if (incl_prep == 0 || incl_non_prep == 0) {
            // For the next part we need to set the search to neutral so that we may
            // perform a subsearch within the existing parameters.
            search.setSearchVectors(results.getSearchVectors());
            search = searchPREP(search, incl_prep, incl_non_prep);

            try {
                results = searchDAO.search(search, new BuilderBean());
            } catch (WhichDoctorSearchDaoException wse) {
                logger.error("Error performing search for rotations: " + wse.getMessage());
            }
        }

        if (results != null && results.getSearchResults() != null) {
            for (Object obj : results.getSearchResults()) {
                RotationBean rotation = (RotationBean) obj;
                if (rotation.getPerson() != null) {
                    int id = rotation.getPerson().getPersonIdentifier();
                    if (!people.containsKey(id)) {
                        people.put(id, id);
                    }
                }
            }
        }

        for (Integer id : people.keySet()) {
            personIdentifiers.add(id);
        }
        return personIdentifiers;
    }

    /**
     * Process the rotation update.
     *
     * @param traineeMIN the trainee MIN
     * @param rotationGUID the rotation GUID
     * @param educationMIN the education MIN
     * @param pdaMIN the pda MIN
     * @return the result string
     * @throws Exception the exception
     */
    private boolean processRotationUpdate(final int traineeMIN, final int rotationGUID, final int educationMIN,
            final int pdaMIN) throws Exception {

        boolean success = false;

        // Check that the trainee, rotation and supervisor records exist.
        // If not return an error
        loadTrainee(traineeMIN);
        RotationBean rotation = loadRotation(rotationGUID);
        PersonBean educationSpvr = loadSupervisor(educationMIN);
        PersonBean pdaSpvr = loadSupervisor(pdaMIN);

        // Process the supervisor change
        ArrayList<SupervisorBean> updatedSupervisorList = new ArrayList<SupervisorBean>();

        // This holds the existing supervisors that maybe changed
        TreeMap<String, ArrayList<SupervisorBean>> supervisorsToBeChanged = new TreeMap<String, ArrayList<SupervisorBean>>();

        // First build a list of existing supervisors that do not need modifying
        if (rotation.getSupervisors() != null) {
            for (SupervisorBean spvr : rotation.getSupervisors()) {

                // At present function only changes the Education and PDA supervisors.
                // Any other supervisors should be added to the updated list.
                String type = spvr.getRelationshipType();
                if (StringUtils.equalsIgnoreCase("Education", type) || StringUtils.equalsIgnoreCase("PDA", type)) {

                    ArrayList<SupervisorBean> spvrs = new ArrayList<SupervisorBean>();
                    if (supervisorsToBeChanged.containsKey(type)) {
                        spvrs = supervisorsToBeChanged.get(type);
                    }

                    if (StringUtils.equalsIgnoreCase("Education", type)) {
                        // An education supervisor - if educationMIN < 0 then unchanged
                        if (educationMIN < 0) {
                            updatedSupervisorList.add(spvr);
                        } else {
                            spvrs.add(spvr);
                        }
                    }

                    if (StringUtils.equalsIgnoreCase("PDA", type)) {
                        // An education supervisor - if pdaMIN < 0 then unchanged
                        if (pdaMIN < 0) {
                            updatedSupervisorList.add(spvr);
                        } else {
                            spvrs.add(spvr);
                        }
                    }
                    supervisorsToBeChanged.put(type, spvrs);
                } else {
                    updatedSupervisorList.add(spvr);
                }
            }
        }

        // WhichDoctor can store multiple education/PDA supervisors,
        // but the web service only accepts one of each.
        int educationOrder = EDUCATION_ORDER;
        int pdaOrder = PDA_ORDER;

        // Update the education supervisor (if one is provided)
        if (educationSpvr != null) {
            boolean supervisorProcessed = false;

            if (supervisorsToBeChanged.containsKey("Education")) {
                // Education supervisors currently exist - check if new or existing.
                ArrayList<SupervisorBean> spvrs = supervisorsToBeChanged.get("Education");

                for (SupervisorBean spvr : spvrs) {
                    if (spvr.getPersonGUID() == educationSpvr.getGUID()) {
                        // The supervisor already exists, add the updated list
                        updatedSupervisorList.add(spvr);
                        supervisorProcessed = true;
                    }
                }
            }

            if (!supervisorProcessed) {
                // The supervisor does not currently exist, create new
                updatedSupervisorList
                        .add(createSupervisor(rotation.getGUID(), educationSpvr, educationOrder, "Education"));
            }
        }

        // Update the PDA supervisor (if one is provided)
        if (pdaSpvr != null) {
            boolean supervisorProcessed = false;

            if (supervisorsToBeChanged.containsKey("PDA")) {
                // PDA supervisors currently exist - check if new or existing.
                ArrayList<SupervisorBean> spvrs = supervisorsToBeChanged.get("PDA");

                for (SupervisorBean spvr : spvrs) {
                    if (spvr.getPersonGUID() == pdaSpvr.getGUID()) {
                        // The supervisor already exists, add the updated list
                        updatedSupervisorList.add(spvr);
                        supervisorProcessed = true;
                    }
                }
            }

            if (!supervisorProcessed) {
                // The supervisor does not currently exist, create new
                updatedSupervisorList.add(createSupervisor(rotation.getGUID(), pdaSpvr, pdaOrder, "PDA"));
            }
        }

        // Add the updated list of supervisors
        rotation.setSupervisors(updatedSupervisorList);
        rotation.setLogMessage("Rotation supervisors updated by web service");

        // Load the privileges bean for the change
        PrivilegesBean privileges = null;
        try {
            privileges = privilegesDAO.load();
        } catch (SFSDaoException sde) {
            logger.error("Error loading privileges: " + sde.getMessage());
            throw new Exception("Error loading privileges");
        }

        // Update the rotation and supervisors
        try {
            rotationDAO.modify(rotation, this.user, privileges);
            success = true;
        } catch (WhichDoctorDaoException wde) {
            logger.error("Error modifying rotation: " + wde.getMessage());
            throw new Exception("Cannot modify rotation - " + wde.getMessage());
        }

        return success;
    }

    /**
     * Load the trainee.
     *
     * @param identifier the identifier
     * @return the person bean
     * @throws Exception the exception
     */
    private PersonBean loadTrainee(final int identifier) throws Exception {

        PersonBean person = null;

        try {
            person = personDAO.loadIdentifier(identifier);
        } catch (WhichDoctorDaoException wde) {
            logger.error("Error loading trainee: " + wde.getMessage());
        }
        if (person == null) {
            throw new Exception("Trainee not found");
        }
        return person;
    }

    /**
     * Load the supervisor.
     * Throws an error if the identifier is greater than zero but no result is found.
     *
     * @param identifier the identifier
     * @return the person bean
     * @throws Exception the exception
     */
    private PersonBean loadSupervisor(final int identifier) throws Exception {

        PersonBean person = null;

        if (identifier > 0) {
            // Try to load the supervisor
            try {
                person = personDAO.loadIdentifier(identifier);
            } catch (WhichDoctorDaoException wde) {
                logger.error("Error loading PDA supervisor: " + wde.getMessage());
            }
            if (person == null) {
                // The PDA supervisor was not found within WhichDoctor
                throw new Exception("Supervisor not found");
            }
        }
        return person;
    }

    /**
     * Load the rotation.
     *
     * @param guid the guid
     * @return the rotation bean
     * @throws Exception the exception
     */
    private RotationBean loadRotation(final int guid) throws Exception {

        RotationBean rotation = null;

        try {
            BuilderBean loadDetails = new BuilderBean();
            // Load all of the rotation's details
            loadDetails.setParameter("LOAD_ALL", true);

            rotation = rotationDAO.loadGUID(guid, loadDetails);
        } catch (WhichDoctorDaoException wde) {
            logger.error("Error loading rotation: " + wde.getMessage());
        }
        if (rotation == null) {
            throw new Exception("Rotation not found");
        }
        return rotation;
    }

    /**
     * Initiate the rotation search.
     *
     * @param year the year
     * @param program the program
     * @param training_site_country_code the training_site_country_code
     * @param state the state
     * @param primary_site the primary_site
     * @param training_site the training_site
     * @param division the division
     * @param keyword the keyword
     * @return the search bean
     */
    private SearchBean initiateSearch(final int year, final String program, final String training_site_country_code,
            final String state, final String primary_site, final String training_site, final String division,
            final String keyword) {

        SearchBean search = searchDAO.initiate("rotation", new UserBean());
        search.setLimit(0);

        RotationBean criteria = (RotationBean) search.getSearchCriteria();
        RotationBean constraints = (RotationBean) search.getSearchConstraints();

        if (year > 0) {
            final Calendar periodFrom = Calendar.getInstance();
            final Calendar periodTo = Calendar.getInstance();

            periodFrom.set(year, 1, 1, 0, 0);
            periodTo.set(year, 12, 31, 23, 59);

            criteria.setStartDate(new Date(periodTo.getTime().getTime()));
            constraints.setStartDate(DataFilter.parseDate("1/1/1900", false));

            criteria.setEndDate(new Date(periodFrom.getTime().getTime()));
            constraints.setEndDate(DataFilter.parseDate("31/12/2037", false));
        }

        // The program details
        if (StringUtils.equalsIgnoreCase(program, "BT")) {
            criteria.setRotationType("Basic Training");
        }
        if (StringUtils.equalsIgnoreCase(program, "AT")) {
            criteria.setRotationType("Advanced Training");
        }

        if (StringUtils.isNotBlank(keyword)) {
            criteria.setBasicSearch(keyword);
        }

        OrganisationBean orgCriteria = new OrganisationBean();
        AddressBean addrCriteria = new AddressBean();
        boolean organisation = false;
        boolean address = false;

        // Load the country code
        if (StringUtils.isNotBlank(training_site_country_code)) {
            try {
                String country = this.objectTypeDAO.load("State/Country", training_site_country_code);
                addrCriteria.setCountry(country);
                organisation = true;
                address = true;
            } catch (SFSDaoException sfe) {
                logger.error("Error loading country abbreviation: " + sfe.getMessage());
            }
        }

        if (StringUtils.isNotBlank(state)) {
            addrCriteria.setAddressField(state);
            organisation = true;
            address = true;
        }

        if (StringUtils.isNotBlank(primary_site)) {
            orgCriteria.setName(training_site);
            organisation = true;
        }

        if (StringUtils.isNotBlank(training_site)) {
            orgCriteria.setName(training_site);
            organisation = true;
        }

        if (organisation) {
            if (address) {
                Collection<AddressBean> addresses = new ArrayList<AddressBean>();
                addresses.add(addrCriteria);
                orgCriteria.setAddress(addresses);
            }
            criteria.setOrganisation1(orgCriteria);
        }

        if (StringUtils.equalsIgnoreCase(division, "A") || StringUtils.equalsIgnoreCase(division, "P")) {

            ObjectTypeBean object = new ObjectTypeBean();
            if (StringUtils.equalsIgnoreCase(division, "P")) {
                object.setClassName("Paediatric");
            } else {
                object.setClassName("Adult");
            }

            MembershipBean mCriteria = this.membershipDAO.getDefaultInstance();
            mCriteria.setField("Division", object);

            Collection<MembershipBean> memberships = new ArrayList<MembershipBean>();
            memberships.add(mCriteria);

            PersonBean pCriteria = new PersonBean();
            pCriteria.setMembershipDetails(memberships);
            criteria.setPersonSearch(pCriteria);
        }

        search.setSearchCriteria(criteria);
        search.setSearchConstraints(constraints);

        return search;
    }

    /**
     * Search for the PREP parameters.
     *
     * @param search the search
     * @param incl_prep the incl_prep
     * @param incl_non_prep the incl_non_prep
     * @return the search bean
     */
    private SearchBean searchPREP(final SearchBean search, final int incl_prep, final int incl_non_prep) {

        search.clearPreviousSearch();
        search.setAction("subtract");

        SearchBean newSearch = searchDAO.initiate("rotation", new UserBean());

        RotationBean criteria = (RotationBean) newSearch.getSearchCriteria();
        RotationBean constraints = (RotationBean) newSearch.getSearchConstraints();

        PersonBean pCriteria = new PersonBean();
        PersonBean pConstraints = new PersonBean();

        SpecialtyBean specialtyCriteria = new SpecialtyBean();
        SpecialtyBean specialtyConstraints = new SpecialtyBean();

        if (incl_prep == 0) {
            // Subtract people with a specialty with a curriculum year greater than 2008
            specialtyCriteria.setTrainingProgramYear(2008);
            specialtyConstraints.setTrainingProgramYear(2037);
        }
        if (incl_non_prep == 0) {
            // Subtract people with a specialty with a curriculum year less than 2008
            specialtyCriteria.setTrainingProgramYear(2007);
            specialtyConstraints.setTrainingProgramYear(1900);
        }
        if (incl_prep == 0 && incl_non_prep == 0) {
            // Subtract people with a specialty with a curriculum year between 1900 & 2037
            specialtyCriteria.setTrainingProgramYear(1900);
            specialtyConstraints.setTrainingProgramYear(2037);
        }

        Collection<SpecialtyBean> sCriteria = new ArrayList<SpecialtyBean>();
        Collection<SpecialtyBean> sConstraints = new ArrayList<SpecialtyBean>();
        sCriteria.add(specialtyCriteria);
        sConstraints.add(specialtyConstraints);

        pCriteria.setSpecialtyList(sCriteria);
        pConstraints.setSpecialtyList(sConstraints);

        criteria.setPersonSearch(pCriteria);
        constraints.setPersonSearch(pConstraints);

        search.setSearchCriteria(criteria);
        search.setSearchConstraints(constraints);

        return search;
    }

    /**
     * Creates the supervisor.
     *
     * @param rotationGUID the rotation guid
     * @param person the person
     * @param orderId the order id
     * @param type the type
     * @return the supervisor bean
     */
    private SupervisorBean createSupervisor(final int rotationGUID, final PersonBean person, final int orderId,
            final String type) {

        SupervisorBean spvr = new SupervisorBean();

        spvr.setReferenceGUID(rotationGUID);
        spvr.setPerson(person);
        spvr.setOrderId(orderId);
        spvr.setRelationshipClass("Basic Training Supervisor");
        spvr.setRelationshipType(type);
        spvr.setSupervisorClass("rotation");

        return spvr;
    }

    /**
     * Parses the person identifiers.
     *
     * @param personIdentifiers the person identifiers
     * @return the list
     */
    private List<Integer> parseIdentifiers(final String personIdentifiers) {

        List<Integer> identifiers = new ArrayList<Integer>();

        StringTokenizer tk = new StringTokenizer(personIdentifiers, ",");

        while (tk.hasMoreTokens()) {
            String token = tk.nextToken();

            int identifier = 0;
            try {
                String value = StringUtils.replace(token, "\"", "");
                value = StringUtils.replace(value, "'", "");
                identifier = Integer.parseInt(value.trim());
            } catch (NumberFormatException nfe) {
                logger.info("Error parsing person identifier: " + nfe.getMessage());
            }

            if (identifier > 0) {
                identifiers.add(identifier);
            }
        }
        return identifiers;
    }

    /**
     * Order the third gen rotations by year descending and start date ascending.
     *
     * @param rotations the rotations
     * @return the list
     */
    private List<RotationBean> orderThirdGenRotations(final List<RotationBean> rotations) {

        List<RotationBean> orderedRotations = new ArrayList<RotationBean>();

        Map<Integer, Map<Long, RotationBean>> order = new TreeMap<Integer, Map<Long, RotationBean>>(
                Collections.reverseOrder());

        if (rotations != null) {
            int counter = 0;

            for (RotationBean rotation : rotations) {
                Map<Long, RotationBean> orts = new TreeMap<Long, RotationBean>();
                if (order.containsKey(rotation.getYear())) {
                    orts = order.get(rotation.getYear());
                }

                String key = rotation.getStartDate().getTime() + "0" + counter;

                orts.put(Long.parseLong(key), rotation);

                order.put(rotation.getYear(), orts);

                counter++;
            }
        }

        for (int year : order.keySet()) {
            Map<Long, RotationBean> orts = order.get(year);
            for (long key : orts.keySet()) {
                RotationBean rotation = orts.get(key);
                orderedRotations.add(rotation);
            }
        }
        return orderedRotations;
    }

}