package gov.va.vinci.dart;

import gov.va.vinci.dart.biz.Activity;
import gov.va.vinci.dart.biz.DartRequest;
import gov.va.vinci.dart.biz.Group;
import gov.va.vinci.dart.biz.Location;
import gov.va.vinci.dart.biz.OperationalRequest;
import gov.va.vinci.dart.biz.OperationalStudy;
import gov.va.vinci.dart.biz.Participant;
import gov.va.vinci.dart.biz.Person;
import gov.va.vinci.dart.biz.PreparatoryRequest;
import gov.va.vinci.dart.biz.PreparatoryStudy;
import gov.va.vinci.dart.biz.Request;
import gov.va.vinci.dart.biz.ResearchStudy;
import gov.va.vinci.dart.biz.Role;
import gov.va.vinci.dart.common.exception.ObjectNotFoundException;
import gov.va.vinci.dart.common.json.ErrorView;
import gov.va.vinci.dart.db.util.HibernateSessionManager;
import gov.va.vinci.dart.json.CreateActivityView;
import gov.va.vinci.dart.json.NewActivityView;
import gov.va.vinci.dart.json.PILocationView;
import gov.va.vinci.dart.json.PIParticipantInfoView;
import gov.va.vinci.dart.json.PIParticipantView;
import gov.va.vinci.dart.json.PrimaryInfoView;
import gov.va.vinci.dart.json.RequestIdView;
import gov.va.vinci.dart.json.SaveActivityView;
import gov.va.vinci.dart.json.SavePrimaryInfoView;
import gov.va.vinci.dart.json.SetupView;
import gov.va.vinci.dart.json.atom.AtomLinkFactory;
import gov.va.vinci.dart.json.builder.ActivityViewBuilder;
import gov.va.vinci.dart.service.DartObjectFactory;
import gov.va.vinci.dart.usr.UserManager;
import gov.va.vinci.dart.usr.UserPreferences;
import gov.va.vinci.dart.wf2.EmailUtils;
import gov.va.vinci.dart.wf2.WorkflowResolver;
import gov.va.vinci.security.userdetails.UserDetails;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.persistence.NoResultException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class ActivityController extends DartController {

    private static final int SHORT_NAME_LENGTH = 64;
    public static final String VINCI_SERVICES_USER_ID = "123";
    public static final SimpleDateFormat SDF = new SimpleDateFormat("MM/dd/yyyy");

    public static final String DEFAULT_ROLE = "none";
    public static final String PRIMARY_INVESTIGATOR_ROLE = "primary investigator";

    private static Log log = LogFactory.getLog(ActivityController.class);

    @Autowired
    private AtomLinkFactory linkFactory;

    @Autowired
    private WorkflowResolver workflowResolver;

    public static Activity retrieveActivity(final int activityId) throws ObjectNotFoundException {
        Activity activity = null;

        // find the activity, based on type
        try {
            activity = ResearchStudy.findById(activityId);
        } catch (NoResultException e) {

        }

        try {
            if (activity == null) {
                activity = PreparatoryStudy.findById(activityId);
            }
        } catch (NoResultException e) {

        }

        try {
            if (activity == null) {
                activity = OperationalStudy.findById(activityId);
            }
        } catch (NoResultException e) {

        }

        return activity;
    }

    @RequestMapping(value = "/setup", method = RequestMethod.GET)
    @ResponseBody
    public Object setup(final HttpServletRequest request) {

        log.debug("setup");
        linkFactory.setURIBase(request.getRequestURL().toString());

        try {

            HibernateSessionManager.start();

            UserPreferences prefs = getUserPreferences();

            SetupView view = new SetupView();

            view.setUserId(prefs.getUserId());
            view.setUserLoginId(prefs.getUserLoginId());
            view.setUserFullName(prefs.getUserFullName());
            view.setReportingLink(getReportingPage());

            // default permissions
            view.setRequestor(true);
            view.setAdmin(false); // reviewer
            view.setStaff(false); // read-only staff
            view.setJanitor(false); // Administration Tool tab

            Person user = Person.findById(prefs.getUserId());
            Role.initialize();

            // add user roles to the response
            for (Role role : user.listRoles()) {
                view.getRoles().add(role.getName());
            }

            // add user groups for display purposes...
            for (Group group : user.getGroups()) {
                view.getGroups().add(group.getShortName());
            }

            view.setNdsAdmin(user.hasRole(Role.NDS_ADMIN) == true);

            // Irma cannot initiate requests
            // Reviewers cannot initiate requests
            if (user.hasRole(Role.NDS_ADMIN) || user.hasRole(Role.REVIEWER)) {
                view.setRequestor(false);
            }

            // reviewer
            if (user.hasRole(Role.NDS_ADMIN) || user.hasRole(Role.REVIEWER)) {
                view.setAdmin(true);
            }

            if (user.hasRole(Role.ADMINISTRATOR)) {
                view.setJanitor(true); // Administration Tool tab
            }

            if (user.hasRole(Role.READ_ONLY_STAFF)) {
                view.setStaff(true); // read-only staff

                view.setAdmin(false); // read-only staff is not currently NDS admin, reviewer, or requestor
                view.setRequestor(false);
            }

            if (user.hasRole(Role.SUPER_USER)) {
                view.setSuperUser(true);

                view.setAdmin(false); // super-user is not currently NDS admin or requestor
                view.setRequestor(false);
            }

            view.setDebug(DartController.isDebugMode()); // debug mode?

            return view;
        } catch (Exception e) {
            log.error("Error loading setup data.", e);
            HibernateSessionManager.rollback();
            return new ErrorView("Error loading setup data.");
        } finally {
            HibernateSessionManager.close();
        }
    }

    @RequestMapping(value = "/savePrimaryInfo", method = RequestMethod.POST)
    @ResponseBody
    public Object savePrimaryInfo(@RequestBody @Valid final SavePrimaryInfoView view) {

        log.debug("saving primary info for request id = " + view.getRequestId());

        try {
            HibernateSessionManager.start();

            UserPreferences prefs = getUserPreferences();

            Request request = null;

            try {
                request = RequestController.retrieveRequest(view.getRequestId());
            } catch (ObjectNotFoundException e) {
                return new ErrorView("Error retrieving request: " + e.getMessage());
            }

            if (request == null) {
                return new ErrorView("Error retrieving request: " + view.getRequestId());
            }

            Person person = null;
            try {
                person = Person.findById(prefs.getUserId());
            } catch (ObjectNotFoundException e) {
                throw new ObjectNotFoundException("Cannot find person with id: " + prefs.getUserId());
            }
            Role.initialize();

            // verify the access permissions
            if (request.hasCreatorOrParticipant(person) == false) { // participant or the request creator?
                return new ErrorView("Error: User does not have permission to perform this action.");
            }
            if (person.hasRole(Role.SUPER_USER) == true || person.hasRole(Role.NDS_ADMIN) == true
                    || person.hasRole(Role.REVIEWER) == true || person.hasRole(Role.READ_ONLY_STAFF) == true) {
                return new ErrorView("Error: User does not have permission to perform this action.");
            }

            // is request changeable?
            if (request.isEditable(null) == false) {
                return new ErrorView("Error: request is not in editable state.");
            }

            createSites(request, view);

            createParticipants(request, view);

        } catch (Exception e) {
            log.error("Error saving request participant data.", e);
            HibernateSessionManager.rollback();
            return new ErrorView("Error saving request participant data.");
        } finally {
            HibernateSessionManager.close();
        }

        return new ErrorView("OK");
    }

    // call this in the context of a Hibernate transaction
    private void createSites(final Request request, final SavePrimaryInfoView view) throws Exception {

        if (view == null || view.getPrimaryInfo() == null) {
            return;
        }

        ArrayList<Location> orphans = new ArrayList<Location>();
        orphans.addAll(request.getSites());
        Location primaryLocation = null;

        // walk through the list of locations submitted
        for (PILocationView piView : view.getPrimaryInfo().getLocations()) {

            Location loc = Location.findById(piView.getLocationId()); // find the location by id

            if (loc == null) {
                throw new ObjectNotFoundException("Location " + piView.getLocation() + " not found.");
            } else {
                request.getSites().add(loc);
                orphans.remove(loc);

                if (piView.isPrimary()) {
                    primaryLocation = loc;
                }
            }
        }

        if (orphans.size() > 0) {
            log.debug("removing sites from request.");
            for (Location loc : orphans) {
                request.removeLocationDocuments(loc);

                request.getSites().remove(loc);
            }
        }

        request.setPrimaryLocation(primaryLocation);
    }

    // call this in the context of a Hibernate transaction
    private void createParticipants(final Request request, final SavePrimaryInfoView view) throws Exception {

        // anything to do?
        if (view.getPrimaryInfo() == null || view.getPrimaryInfo().getInvestigators() == null
                || view.getPrimaryInfo().getInvestigators().size() == 0) {
            return;
        }

        ArrayList<Participant> orphans = new ArrayList<Participant>();
        orphans.addAll(request.getParticipants());

        // first let's walk through the list of investigators and harvest locations from it
        for (Integer locationId : view.getPrimaryInfo().getInvestigators().keySet()) {

            Location loc = Location.findById(locationId); // find the location by id

            if (loc == null) {
                throw new ObjectNotFoundException("Location ID " + locationId + " not found.");
            } else {
                // now let's walk through the list of participants for the location
                PIParticipantView participantView = view.getPrimaryInfo().getInvestigators().get(locationId);

                for (PIParticipantInfoView participantInfoView : participantView.getParticipants()) {

                    String participantName = participantInfoView.getName(); // participant username

                    boolean hasNotifications = participantInfoView.isChecked();
                    boolean hasDataAccess = participantInfoView.isDataAccessChecked();
                    boolean hasCapriAccess = participantInfoView.isCapriAccessChecked();

                    // log.debug("participantName = " + participantName + ", hasNotifications = " + hasNotifications +
                    // ", hasDataAccess = " + hasDataAccess);

                    Person person = null;

                    try {
                        person = Person.findByName(participantInfoView.getUsername());
                    } catch (ObjectNotFoundException e) {
                        // ignore here - handle in the next if block
                    }

                    if (person == null) {
                        log.debug("Person " + participantName + " not found.");

                        UserManager userManager = DartObjectFactory.getInstance().getUserManager();
                        // userManager.setUserPreferences(new UserPreferencesImpl());

                        // get the participant's info from Active Directory
                        UserDetails userDetails = userManager.getUserDetails(participantInfoView.getUsername());

                        // person selected from the Active Directory should be created in our database.
                        person = Person.create(participantInfoView.getUsername(), userDetails.getFullName(), loc);
                        Participant part = Participant.create(person, request, loc, hasNotifications, hasDataAccess, hasCapriAccess, false); // default
                                                                                                                             // to
                                                                                                                             // NOT
                                                                                                                             // the
                                                                                                                             // principal
                                                                                                                             // investigator
                                                                                                                             // for
                                                                                                                             // now
                                                                                                                             // (updated
                                                                                                                             // later)
                        request.getParticipants().add(part);
                    } else {
                        // find that person/location in the orphans list
                        Participant part = findParticipant(orphans, person, loc);

                        if (part == null) {
                            // create a participant object for that person in that location
                            part = Participant.create(person, request, loc, hasNotifications, hasDataAccess, hasCapriAccess, false); // default
                                                                                                                     // to NOT
                                                                                                                     // the
                                                                                                                     // principal
                                                                                                                     // investigator
                                                                                                                     // for now
                                                                                                                     // (updated
                                                                                                                     // later)
                            request.getParticipants().add(part);
                        } else {
                            log.debug("remove participant from orphans " + part + " id = " + part.getId());
                            orphans.remove(part);

                            // update the participant (if the principal investigator has changed, clear that flag)
                            part.modify(person, request, loc, hasNotifications, hasDataAccess, hasCapriAccess, false); // default to NOT the
                                                                                                       // principal investigator
                                                                                                       // for now (updated
                                                                                                       // later)
                        }
                    }
                }// end for
            }// end else
        }// end for

        if (orphans.size() > 0) {
            log.debug("removing participants from request.");

            // clear the list of participant orphans from the request participants list
            for (Participant part : orphans) {
                // remove the participant documents
                request.removeParticipantDocuments(part);

                log.debug("removing orphaned participant " + part.getPerson().getFullName() + " from request "
                        + request.getTrackingNumber());
                request.getParticipants().remove(part);
                part.delete();
            }
        }

        // testing -- for OperationalRequest there will now only be one participant per request, so it should be okay to specify
        // that that one person is the principal investigator and that site is the primary site
        // if( DartRequest.class.isAssignableFrom(request.getClass()) ) { //OperationalRequest does not have a primary location
        // or principal investigator

        // now let's walk through the submitted list of locations and find the primary investigators for each location and the
        // primary site for the whole project
        for (PILocationView locationView : view.getPrimaryInfo().getLocations()) {

            Location loc = Location.findById(locationView.getLocationId()); // find the location by id
            if (loc == null) {
                throw new ObjectNotFoundException("Location " + locationView.getLocation() + " not found.");
            } else {
                if (locationView.isPrimary()) {
                    request.setPrimaryLocation(loc);
                }

                // find the location primary investigator
                log.debug("primary investigator name = " + locationView.getPrimaryInvestigator());

                Person primaryPerson = Person.findByName(locationView.getPrimaryInvestigatorUserId());

                if (primaryPerson == null) {
                    throw new ObjectNotFoundException("Person " + locationView.getPrimaryInvestigator() + " not found.");
                } else {
                    Participant primaryParticipant = null;
                    try {
                        primaryParticipant = request.findParticipant(primaryPerson, loc);
                    } catch (ObjectNotFoundException e) {
                        // ignore it.
                    }

                    if (primaryParticipant == null) {
                        throw new ObjectNotFoundException("Request principal investigator participant "
                                + locationView.getPrimaryInvestigator() + " not found.");
                    } else {

                        if (DartRequest.class.isAssignableFrom(request.getClass())) {

                            // set the location primary investigator and give them data access rights
                            primaryParticipant.modify(primaryPerson, request, loc, true, true, primaryParticipant.getCapriAccess(), true);

                        } else if (PreparatoryRequest.class.isAssignableFrom(request.getClass())) {

                            // set the location primary investigator and give them data access rights
                            primaryParticipant.modify(primaryPerson, request, loc, true, true, primaryParticipant.getCapriAccess(), true);

                        } else { // OperationalRequest now only has one participant per request (default to
                                 // principalInvestigator), but does not require that data access be checked

                            // set the location primary investigator but leave their data access and notifications as they were
                            primaryParticipant.modify(primaryPerson, request, loc, primaryParticipant.getNotification(),
                                    primaryParticipant.getDataAccess(), primaryParticipant.getCapriAccess(), true);
                        }
                    }
                }
            }
        }
        // }//end if -- DartRequest
    }

    private Participant findParticipant(final List<Participant> participantList, final Person person, final Location location) {
        Participant result = null;

        if (participantList != null && person != null && location != null) {
            for (Participant part : participantList) {
                if (part.getPerson().getId() == person.getId() && part.getLocation().getId() == location.getId()) {
                    return part;
                }
            }
        }
        return result;
    }

    @RequestMapping(value = "/saveActivityInfo", method = RequestMethod.POST)
    @ResponseBody
    public Object saveActivityInfo(@RequestBody @Valid final SaveActivityView view) {

        log.debug("saveActivityInfo requestId = " + view.getRequestId());

        try {
            HibernateSessionManager.start();

            UserPreferences prefs = getUserPreferences();

            Request request = null;

            try {
                request = RequestController.retrieveRequest(view.getRequestId());
            } catch (ObjectNotFoundException e) {
                return new ErrorView("Error retrieving request: " + e.getMessage());
            }

            if (request == null) {
                return new ErrorView("Error retrieving request: " + view.getRequestId());
            }

            // is request changeable?
            if (request.isEditable(null) == false) {
                return new ErrorView("Error: request is not in editable state.");
            }

            Person person = null;
            try {
                person = Person.findById(prefs.getUserId());
            } catch (ObjectNotFoundException e) {
                throw new ObjectNotFoundException("Cannot find person with id: " + prefs.getUserId());
            }
            Role.initialize();

            // verify the access permissions
            if (request.hasCreatorOrParticipant(person) == false) { // participant or the request creator?
                return new ErrorView("Error: User does not have permission to perform this action.");
            }
            if (person.hasRole(Role.SUPER_USER) == true || person.hasRole(Role.NDS_ADMIN) == true
                    || person.hasRole(Role.REVIEWER) == true || person.hasRole(Role.READ_ONLY_STAFF) == true) {
                return new ErrorView("Error: User does not have permission to perform this action.");
            }

            Date irbDate = isEmpty(view.getiRBExpirationDate()) == true ? null : SDF.parse(view.getiRBExpirationDate());
            Date startDate = isEmpty(view.getActivityStartDate()) == true ? null : SDF.parse(view.getActivityStartDate());
            Date endDate = isEmpty(view.getActivityEndDate()) == true ? null : SDF.parse(view.getActivityEndDate());

            Activity activity = null;
            try {

                activity = ActivityController.retrieveActivity(request.getActivity().getId());

                if (activity != null) {
                    if (ResearchStudy.class.isAssignableFrom(activity.getClass())) {

                        ResearchStudy researchStudy = (ResearchStudy) activity;
                        researchStudy.modify(view.getShortName(), startDate, endDate, researchStudy.getOfficialName(),
                                prefs.getUserLoginId());

                        log.debug("updated ResearchStudy activity - updated by = " + researchStudy.getUpdatedBy());

                    } else if (OperationalStudy.class.isAssignableFrom(activity.getClass())) {

                        OperationalStudy operationalStudy = (OperationalStudy) activity;
                        operationalStudy.modify(view.getShortName(), startDate, endDate, operationalStudy.getOfficialName(),
                                prefs.getUserLoginId(), prefs.getUserId());

                        log.debug("updated OperationalStudy activity - updated by = " + operationalStudy.getUpdatedBy());
                    } else if (PreparatoryStudy.class.isAssignableFrom(activity.getClass())) {
                        PreparatoryStudy preparatoryStudy = (PreparatoryStudy) activity;
                        preparatoryStudy
                                .modify(view.getShortName(), preparatoryStudy.getOfficialName(), prefs.getUserLoginId());

                    }
                }// end if
            } catch (ObjectNotFoundException e) {
                log.error("Error loading activity " + request.getActivity().getId(), e);
            }

            if (DartRequest.class.isAssignableFrom(request.getClass())) {
                DartRequest dartRequest = (DartRequest) request;
                dartRequest.modify(view.getShortName(), dartRequest.getDataSourceStartDate(),
                        dartRequest.getDataSourceEndDate(), view.getiRBApprovalNumber(), irbDate, prefs.getUserLoginId());

                request.setIrbExpiration(irbDate);
                request.setIrbNumber(view.getiRBApprovalNumber());
            } else if (OperationalRequest.class.isAssignableFrom(request.getClass())) {
                OperationalRequest opsRequest = (OperationalRequest) request;
                opsRequest
                        .modify(view.getShortName(), view.getProgramOffice(), view.getJustification(), prefs.getUserLoginId());
            } else if (PreparatoryRequest.class.isAssignableFrom(request.getClass())) {
                PreparatoryRequest preparatoryRequest = (PreparatoryRequest) request;
                Date expectedIRBSubmissiontDate =
                        isEmpty(view.getExpectedIRBSubmissionDate()) == true ? null : SDF.parse(view
                                .getExpectedIRBSubmissionDate());
                preparatoryRequest.modify(view.getShortName(), expectedIRBSubmissiontDate, prefs.getUserLoginId());
            }

        } catch (Exception e) {
            log.error("Error saving request data.", e);
            HibernateSessionManager.rollback();
            return new ErrorView("Error saving request data.");
        } finally {
            HibernateSessionManager.close();
        }

        return new ErrorView("OK");
    }

    public static boolean isEmpty(String str) {
        return str == null || str.length() < 1;
    }

    @RequestMapping(value = "/getActivityInfo", method = RequestMethod.POST)
    @ResponseBody
    public Object getActivityInfo(@RequestBody final RequestIdView view) {

        log.debug("get activity info for request " + view.getRequestId());

        try {
            HibernateSessionManager.start();

            UserPreferences prefs = getUserPreferences();

            Person person = null;
            try {
                person = Person.findById(prefs.getUserId());
            } catch (ObjectNotFoundException e) {
                return new ErrorView("Error: " + e.getMessage());
            }
            Role.initialize();

            Request request = null;
            try {
                request = RequestController.retrieveRequest(view.getRequestId());
            } catch (ObjectNotFoundException e) {
                return new ErrorView("Error retrieving request: " + e.getMessage());
            }

            // Activity activity = null;
            // int activityId = request.getActivity().getId();
            // try {
            // activity = ActivityController.retrieveActivity( activityId );
            // } catch (ObjectNotFoundException e) {
            // log.error("Error loading activity " + activityId, e);
            // return new ErrorView("Error retrieving activity: " + e.getMessage());
            // }
            Activity activity = request.getActivity();
            if (activity == null) {
                return new ErrorView("Error retrieving activity.");
            }

            // verify the access permissions
            if (activity.verifyReadAccessPermissions(person) == false) {
                return new ErrorView("Error: User does not have permission to perform this action.");
            }

            return new ActivityViewBuilder().build(activity, request, person);

        } catch (Exception e) {
            log.error("Error retrieving activity data.", e);
            HibernateSessionManager.rollback();
            return new ErrorView("Error retrieving activity data.");
        } finally {
            HibernateSessionManager.close();
        }
    }

    @RequestMapping(value = "/createActivity", method = RequestMethod.POST)
    @ResponseBody
    public Object createActivity(@RequestBody final CreateActivityView request) throws Exception {
        log.debug("create new activity");

        Activity activity = null;
        Request newRequest = null;

        try {
            HibernateSessionManager.start();

            UserPreferences prefs = getUserPreferences();

            String shortName = request.getOfficialName();
            if (shortName != null && shortName.length() > SHORT_NAME_LENGTH) {
                shortName = shortName.substring(0, SHORT_NAME_LENGTH);
            }

            Person requestor = Person.findById(prefs.getUserId());

            if (Request.DATA_ACCESS.equals(request.getType()) == true) {
                activity = ResearchStudy.create(shortName, null, null, request.getOfficialName(), prefs.getUserLoginId());

                // create a first request for that activity (creates an event too)
                newRequest = DartRequest.create(shortName, null, null, requestor, activity, prefs.getUserLoginId());

                newRequest.setWorkflowTypeId(WorkflowResolver.WF_RESEARCH_REQUEST); // set the top-level workflow type
            } else if (Request.PREPARATORY_TO_RESEARCH_ACCESS.equals(request.getType()) == true) {
                activity = PreparatoryStudy.create(shortName, null, null, request.getOfficialName(), prefs.getUserLoginId());

                // create a first request for that activity (creates an event too)
                newRequest = PreparatoryRequest.create(shortName, requestor, activity, prefs.getUserLoginId());
                newRequest.setWorkflowTypeId(WorkflowResolver.WF_PREPARATORY_REQUEST); // set the top-level workflow type
            } else if (Request.OPERATIONS_DATA_ACCESS.equals(request.getType()) == true) {
                activity =
                        OperationalStudy.create(shortName, null, null, request.getOfficialName(), prefs.getUserLoginId(),
                                prefs.getUserId());

                // create a first request for that activity (creates an event too)
                newRequest = OperationalRequest.create(shortName, requestor, activity, prefs.getUserLoginId());

                newRequest.setWorkflowTypeId(WorkflowResolver.WF_OPERATIONAL_REQUEST); // set the top-level workflow type
            } else {
                throw new IllegalStateException("Cannot create activity - Illegal request type");
            }

            workflowResolver.resolve(newRequest).initialize(null, newRequest, prefs.getUserLoginId()); // initialize the
                                                                                                       // top-level workflow

            // send the requestor an email (only the requestor, nobody has been added for notifications yet)
            EmailUtils.createAndSendRequestInitiatedEmail(newRequest, prefs.getUserLoginId());



        } catch (Exception e) {
            log.error("Error creating new Activity.", e);
            HibernateSessionManager.rollback();
            return new ErrorView("Error creating new Activity.");
        } finally {
            HibernateSessionManager.close();
        }

        NewActivityView view = new NewActivityView();
        view.setActivityId(activity.getId());
        view.setRequestId(newRequest.getId());

        return view;
    }

    @RequestMapping(value = "/getPrimaryInfo", method = RequestMethod.POST)
    @ResponseBody
    public Object getPrimaryInfo(@RequestBody final RequestIdView view) {

        log.debug("get primary info for request " + view.getRequestId());

        try {
            HibernateSessionManager.start();

            UserPreferences prefs = getUserPreferences();

            Person person = null;
            try {
                person = Person.findById(prefs.getUserId());
            } catch (ObjectNotFoundException e) {
                throw new ObjectNotFoundException("Cannot find person with id: " + prefs.getUserId());
            }
            Role.initialize();

            Request request = null;

            try {
                request = RequestController.retrieveRequest(view.getRequestId());
            } catch (ObjectNotFoundException e) {
                return new ErrorView("Error retrieving request: " + e.getMessage());
            }

            Activity activity = request.getActivity();
            int activityId = request.getActivity().getId();

            log.debug("activity id = " + activityId);

            if (activity == null) {
                // return default values
                return new PrimaryInfoView();
            }

            // verify the access permissions
            if (activity.verifyReadAccessPermissions(person) == false) {
                return new ErrorView("Error: User does not have permission to perform this action.");
            }

            PrimaryInfoView result = new PrimaryInfoView();

            Set<Location> locations = request.getSites();
            Set<Participant> participants = request.getParticipants();

            // loop on participants by location
            for (Location location : locations) {
                PIParticipantView piView = new PIParticipantView();
                Participant locationPrincipalInvestigator = null;

                // Does this location happen to be the primary for the activity?
                // if so, set the flag
                boolean activityPrimaryLocation = false;
                if (request.getPrimaryLocation() != null) {
                    activityPrimaryLocation = (location.getId() == request.getPrimaryLocation().getId());
                }

                for (Participant participant : participants) {
                    if (location.equals(participant.getLocation()) == true) {

                        // Does this participant happen to be the primary for the location?
                        // if so, save it
                        if (locationPrincipalInvestigator == null && participant.getPrincipalInvestigator() == true) {
                            locationPrincipalInvestigator = participant;
                        }

                        PIParticipantInfoView participantInfoView = new PIParticipantInfoView();
                        participantInfoView.setName(participant.getPerson().getFullName());
                        participantInfoView.setUsername(participant.getPerson().getName());
                        participantInfoView.setChecked(participant.getNotification());
                        participantInfoView.setDataAccessChecked(participant.getDataAccess());
                        participantInfoView.setCapriAccessChecked(participant.getCapriAccess());
                        piView.getParticipants().add(participantInfoView);
                    }
                }

                // sort the participant list (for display)
                Collections.sort(piView.getParticipants());

                result.getInvestigators().put(location.getId(), piView); // map based on the location ID

                result.getLocations().add(
                        new PILocationView(location.getName(), location.getId(), activityPrimaryLocation,
                                locationPrincipalInvestigator == null ? "" : locationPrincipalInvestigator.getPerson()
                                        .getFullName(), locationPrincipalInvestigator == null ? ""
                                        : locationPrincipalInvestigator.getPerson().getName()));
            }

            result.setAmendment(request.isAmendment());
            // sort the location list (for display)
            Collections.sort(result.getLocations());

            return result;

        } catch (Exception e) {
            log.error("Error retrieving participant data.", e);
            HibernateSessionManager.rollback();
            return new ErrorView("Error retrieving participant data.");
        } finally {
            HibernateSessionManager.close();
        }
    }
}
