gt:         if (CollectionUtils.isNotEmpty(getReviewAttachments())) {
context: /*
   * Kuali Coeus, a comprehensive research administration system for higher education.
   * 
   * Copyright 2005-2016 Kuali, Inc.
   * 
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Affero General Public License as
   * published by the Free Software Foundation, either version 3 of the
   * License, or (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU Affero General Public License for more details.
   * 
   * You should have received a copy of the GNU Affero General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  package org.kuali.kra.protocol.actions;
  
  import java.io.Serializable;
  import java.sql.Date;
  import java.sql.Timestamp;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import org.apache.commons.collections4.CollectionUtils;
  import org.apache.commons.lang3.StringUtils;
  import org.apache.commons.lang3.time.DateUtils;
  import org.kuali.coeus.common.committee.impl.bo.CommitteeBase;
  import org.kuali.coeus.common.committee.impl.bo.CommitteeScheduleBase;
  import org.kuali.coeus.common.committee.impl.lookup.keyvalue.CommitteeIdByUnitValuesFinderService;
  import org.kuali.coeus.common.committee.impl.meeting.CommitteeScheduleMinuteBase;
  import org.kuali.coeus.common.committee.impl.meeting.ProtocolVoteAbstaineeBase;
  import org.kuali.coeus.common.committee.impl.meeting.ProtocolVoteRecusedBase;
  import org.kuali.coeus.common.committee.impl.service.CommitteeScheduleServiceBase;
  import org.kuali.coeus.common.framework.auth.SystemAuthorizationService;
  import org.kuali.coeus.common.framework.module.CoeusSubModule;
  import org.kuali.coeus.common.framework.person.KcPersonService;
  import org.kuali.coeus.common.framework.auth.task.TaskAuthorizationService;
  import org.kuali.coeus.sys.framework.controller.DocHandlerService;
  import org.kuali.coeus.sys.framework.keyvalue.KeyValueComparator;
  import org.kuali.coeus.sys.framework.keyvalue.PrefixValuesFinder;
  import org.kuali.coeus.sys.framework.service.KcServiceLocator;
  import org.kuali.kra.infrastructure.Constants;
  import org.kuali.kra.infrastructure.TaskName;
  import org.kuali.kra.protocol.ProtocolBase;
  import org.kuali.kra.protocol.ProtocolDocumentBase;
  import org.kuali.kra.protocol.ProtocolFormBase;
  import org.kuali.kra.protocol.ProtocolVersionService;
  import org.kuali.kra.protocol.actions.amendrenew.ProtocolAmendRenewService;
  import org.kuali.kra.protocol.actions.amendrenew.ProtocolAmendRenewalBase;
  import org.kuali.kra.protocol.actions.amendrenew.ProtocolAmendmentBean;
  import org.kuali.kra.protocol.actions.approve.ProtocolApproveBean;
  import org.kuali.kra.protocol.actions.assignagenda.ProtocolAssignToAgendaBean;
  import org.kuali.kra.protocol.actions.correction.AdminCorrectionBean;
  import org.kuali.kra.protocol.actions.decision.CommitteeDecision;
  import org.kuali.kra.protocol.actions.decision.CommitteeDecisionService;
  import org.kuali.kra.protocol.actions.delete.ProtocolDeleteBean;
  import org.kuali.kra.protocol.actions.followup.FollowupActionService;
  import org.kuali.kra.protocol.actions.genericactions.ProtocolGenericActionBean;
  import org.kuali.kra.protocol.actions.notifycommittee.ProtocolNotifyCommitteeBean;
  import org.kuali.kra.protocol.actions.print.CorrespondencePrintOption;
  import org.kuali.kra.protocol.actions.print.ProtocolQuestionnairePrintingService;
  import org.kuali.kra.protocol.actions.print.ProtocolSummaryPrintOptions;
  import org.kuali.kra.protocol.actions.print.QuestionnairePrintOption;
  import org.kuali.kra.protocol.actions.request.ProtocolRequestBean;
  import org.kuali.kra.protocol.actions.reviewcomments.ReviewCommentsService;
  import org.kuali.kra.protocol.actions.submit.ProtocolReviewer;
  import org.kuali.kra.protocol.actions.submit.ProtocolSubmissionBase;
  import org.kuali.kra.protocol.actions.submit.ProtocolSubmitAction;
  import org.kuali.kra.protocol.actions.submit.ValidProtocolActionActionBase;
  import org.kuali.kra.protocol.actions.undo.UndoLastActionBean;
  import org.kuali.kra.protocol.actions.withdraw.ProtocolAdministrativelyIncompleteBean;
  import org.kuali.kra.protocol.actions.withdraw.ProtocolAdministrativelyWithdrawBean;
  import org.kuali.kra.protocol.actions.withdraw.ProtocolWithdrawBean;
  import org.kuali.kra.protocol.auth.ProtocolTaskBase;
  import org.kuali.kra.protocol.correspondence.ProtocolCorrespondence;
  import org.kuali.kra.protocol.correspondence.ProtocolCorrespondenceAuthorizationService;
  import org.kuali.kra.protocol.onlinereview.ProtocolOnlineReviewBase;
  import org.kuali.kra.protocol.onlinereview.ProtocolReviewAttachmentBase;
  import org.kuali.kra.protocol.questionnaire.ProtocolModuleQuestionnaireBeanBase;
  import org.kuali.kra.protocol.questionnaire.ProtocolSubmissionQuestionnaireHelper;
  import org.kuali.kra.protocol.summary.ProtocolSummary;
  import org.kuali.coeus.common.questionnaire.framework.answer.AnswerHeader;
  import org.kuali.coeus.common.questionnaire.framework.answer.ModuleQuestionnaireBean;
  import org.kuali.coeus.common.questionnaire.framework.answer.QuestionnaireAnswerService;
  import org.kuali.rice.core.api.util.ConcreteKeyValue;
  import org.kuali.rice.core.api.util.KeyValue;
  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
  import org.kuali.rice.ken.util.NotificationConstants;
  import org.kuali.rice.kew.api.KewApiConstants;
  import org.kuali.rice.kew.api.WorkflowDocument;
  import org.kuali.rice.kew.api.document.DocumentStatus;
  import org.kuali.rice.krad.bo.DocumentHeader;
  import org.kuali.rice.krad.service.BusinessObjectService;
  import org.kuali.rice.krad.service.DocumentService;
  import org.kuali.rice.krad.util.GlobalVariables;
  import org.kuali.rice.krad.util.ObjectUtils;
  
  /**
   * The form helper class for the ProtocolBase Actions tab.
   */
  @SuppressWarnings("serial")
  public abstract class ActionHelperBase implements Serializable {
  
      protected static final String NAMESPACE = "KC-UNT";
      protected transient QuestionnaireAnswerService questionnaireAnswerService;
  
      private static final String DEFAULT_TAB = "Versions";
      private static final String ALTERNATE_OPEN_TAB = "Parameters";
      
      /**
       * Each Helper must contain a reference to its document form
       * so that it can access the document.
       */
      protected ProtocolFormBase form;
      
      protected boolean canSubmitProtocol = false;
      protected boolean canSubmitProtocolUnavailable = false;
      protected String submissionConstraint;
      
      protected boolean canReturnToPI = false;
      protected boolean canReturnToPIUnavailable = false;
      protected boolean canCreateAmendment = false;
      protected boolean canCreateAmendmentUnavailable = false;
      protected boolean canModifyAmendmentSections = false;
      protected boolean canModifyAmendmentSectionsUnavailable = false;
      protected boolean canCreateRenewal = false;
      protected boolean canCreateRenewalUnavailable = false;
      protected boolean canNotifyCommittee = false;
      protected boolean canNotifyCommitteeUnavailable = false;
      protected boolean canWithdraw = false;
      protected boolean canWithdrawUnavailable = false;
      protected boolean canRequestClose = false;
      protected boolean canRequestCloseUnavailable = false;
      protected boolean canRequestSuspension = false;
      protected boolean canRequestSuspensionUnavailable = false;
      protected boolean canRequestTerminate = false;
      protected boolean canRequestTerminateUnavailable = false;
      protected boolean canWithdrawSubmission = false;
      protected boolean canWithdrawSubmissionUnavailable = false;
      protected boolean canDeleteProtocolAmendRenew = false;
      protected boolean canDeleteProtocolAmendRenewUnavailable = false;
      protected boolean canAssignToAgenda = false;
      protected boolean canAssignToAgendaUnavailable = false;
      protected boolean canAssignCmtSched = false;
      protected boolean canAssignCmtSchedUnavailable = false;
      protected boolean canAssignReviewers = false;
      protected boolean canAssignReviewersCmtSel = false;
      protected boolean canAssignReviewersUnavailable = false;
      protected boolean canApproveFull = false;
      protected boolean canApproveFullUnavailable = false;
      protected boolean canApproveResponse = false;
      protected boolean canApproveResponseUnavailable = false;
      protected boolean canDisapprove = false;
      protected boolean canDisapproveUnavailable = false;
      protected boolean canReturnForSMR = false;
      protected boolean canReturnForSMRUnavailable = false;
      protected boolean canReturnForSRR = false;
      protected boolean canReturnForSRRUnavailable = false;
      protected boolean canSuspend = false;
      protected boolean canSuspendUnavailable = false;
      protected boolean canClose = false;
      protected boolean canCloseUnavailable = false;
      protected boolean canExpire = false;
      protected boolean canExpireUnavailable = false;
      protected boolean canTerminate = false;
      protected boolean canTerminateUnavailable = false;
      protected boolean canMakeAdminCorrection = false;
      protected boolean canMakeAdminCorrectionUnavailable = false;
      protected boolean canRecordCommitteeDecision = false;
      protected boolean canRecordCommitteeDecisionUnavailable = false;
      protected boolean canUndoLastAction = false;
      protected boolean canUndoLastActionUnavailable = false;
      protected boolean canModifyProtocolSubmission = false;
      protected boolean canModifyProtocolSubmissionUnavailable = false;
      protected boolean canManageReviewComments = false;
      protected boolean canManageReviewCommentsUnavailable = false;
      protected boolean canApproveOther = false;
      protected boolean canManageNotes = false;
      protected boolean canManageNotesUnavailable = false;
      protected boolean canAbandon = false;
  
      protected List<? extends ValidProtocolActionActionBase> followupActionActions;
      
      protected boolean canViewOnlineReviewers;
      protected boolean canViewOnlineReviewerComments;
      
      protected boolean canAddCloseReviewerComments;
  
      protected boolean canAddSuspendReviewerComments;
      protected boolean canAddTerminateReviewerComments;    
      
      // authorization flags for protocol correspondences
      protected boolean allowedToViewProtocolCorrespondence;
      protected boolean allowedToUpdateProtocolCorrespondence;
      protected boolean allowedToRegenerateProtocolCorrespondence;
      
      // new addition that needs to be backfitted to IRB as well
      private boolean canPerformAdminDetermination;
      private boolean canPerformAdminDeterminationUnavailable;
      private boolean canAdministrativelyApprove;
      private boolean canAdministrativelyApproveUnavailable;
      private boolean canAdministrativelyMarkIncomplete;
      private boolean canAdministrativelyMarkIncompleteUnavailable;
      private boolean canAdministrativelyWithdraw;
      private boolean canAdministrativelyWithdrawUnavailable;
      
      
      
      protected ProtocolSubmitAction protocolSubmitAction;    
      protected List<KeyValue> submitActionCommitteeIdByUnitKeyValues;
  
      protected ProtocolWithdrawBean protocolWithdrawBean;
      protected ProtocolRequestBean protocolCloseRequestBean;
      protected ProtocolRequestBean protocolSuspendRequestBean;    
      protected ProtocolRequestBean protocolTerminateRequestBean;
      
      protected ProtocolRequestBean protocolWithdrawCloseRequestBean;
      protected ProtocolRequestBean protocolWithdrawSuspendRequestBean;    
      protected ProtocolRequestBean protocolWithdrawTerminateRequestBean;
      
      protected ProtocolNotifyCommitteeBean protocolNotifyCommitteeBean;
      private List<KeyValue> notifyCmtActionCommitteeIdByUnitKeyValues;
      
      protected ProtocolAmendmentBean protocolAmendmentBean;
      protected ProtocolAmendmentBean protocolRenewAmendmentBean;
      protected ProtocolAmendmentBean protocolAmendmentSummaryBean;
      protected ProtocolDeleteBean protocolDeleteBean;
      protected ProtocolAssignToAgendaBean assignToAgendaBean;   
      private ProtocolApproveBean protocolFullApprovalBean;
      
      private ProtocolApproveBean protocolAdminApprovalBean;
      private ProtocolAdministrativelyWithdrawBean protocolAdminWithdrawBean;
      private ProtocolAdministrativelyIncompleteBean protocolAdminIncompleteBean;
      
      protected ProtocolGenericActionBean protocolDisapproveBean;
      protected ProtocolGenericActionBean protocolSMRBean;
      protected ProtocolGenericActionBean protocolSRRBean;
      
      protected ProtocolGenericActionBean protocolSuspendBean;    
      protected ProtocolGenericActionBean protocolCloseBean;
      protected ProtocolGenericActionBean protocolExpireBean;
      protected ProtocolGenericActionBean protocolTerminateBean;
      
      protected ProtocolGenericActionBean protocolReturnToPIBean;
      protected AdminCorrectionBean protocolAdminCorrectionBean;
      protected UndoLastActionBean undoLastActionBean;
      protected CommitteeDecision<?> committeeDecision;
      protected ProtocolGenericActionBean protocolManageReviewCommentsBean;
      protected ProtocolGenericActionBean protocolAbandonBean;
  
      protected String currentTaskName = "";
      protected boolean prevDisabled;
      protected boolean nextDisabled;
      protected transient ParameterService parameterService;
      protected transient TaskAuthorizationService taskAuthorizationService;
      protected transient ProtocolAmendRenewService protocolAmendRenewService;
      protected transient ProtocolVersionService protocolVersionService;
      protected boolean hasAmendments;
      protected boolean hasRenewals;
      protected boolean submissionHasNoAmendmentDetails;
      protected Boolean summaryReport;
      protected Boolean fullReport;
      protected Boolean historyReport;
      protected Boolean reviewCommentsReport;
      
      protected ProtocolSummary protocolSummary;
      protected ProtocolSummary prevProtocolSummary;
      protected int currentSequenceNumber = -1;
      
      protected String selectedHistoryItem;
      protected Date filteredHistoryStartDate;
      protected Date filteredHistoryEndDate;
      
      // additional properties for Submission Details
      protected List<CommitteeScheduleMinuteBase> reviewComments;        
      protected List<? extends ProtocolReviewAttachmentBase> reviewAttachments;        
      protected List<ProtocolVoteAbstaineeBase> abstainees;        
      protected List<ProtocolVoteRecusedBase> recusers;
      
      // the reviewers for the currently selected submission
      protected List<ProtocolReviewer> currentReviewers = new ArrayList<ProtocolReviewer>();
      // mapping for current online reviews keyed by the current reviewer id
      private HashMap<String, ProtocolOnlineReviewBase> onlineReviewsMap = new HashMap<String, ProtocolOnlineReviewBase>(); 
      
      protected int currentSubmissionNumber;
      protected String renewalSummary;
  
      @SuppressWarnings("rawtypes")
      protected transient CommitteeScheduleServiceBase committeeScheduleService;
      protected transient KcPersonService kcPersonService;
      protected transient SystemAuthorizationService systemAuthorizationService;
      protected transient BusinessObjectService businessObjectService;
      protected transient FollowupActionService<?> followupActionService;
          
      protected Map<String,Boolean> followupActionMap = new HashMap<String,Boolean>();
      
      protected Map<String, ProtocolActionBean> actionBeanTaskMap = new HashMap<String, ProtocolActionBean>();    
      // protocol print
      protected ProtocolSummaryPrintOptions protocolSummaryPrintOptions;
      // TODO ProtocolSummaryPrintOptions should be refactored into IRB and IACUC subclasses and the below constructor should be replaced with a hook invocation.
      protected ProtocolSummaryPrintOptions protocolPrintOption = new ProtocolSummaryPrintOptions();
      protected List<QuestionnairePrintOption> questionnairesToPrints;
      protected List<CorrespondencePrintOption> correspondencesToPrint;
      
      // flag if versioned protocol questionnaire exist
      protected boolean summaryQuestionnaireExist;
      protected boolean hideReviewerName;
      protected boolean hideSubmissionReviewerName;
      protected boolean hideReviewerNameForAttachment;
      //flag to hide private final columns/attachments from PI when they are public
      protected boolean hidePrivateFinalFlagsForPublicCommentsAttachments; 
      protected ProtocolCorrespondence protocolCorrespondence;
      
      // indicator for whether there is submission questionnaire answer exist.
      // ie, questionnaire has been saved for a request/notify irb action
      protected boolean submissionQuestionnaireExist;
      // check if there is submission questionnaire to answer
      protected boolean toAnswerSubmissionQuestionnaire;
      protected ProtocolSubmissionQuestionnaireHelper protocolSubmissionQuestionnaireHelper;
  
      /**
       * Constructs an ActionHelperBase.
       * @param form the protocol form
       * @throws Exception 
       */
      public ActionHelperBase(ProtocolFormBase form) throws Exception {
          this.form = form;
      }
      
      
      public void initializeProtocolActions() throws Exception {
          protocolSubmitAction = getNewProtocolSubmitActionInstanceHook(this);
          protocolWithdrawBean = getNewProtocolWithdrawBeanInstanceHook(this);
  
          createAmendmentBean();
          
          protocolNotifyCommitteeBean = getNewProtocolNotifyCommitteeBeanInstanceHook(this);
  
                  
          protocolDeleteBean = getNewProtocolDeleteBeanInstanceHook(this);      
          assignToAgendaBean = getNewProtocolAssignToAgendaBeanInstanceHook(this);         
          assignToAgendaBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());        
          protocolFullApprovalBean = buildProtocolApproveBean(getFullApprovalProtocolActionTypeHook(), Constants.PROTOCOL_FULL_APPROVAL_ACTION_PROPERTY_KEY);
  
          protocolAdminApprovalBean = buildProtocolApproveBean(getAdminApprovalProtocolActionTypeHook(), Constants.PROTOCOL_ADMIN_APPROVAL_ACTION_PROPERTY_KEY);
          protocolAdminWithdrawBean = getNewProtocolAdminWithdrawBeanInstanceHook(this);
          protocolAdminIncompleteBean = getNewProtocolAdminIncompleteBeanInstanceHook(this);
           
          protocolDisapproveBean = buildProtocolGenericActionBean(getDisapprovedProtocolActionTypeHook(), Constants.PROTOCOL_DISAPPROVE_ACTION_PROPERTY_KEY);
          protocolSMRBean = buildProtocolGenericActionBean(getSMRProtocolActionTypeHook(), Constants.PROTOCOL_SMR_ACTION_PROPERTY_KEY);  
          protocolSRRBean = buildProtocolGenericActionBean(getSRRProtocolActionTypeHook(), Constants.PROTOCOL_SRR_ACTION_PROPERTY_KEY);
          protocolReturnToPIBean = buildProtocolGenericActionBean(getReturnToPIActionTypeHook(), Constants.PROTOCOL_RETURN_TO_PI_PROPERTY_KEY);
          protocolSuspendBean = buildProtocolGenericActionBean(getSuspendKeyHook(), Constants.PROTOCOL_SUSPEND_ACTION_PROPERTY_KEY);
          protocolExpireBean = buildProtocolGenericActionBean(getExpireKeyHook(), Constants.PROTOCOL_EXPIRE_ACTION_PROPERTY_KEY);
          protocolTerminateBean = buildProtocolGenericActionBean(getTerminateKeyHook(), Constants.PROTOCOL_TERMINATE_ACTION_PROPERTY_KEY);        
          protocolAbandonBean = buildProtocolGenericActionBean(getAbandonActionTypeHook(), getAbandonPropertyKeyHook());
          
            
          protocolAdminCorrectionBean = createAdminCorrectionBean();
          undoLastActionBean = getNewUndoLastActionBeanInstanceHook();
          
          committeeDecision = getNewCommitteeDecisionInstanceHook(this);
          committeeDecision.init();
          committeeDecision.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
  
          protocolManageReviewCommentsBean = buildProtocolGenericActionBean(getProtocolActionTypeCodeForManageReviewCommentsHook(), 
                  Constants.PROTOCOL_MANAGE_REVIEW_COMMENTS_KEY);
          getProtocol().getProtocolSubmission().refreshReferenceObject("reviewAttachments");
          protocolManageReviewCommentsBean.getReviewAttachmentsBean().setReviewAttachments(getProtocol().getProtocolSubmission().getReviewAttachments());
          if (CollectionUtils.isNotEmpty(protocolManageReviewCommentsBean.getReviewAttachmentsBean().getReviewAttachments())) {
              protocolManageReviewCommentsBean.getReviewAttachmentsBean().setHideReviewerName(getReviewerCommentsService().setHideReviewerName(protocolManageReviewCommentsBean.getReviewAttachmentsBean().getReviewAttachments()));
          }
          
          initActionBeanTaskMap();        
      }
      
  
      protected abstract String getSRRProtocolActionTypeHook();
  
      protected abstract String getSMRProtocolActionTypeHook();
      
      protected abstract String getReturnToPIActionTypeHook();
  
      protected abstract String getDisapprovedProtocolActionTypeHook();
  
      protected abstract String getProtocolActionTypeCodeForManageReviewCommentsHook();    
      
      protected abstract CommitteeDecision<?> getNewCommitteeDecisionInstanceHook(ActionHelperBase actionHelper);    
  
      protected abstract ProtocolAssignToAgendaBean getNewProtocolAssignToAgendaBeanInstanceHook(ActionHelperBase actionHelper);
  
      protected abstract ProtocolAdministrativelyWithdrawBean getNewProtocolAdminWithdrawBeanInstanceHook(ActionHelperBase actionHelper);
      
      protected abstract ProtocolAdministrativelyIncompleteBean getNewProtocolAdminIncompleteBeanInstanceHook(ActionHelperBase actionHelper);
      
      protected abstract String getAdminApprovalProtocolActionTypeHook();
      
      protected abstract String getFullApprovalProtocolActionTypeHook();
  
      protected abstract ProtocolWithdrawBean getNewProtocolWithdrawBeanInstanceHook(ActionHelperBase actionHelper);
  
      protected abstract ProtocolAmendmentBean getNewProtocolAmendmentBeanInstanceHook(ActionHelperBase actionHelper);
      
      protected abstract ProtocolNotifyCommitteeBean getNewProtocolNotifyCommitteeBeanInstanceHook(ActionHelperBase actionHelper);
  
      protected abstract ProtocolSubmitAction getNewProtocolSubmitActionInstanceHook(ActionHelperBase actionHelper);
      
      protected abstract ProtocolDeleteBean getNewProtocolDeleteBeanInstanceHook(ActionHelperBase actionHelper);
  
      protected abstract AdminCorrectionBean getNewAdminCorrectionBeanInstanceHook(ActionHelperBase actionHelper);
      
      protected abstract UndoLastActionBean getNewUndoLastActionBeanInstanceHook();
  
      /**
       * Initializes the mapping between the task names and the beans.  This is used to get the bean associated to the task name passed in from the tag file.
       * The reason TaskName (a text code) is used and ProtocolActionType (a number code) is not is because not every task is mapped to a ProtocolActionType.
       */
      protected void initActionBeanTaskMap() {
          
          actionBeanTaskMap.put(TaskName.PROTOCOL_ADMIN_CORRECTION, protocolAdminCorrectionBean);
          actionBeanTaskMap.put(TaskName.CREATE_PROTOCOL_AMMENDMENT, protocolAmendmentBean);
          actionBeanTaskMap.put(TaskName.CREATE_PROTOCOL_RENEWAL, protocolRenewAmendmentBean);
          
          actionBeanTaskMap.put(TaskName.APPROVE_PROTOCOL, protocolFullApprovalBean);        
          actionBeanTaskMap.put(TaskName.ASSIGN_TO_AGENDA, assignToAgendaBean);
          actionBeanTaskMap.put(TaskName.RECORD_COMMITTEE_DECISION, committeeDecision);
          actionBeanTaskMap.put(TaskName.PROTOCOL_AMEND_RENEW_DELETE, protocolDeleteBean);
          actionBeanTaskMap.put(TaskName.DISAPPROVE_PROTOCOL, protocolDisapproveBean);
          actionBeanTaskMap.put(TaskName.EXPIRE_PROTOCOL, protocolExpireBean);
          actionBeanTaskMap.put(TaskName.PROTOCOL_MANAGE_REVIEW_COMMENTS, protocolManageReviewCommentsBean);
          actionBeanTaskMap.put(TaskName.RETURN_FOR_SMR, protocolSMRBean);
          actionBeanTaskMap.put(TaskName.RETURN_FOR_SRR, protocolSRRBean);
          actionBeanTaskMap.put(TaskName.RETURN_TO_PI_PROTOCOL, protocolReturnToPIBean);
           
          actionBeanTaskMap.put(TaskName.SUBMIT_PROTOCOL, protocolSubmitAction);
          actionBeanTaskMap.put(TaskName.NOTIFY_COMMITTEE, protocolNotifyCommitteeBean);
          actionBeanTaskMap.put(TaskName.SUSPEND_PROTOCOL, protocolSuspendBean);
          actionBeanTaskMap.put(TaskName.TERMINATE_PROTOCOL, protocolTerminateBean);
          actionBeanTaskMap.put(TaskName.PROTOCOL_UNDO_LAST_ACTION, undoLastActionBean);
          
          actionBeanTaskMap.put(TaskName.PROTOCOL_WITHDRAW, protocolWithdrawBean);
          
          actionBeanTaskMap.put(TaskName.ADMIN_APPROVE_PROTOCOL, protocolAdminApprovalBean);
          actionBeanTaskMap.put(TaskName.ADMIN_WITHDRAW_PROTOCOL, protocolAdminWithdrawBean);
          actionBeanTaskMap.put(TaskName.ADMIN_INCOMPLETE_PROTOCOL, protocolAdminIncompleteBean);
      }
      
      
          protected abstract String getAbandonActionTypeHook();
          
          protected abstract String getAbandonPropertyKeyHook();
          
          protected abstract String getExpireKeyHook();
          
          protected abstract String getTerminateKeyHook();
          
          protected abstract String getSuspendKeyHook();
                 
          protected abstract ProtocolGenericActionBean buildProtocolGenericActionBean(String actionTypeCode, String errorPropertyKey);
          
          
          protected ReviewCommentsService getReviewCommentsService() {
              return KcServiceLocator.getService(getReviewCommentsServiceClassHook());
          }   
          
          protected abstract Class<? extends ReviewCommentsService> getReviewCommentsServiceClassHook();  
  
          
   
      protected ProtocolApproveBean buildProtocolApproveBean(String actionTypeCode, String errorPropertyKey) throws Exception {        
          ProtocolApproveBean bean = getNewProtocolApproveBeanInstanceHook(this, errorPropertyKey);       
          bean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
          
          ProtocolActionBase protocolAction = findProtocolAction(actionTypeCode, getProtocol().getProtocolActions(), getProtocol().getProtocolSubmission());
          if (protocolAction != null) {
              bean.setComments(protocolAction.getComments());
              bean.setActionDate(new Date(protocolAction.getActionDate().getTime()));
          }
          bean.setApprovalDate(buildApprovalDate(getProtocol()));
          bean.setExpirationDate(buildExpirationDate(getProtocol(), bean.getApprovalDate()));
          bean.setDefaultExpirationDateDifference(this.getDefaultExpirationDateDifference());
          return bean;
      }
  
          
      protected abstract ProtocolApproveBean getNewProtocolApproveBeanInstanceHook(ActionHelperBase actionHelper, String errorPropertyKey);
  
      /**
       * Builds an approval date, defaulting to the approval date from the protocol.
       * 
       * If the approval date from the protocol is null, or if the protocol is new or a renewal, then if the committee has scheduled a meeting to approve the 
       * protocol, sets to the scheduled approval date; otherwise, sets to the current date.
       * 
       * @param protocol
       * @return a non-null approval date
       */
      protected Date buildApprovalDate(ProtocolBase protocol) {
          Date approvalDate = protocol.getApprovalDate();
          
          if (approvalDate == null || protocol.isNew() || protocol.isRenewal()) {
              CommitteeScheduleBase committeeSchedule = protocol.getProtocolSubmission().getCommitteeSchedule();
              if (committeeSchedule != null) {
                  approvalDate = committeeSchedule.getScheduledDate();
              } else {
                  approvalDate = new Date(System.currentTimeMillis());
              }
          }
          
          return approvalDate;
      }
      
      /**
       * Builds an expiration date, defaulting to the expiration date from the protocol.  
       * 
       * If the expiration date from the protocol is null, or if the protocol is new or a renewal, creates an expiration date exactly one year ahead and one day 
       * less than the approval date.
       * 
       * @param protocol
       * @param approvalDate
       * @return a non-null expiration date
       */
      protected Date buildExpirationDate(ProtocolBase protocol, Date approvalDate) {
          Date expirationDate = protocol.getExpirationDate();
          
          if (expirationDate == null || protocol.isNew() || protocol.isRenewal()) {
              java.util.Date newExpirationDate = DateUtils.addYears(approvalDate, getDefaultExpirationDateDifference());
              newExpirationDate = DateUtils.addDays(newExpirationDate, -1);
              expirationDate = org.kuali.coeus.sys.framework.util.DateUtils.convertToSqlDate(newExpirationDate);
          }
          
          return expirationDate;
      }
  
      protected ProtocolActionBase findProtocolAction(String actionTypeCode, List<ProtocolActionBase> protocolActions, ProtocolSubmissionBase currentSubmission) {
  
          for (ProtocolActionBase pa : protocolActions) {
              if (pa.getProtocolActionType().getProtocolActionTypeCode().equals(actionTypeCode)
                      && (pa.getProtocolSubmission() == null || pa.getProtocolSubmission().equals(currentSubmission))) {
                  return pa;
              }
          }
          return null;
      }
  
      /**
       * This method is to reinitialize amendment beans, otherwise a second pass thru prepareView() will show same
       * amendment creation options as previous passes
       * @throws Exception
       */
      public void initAmendmentBeans(boolean forceReset) throws Exception {
        if (protocolAmendmentBean == null || forceReset) {
              protocolAmendmentBean = createAmendmentBean();
        }
        if (protocolRenewAmendmentBean == null || forceReset) {
              protocolRenewAmendmentBean = createAmendmentBean();
        }
      }
      
      protected ProtocolAmendmentBean createAmendmentBean() throws Exception {
          protocolAmendmentBean = getNewProtocolAmendmentBeanInstanceHook(this);
          protocolRenewAmendmentBean = getNewProtocolAmendmentBeanInstanceHook(this);
          protocolAmendmentSummaryBean = getNewProtocolAmendmentBeanInstanceHook(this);
          configureAmendmentBean(protocolAmendmentBean);
          configureAmendmentBean(protocolRenewAmendmentBean);
          configureAmendmentBean(protocolAmendmentSummaryBean);
          return protocolAmendmentBean;
      }
      
  
      /**
       * Create an Amendment Bean.  The modules that can be selected depends upon the
       * current outstanding amendments.  If a module is currently being modified by a
       * previous amendment, it cannot be modified by another amendment.  Once the 
       * previous amendment has completed (approved, disapproved, etc), then a new
       * amendment can modify the same module.
       * @return
       * @throws Exception 
       */
      protected ProtocolAmendmentBean configureAmendmentBean(ProtocolAmendmentBean amendmentBean) throws Exception {
          List<String> moduleTypeCodes;
  
          if (StringUtils.isNotEmpty(getProtocol().getProtocolNumber()) && (getProtocol().isAmendment() || getProtocol().isRenewal())) {
              moduleTypeCodes = getProtocolAmendRenewServiceHook().getAvailableModules(getProtocol().getAmendedProtocolNumber());
              populateExistingAmendmentBean(amendmentBean, moduleTypeCodes);
          } else {
              moduleTypeCodes = getProtocolAmendRenewServiceHook().getAvailableModules(getProtocol().getProtocolNumber());
          }
          
          for (String moduleTypeCode : moduleTypeCodes) {
              enableModuleOption(moduleTypeCode, amendmentBean);
          }
          
          return amendmentBean;
      }
  
      
  
  
      /**
       * Create an AdminCorrection Bean.  The modules that can be edited (or corrected) depends upon the
       * current outstanding amendments.  If a module is currently being modified by a
       * an amendment, it cannot be corrected through Administrative Correction.  
       * @return
       * @throws Exception 
       */
      private AdminCorrectionBean createAdminCorrectionBean() throws Exception {
          AdminCorrectionBean adminCorrectionBean = getNewAdminCorrectionBeanInstanceHook(this); 
          List<String> moduleTypeCodes = getProtocolAmendRenewServiceHook().getAvailableModules(getProtocol().getProtocolNumber());
          
          for (String moduleTypeCode : moduleTypeCodes) {
              enableModuleOption(moduleTypeCode, adminCorrectionBean);
          }
          
          return adminCorrectionBean;
      }    
  
      public void prepareView() throws Exception {
          initializeSubmissionConstraintHook();
          prepareProtocolSubmitActionView();
          prepareNotifyCommitteeActionView();
                    
          assignToAgendaBean.prepareView();        
          canCreateAmendment = hasCreateAmendmentPermission();
          canCreateAmendmentUnavailable = hasCreateAmendmentUnavailablePermission();
          canModifyAmendmentSections = hasModifyAmendmentSectionsPermission();
          canModifyAmendmentSectionsUnavailable = hasModifyAmendmentSectionsUnavailablePermission();
          canCreateRenewal = hasCreateRenewalPermission();
          canCreateRenewalUnavailable = hasCreateRenewalUnavailablePermission();
          canWithdraw = hasWithdrawPermission();            
          canWithdrawUnavailable = hasWithdrawUnavailablePermission();
          canDeleteProtocolAmendRenew = hasDeleteProtocolAmendRenewPermission();
          canDeleteProtocolAmendRenewUnavailable = hasDeleteProtocolAmendRenewUnavailablePermission();
                 
          canAssignToAgenda = hasAssignToAgendaPermission();
          canAssignToAgendaUnavailable = hasAssignToAgendaUnavailablePermission();
          canApproveFull = hasFullApprovePermission();
          canApproveFullUnavailable = hasFullApproveUnavailablePermission();
          canDisapprove = hasDisapprovePermission();
          canDisapproveUnavailable = hasDisapproveUnavailablePermission();
          
          canApproveOther = hasApproveOtherPermission();
                  
          canReturnForSMR = hasReturnForSMRPermission();
          canReturnForSMRUnavailable = hasReturnForSMRUnavailablePermission();
          canReturnForSRR = hasReturnForSRRPermission();
          canReturnForSRRUnavailable = hasReturnForSRRUnavailablePermission();
          canSuspend = hasSuspendPermission();
          canSuspendUnavailable = hasSuspendUnavailablePermission();
          canExpire = hasExpirePermission();
          canExpireUnavailable = hasExpireUnavailablePermission();
          canTerminate = hasTerminatePermission();
          canTerminateUnavailable = hasTerminateUnavailablePermission();
  
          canMakeAdminCorrection = hasAdminCorrectionPermission();
          canMakeAdminCorrectionUnavailable = hasAdminCorrectionUnavailablePermission();
          
          canAdministrativelyApprove = hasAdministrativelyApprovePermission();
          canAdministrativelyApproveUnavailable = hasAdministrativelyApproveUnavailablePermission();
          canAdministrativelyWithdraw = hasAdministrativelyWithdrawPermission();
          canAdministrativelyWithdrawUnavailable = hasAdministrativelyWithdrawUnavailablePermission();
          canAdministrativelyMarkIncomplete = hasAdministrativelyMarkIncompletePermission();
          canAdministrativelyMarkIncompleteUnavailable = hasAdministrativelyMarkIncompleteUnavailablePermission();
          
   
          canRecordCommitteeDecision = hasRecordCommitteeDecisionPermission();
          canRecordCommitteeDecisionUnavailable = hasRecordCommitteeDecisionUnavailablePermission();
          canUndoLastAction = hasUndoLastActionPermission();
          canUndoLastActionUnavailable = hasUndoLastActionUnavailablePermission();
          canModifyProtocolSubmission = hasCanModifySubmissionPermission();
          canModifyProtocolSubmissionUnavailable = hasCanModifySubmissionUnavailablePermission();
          canManageReviewComments = hasManageReviewCommentsPermission();
          canManageReviewCommentsUnavailable = hasManageReviewCommentsUnavailablePermission();
          canAbandon = hasAbandonProtocolPermission();
          
          followupActionActions = getFollowupActionService().getFollowupsForProtocol(form.getProtocolDocument().getProtocol());
  
          
          canViewOnlineReviewers = hasCanViewOnlineReviewersPermission();
          canViewOnlineReviewerComments = hasCanViewOnlineReviewerCommentsPermission();        
          canAddSuspendReviewerComments = hasSuspendPermission();
          canAddTerminateReviewerComments = hasTerminatePermission();
          
          initProtocolCorrespondenceAuthorizationFlags();
          
          hidePrivateFinalFlagsForPublicCommentsAttachments = checkToHidePrivateFinalFlagsForPublicCommentsAttachments();
          initSubmissionDetails();
          
          initAmendmentBeans(false);
          initPrintQuestionnaire();
          initPrintCorrespondence();
      }
      
              
      protected abstract void initializeSubmissionConstraintHook();
  
      
      protected List<KeyValue> getKeyValuesForCommitteeSelection(Collection<? extends CommitteeBase<?, ?, ?>> committees) {
          List<KeyValue> retVal = new ArrayList<KeyValue>();
          for(CommitteeBase<?, ?, ?> committee : committees) {
              retVal.add(new ConcreteKeyValue(committee.getCommitteeId(), committee.getCommitteeName()));
          }
          Collections.sort(retVal, new KeyValueComparator());
          retVal.add(0, new ConcreteKeyValue(PrefixValuesFinder.getPrefixKey(), PrefixValuesFinder.getDefaultPrefixValue()));
          return retVal;
      }
  
  
      private void prepareProtocolSubmitActionView() {        
          canSubmitProtocol = hasSubmitProtocolPermission();
          canSubmitProtocolUnavailable = hasSubmitProtocolUnavailablePermission();
          if(protocolSubmitAction == null) {
          	protocolSubmitAction = getNewProtocolSubmitActionInstanceHook(this);
          }
          protocolSubmitAction.prepareView();
          // Initialize the submit committee key values (expensive call) only after checking the conditions for the display of the committee selection
          if(canSubmitProtocol && isShowCommittee()) {            
              // pass in the lead unit of the protocol and the doc route status to the committee finder service
              Collection<? extends CommitteeBase<?, ?, ?>> committees = 
                  getCommitteeIdByUnitValuesFinderService().getAssignmentCommittees(getProtocol().getLeadUnitNumber(), getDocRouteStatus(), null);
              submitActionCommitteeIdByUnitKeyValues = getKeyValuesForCommitteeSelection(committees);
          }
      }
      
      protected boolean hasSubmitProtocolUnavailablePermission() {
          ProtocolTaskBase task = getNewSubmitProtocolUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
        
  
      private void prepareNotifyCommitteeActionView() {
          protocolNotifyCommitteeBean.prepareView();
          canNotifyCommittee = hasNotifyCommitteePermission();
          canNotifyCommitteeUnavailable = hasNotifyCommitteeUnavailablePermission();
          // Initialize the notify cmt key values only after checking the conditions for the display of the committee selection
          if(canNotifyCommittee && isShowCommittee()) {            
              // pass in the current committee id and the doc route status to the committee finder service
              Collection<? extends CommitteeBase<?, ?, ?>> committees = 
                  getCommitteeIdByUnitValuesFinderService().getAssignmentCommittees(null, getDocRouteStatus(), protocolNotifyCommitteeBean.getCommitteeId());
              notifyCmtActionCommitteeIdByUnitKeyValues = getKeyValuesForCommitteeSelection(committees);
          }
      }
         
      protected boolean hasNotifyCommitteePermission() {
          ProtocolTaskBase task = getNewNotifyCommitteeTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase getNewNotifyCommitteeTaskInstanceHook(ProtocolBase protocol);
  
      
      private boolean hasNotifyCommitteeUnavailablePermission() {
          ProtocolTaskBase task = getNewNotifyCommitteeUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase getNewNotifyCommitteeUnavailableTaskInstanceHook(ProtocolBase protocol);
      
  
      protected String getDocRouteStatus() {
          String retVal = "";
          DocumentHeader docHeader = form.getProtocolDocument().getDocumentHeader(); 
          if( docHeader != null) {
              WorkflowDocument workflowDoc = docHeader.getWorkflowDocument();
              if(workflowDoc != null) {
                  DocumentStatus docStatus = workflowDoc.getStatus();
                  if(docStatus != null) {
                      retVal = docStatus.getCode();
                  }
              }
          }
          return retVal;
      }
  
  
      protected abstract boolean hasApproveOtherPermission();
  
  
      @SuppressWarnings("unchecked")
      protected void populateReviewersAndOnlineReviewsMap() {
          String protocolNum = getProtocol().getProtocolNumber();
          // populate the current submission's reviewers
          this.currentReviewers = getReviewerCommentsService().getProtocolReviewers(protocolNum, currentSubmissionNumber);
          // populate the online reviews map
          List<ProtocolOnlineReviewBase> activeReviews = getReviewerCommentsService().getProtocolOnlineReviews(protocolNum, currentSubmissionNumber);
          for (ProtocolOnlineReviewBase review : activeReviews) {
              this.getOnlineReviewsMap().put(review.getProtocolReviewer().getProtocolReviewerId().toString(), review);
          }
      }
  
      private boolean hasAdministrativelyApprovePermission() {
          ProtocolTaskBase task = getNewAdminApproveProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase getNewAdminApproveProtocolTaskInstanceHook(ProtocolBase protocol);
      
      private boolean hasAdministrativelyApproveUnavailablePermission() {
          ProtocolTaskBase task = getNewAdminApproveUnavailableProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
  
      protected abstract ProtocolTaskBase getNewAdminApproveUnavailableProtocolTaskInstanceHook(ProtocolBase protocol);
      
      
      protected boolean hasExpirePermission() {
          ProtocolTaskBase task = getExpireTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      protected abstract ProtocolTaskBase getExpireTaskInstanceHook(ProtocolBase protocol);
      
      protected boolean hasExpireUnavailablePermission() {
          ProtocolTaskBase task = getExpireUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      protected abstract ProtocolTaskBase getExpireUnavailableTaskInstanceHook(ProtocolBase protocol);
      
      private boolean hasAdministrativelyWithdrawPermission() {
          ProtocolTaskBase task = getNewAdminWithdrawProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
  
      protected abstract ProtocolTaskBase getNewAdminWithdrawProtocolTaskInstanceHook(ProtocolBase protocol);
      
      private boolean hasAdministrativelyWithdrawUnavailablePermission() {
          ProtocolTaskBase task = getNewAdminWithdrawUnavailableProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
  
      protected abstract ProtocolTaskBase getNewAdminWithdrawUnavailableProtocolTaskInstanceHook(ProtocolBase protocol);
      
      
      
      
      private boolean hasAdministrativelyMarkIncompletePermission() {
          ProtocolTaskBase task = getNewAdminMarkIncompleteProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
  
      protected abstract ProtocolTaskBase getNewAdminMarkIncompleteProtocolTaskInstanceHook(ProtocolBase protocol);
      
      private boolean hasAdministrativelyMarkIncompleteUnavailablePermission() {
          ProtocolTaskBase task = getNewAdminMarkIncompleteUnavailableProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
  
      protected abstract ProtocolTaskBase getNewAdminMarkIncompleteUnavailableProtocolTaskInstanceHook(ProtocolBase protocol);
      
      
      
     protected void initProtocolCorrespondenceAuthorizationFlags() {
         ProtocolCorrespondenceAuthorizationService correspondenceAuthorizationService = getProtocolCorrespondenceAuthorizationService(); 
         this.allowedToViewProtocolCorrespondence = correspondenceAuthorizationService.isAllowedToViewProtocolCorrespondence(getProtocol());
         this.allowedToUpdateProtocolCorrespondence = correspondenceAuthorizationService.isAllowedToUpdateProtocolCorrespondence(getProtocol());
         this.allowedToRegenerateProtocolCorrespondence = correspondenceAuthorizationService.isAllowedToRegenerateProtocolCorrespondence(getProtocol());
     }
  
      /**
       * Refreshes the comments for all the beans from the database.  Use sparingly since this will erase non-persisted comments.
       */
      @SuppressWarnings("unchecked")
      public void prepareCommentsView() {
          
          protocolAdminApprovalBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
               
          assignToAgendaBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
          
          protocolFullApprovalBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
          
          protocolDisapproveBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());         
          protocolSMRBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
          protocolSRRBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
          protocolSuspendBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
          protocolExpireBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
          protocolTerminateBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
          committeeDecision.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());        
          protocolManageReviewCommentsBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
          getProtocol().getProtocolSubmission().refreshReferenceObject("reviewAttachments");
          protocolManageReviewCommentsBean.getReviewAttachmentsBean().setReviewAttachments(getProtocol().getProtocolSubmission().getReviewAttachments());
          if (CollectionUtils.isNotEmpty(protocolManageReviewCommentsBean.getReviewAttachmentsBean().getReviewAttachments())) {
              protocolManageReviewCommentsBean.getReviewAttachmentsBean().setHideReviewerName(getReviewerCommentsService().setHideReviewerName(protocolManageReviewCommentsBean.getReviewAttachmentsBean().getReviewAttachments()));
          }
          
          protocolReturnToPIBean.getReviewCommentsBean().setReviewComments(getCopiedReviewComments());
      }
      
      @SuppressWarnings({ "rawtypes" })
      protected List<CommitteeScheduleMinuteBase> getCopiedReviewComments() {
          List<CommitteeScheduleMinuteBase> minutes = getReviewCommentsUsingScheduleOrSubmission();
          return cloneReviewComments(minutes);        
      }
      
      @SuppressWarnings({ "unchecked", "rawtypes" })
      protected List<CommitteeScheduleMinuteBase> getReviewCommentsUsingScheduleOrSubmission() {
          List<CommitteeScheduleMinuteBase> minutes;
          Long scheduleIdFk = getProtocol().getProtocolSubmission().getScheduleIdFk();
          // if the schedule has not yet been selected, then use the review comment service to get the reviews, 
          if(scheduleIdFk == null) {
              minutes = getReviewerCommentsService().getReviewerComments(getProtocol().getProtocolNumber(), currentSubmissionNumber);
              // sort the minutes by entry number, so that all review comments beans show the same ordered listing
              Collections.sort(minutes, new Comparator<CommitteeScheduleMinuteBase>() {
  
                  @Override
                  public int compare(CommitteeScheduleMinuteBase csm1, CommitteeScheduleMinuteBase csm2) {
                      int retVal = 0;
                      if( (csm1 != null) && (csm2 != null) && (csm1.getEntryNumber() != null) && (csm2.getEntryNumber() != null) ) {
                          retVal = csm1.getEntryNumber().compareTo(csm2.getEntryNumber());
                      }
                      return retVal;
                  }
                  
              });
          }
          // otherwise just use the committeesSchedule service to get the reviews for the selected schedule
          else {
              minutes = getCommitteeScheduleService().getMinutesBySchedule(scheduleIdFk);
          }
          return minutes;
      }
      
      @SuppressWarnings("rawtypes")
      protected List<CommitteeScheduleMinuteBase> cloneReviewComments(List<CommitteeScheduleMinuteBase> minutes) {
          List<CommitteeScheduleMinuteBase> clonedMinutes = new ArrayList<CommitteeScheduleMinuteBase>();
          if (CollectionUtils.isNotEmpty(minutes)) {
              for (CommitteeScheduleMinuteBase minute : minutes) {
                  clonedMinutes.add(minute.getCopy());
              }
          }        
          return clonedMinutes;
      }
      
         
      @SuppressWarnings("rawtypes")
      private CommitteeScheduleServiceBase getCommitteeScheduleService() {
          if (committeeScheduleService == null) {
              committeeScheduleService = KcServiceLocator.getService(getCommitteeScheduleServiceClassHook());
          }
          return committeeScheduleService;
      }
      
      
      @SuppressWarnings("rawtypes")
      protected abstract Class<? extends CommitteeScheduleServiceBase> getCommitteeScheduleServiceClassHook();
  
  
      protected abstract ProtocolVersionService getProtocolVersionService();
      
      protected String getParameterValue(String parameterName) {        
          return this.getParameterService().getParameterValueAsString(getProtocolDocumentBOClassHook(), parameterName);      
      }
      
      protected abstract Class<? extends ProtocolDocumentBase> getProtocolDocumentBOClassHook();
    
    
      protected boolean hasSubmitProtocolPermission() {
          ProtocolTaskBase task = getNewSubmitProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase getNewSubmitProtocolTaskInstanceHook(ProtocolBase protocol);
      
    
      protected abstract ProtocolTaskBase getNewSubmitProtocolUnavailableTaskInstanceHook(ProtocolBase protocol);
  
      
      
      protected boolean hasCreateAmendmentPermission() {
          ProtocolTaskBase task = getNewAmendmentProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      
      }
      
      protected boolean hasCreateAmendmentUnavailablePermission() {
          ProtocolTaskBase task = getNewAmendmentProtocolUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      
      }
  
      protected abstract ProtocolTaskBase getNewAmendmentProtocolTaskInstanceHook(ProtocolBase protocol);
      protected abstract ProtocolTaskBase getNewAmendmentProtocolUnavailableTaskInstanceHook(ProtocolBase protocol);
      
      protected boolean hasModifyAmendmentSectionsPermission() {
          ProtocolTaskBase task = getModifyAmendmentSectionsProtocolTaskInstanceHook(getProtocol());
          return ((!getProtocol().isRenewalWithoutAmendment())&&(getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task)));
      }
      
      protected boolean hasModifyAmendmentSectionsUnavailablePermission() {
          ProtocolTaskBase task = getModifyAmendmentSectionsUnavailableProtocolUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
  
      protected abstract ProtocolTaskBase getModifyAmendmentSectionsProtocolTaskInstanceHook(ProtocolBase protocol);
      protected abstract ProtocolTaskBase getModifyAmendmentSectionsUnavailableProtocolUnavailableTaskInstanceHook(ProtocolBase protocol);
      
      
      protected boolean hasCreateRenewalPermission() {
          ProtocolTaskBase task = getNewRenewalProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected boolean hasCreateRenewalUnavailablePermission() {
          ProtocolTaskBase task = getNewRenewalProtocolUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
  
      protected abstract ProtocolTaskBase getNewRenewalProtocolTaskInstanceHook(ProtocolBase protocol);
      protected abstract ProtocolTaskBase getNewRenewalProtocolUnavailableTaskInstanceHook(ProtocolBase protocol);
          
      protected boolean hasWithdrawPermission() {
          ProtocolTaskBase task = getNewWithdrawProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase getNewWithdrawProtocolTaskInstanceHook(ProtocolBase protocol);
  
      
      protected boolean hasWithdrawUnavailablePermission() {
          ProtocolTaskBase task = getNewWithdrawProtocolUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase getNewWithdrawProtocolUnavailableTaskInstanceHook(ProtocolBase protocol);
      
      protected boolean hasDeleteProtocolAmendRenewPermission() {
          ProtocolTaskBase task = createNewAmendRenewDeleteTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
  
      
      protected abstract ProtocolTaskBase createNewAmendRenewDeleteTaskInstanceHook(ProtocolBase protocol);
      
      
      protected boolean hasDeleteProtocolAmendRenewUnavailablePermission() {
          ProtocolTaskBase task = createNewAmendRenewDeleteUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase createNewAmendRenewDeleteUnavailableTaskInstanceHook(ProtocolBase protocol);
      
      
      protected boolean hasAssignToAgendaPermission() {
          ProtocolTaskBase task = createNewAssignToAgendaTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase createNewAssignToAgendaTaskInstanceHook(ProtocolBase protocol);
  
      
      protected boolean hasAssignToAgendaUnavailablePermission() {
          ProtocolTaskBase task = createNewAssignToAgendaUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase createNewAssignToAgendaUnavailableTaskInstanceHook(ProtocolBase protocol);
      
      protected boolean hasFullApprovePermission() {
          return hasPermission(TaskName.APPROVE_PROTOCOL);
      }
      
      protected boolean hasFullApproveUnavailablePermission() {
          return hasPermission(TaskName.APPROVE_PROTOCOL_UNAVAILABLE);
      }
      
      protected boolean hasDisapprovePermission() {
          return hasPermission(TaskName.DISAPPROVE_PROTOCOL);
      }
      
      protected boolean hasDisapproveUnavailablePermission() {
          return hasPermission(TaskName.DISAPPROVE_PROTOCOL_UNAVAILABLE);
      }   
  
      protected boolean hasReturnForSMRPermission() {
          return hasPermission(TaskName.RETURN_FOR_SMR);
      }
      
      protected boolean hasReturnForSMRUnavailablePermission() {
          return hasPermission(TaskName.RETURN_FOR_SMR_UNAVAILABLE);
      }
      
      protected boolean hasReturnForSRRPermission() {
          return hasPermission(TaskName.RETURN_FOR_SRR);
      }
      
      protected boolean hasReturnForSRRUnavailablePermission() {
          return hasPermission(TaskName.RETURN_FOR_SRR_UNAVAILABLE);
      }
  
      protected boolean hasSuspendPermission() {
          ProtocolTaskBase task = getSuspendTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      protected abstract ProtocolTaskBase getSuspendTaskInstanceHook(ProtocolBase protocol);
      
      protected boolean hasSuspendUnavailablePermission() {
          ProtocolTaskBase task = getSuspendUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      protected abstract ProtocolTaskBase getSuspendUnavailableTaskInstanceHook(ProtocolBase protocol);
  
      protected boolean hasTerminatePermission() {
          ProtocolTaskBase task = getTerminateTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      protected abstract ProtocolTaskBase getTerminateTaskInstanceHook(ProtocolBase protocol);
      
      protected boolean hasTerminateUnavailablePermission() {
          ProtocolTaskBase task = getTerminateUnavailableTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      protected abstract ProtocolTaskBase getTerminateUnavailableTaskInstanceHook(ProtocolBase protocol);
  
      protected boolean hasAdminCorrectionPermission() {
          ProtocolTaskBase task = getAdminCorrectionProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected boolean hasAdminCorrectionUnavailablePermission() {
          ProtocolTaskBase task = getAdminCorrectionUnavailableProtocolTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase getAdminCorrectionProtocolTaskInstanceHook(ProtocolBase protocol);
      protected abstract ProtocolTaskBase getAdminCorrectionUnavailableProtocolTaskInstanceHook(ProtocolBase protocol);
      
      protected boolean hasUndoLastActionPermission() {
          return hasPermission(TaskName.PROTOCOL_UNDO_LAST_ACTION) && undoLastActionBean.canUndoLastAction();
      }
      
      protected boolean hasUndoLastActionUnavailablePermission() {
          return hasPermission(TaskName.PROTOCOL_UNDO_LAST_ACTION) && !undoLastActionBean.canUndoLastAction();
      }
      
      protected boolean hasRecordCommitteeDecisionPermission() {
          return hasPermission(TaskName.RECORD_COMMITTEE_DECISION);
      }
      
      protected boolean hasRecordCommitteeDecisionUnavailablePermission() {
          return hasPermission(TaskName.RECORD_COMMITTEE_DECISION_UNAVAILABLE);
      }
          
      protected boolean hasManageReviewCommentsPermission() {
          return hasPermission(TaskName.PROTOCOL_MANAGE_REVIEW_COMMENTS); 
      }
      
      protected boolean hasManageReviewCommentsUnavailablePermission() {
          return hasPermission(TaskName.PROTOCOL_MANAGE_REVIEW_COMMENTS_UNAVAILABLE); 
      }
      
      /*
       * check this 
       */
      protected boolean hasAbandonProtocolPermission() {
          ProtocolTaskBase task = createNewAbandonTaskInstanceHook(getProtocol());
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase createNewAbandonTaskInstanceHook(ProtocolBase protocol);
      
      
      
      // This method should be used for all authorizations going through the task authorization framework, 
      // it makes a downcall to a hook for subclasses to supply the appropriate task using which the 
      // task authorization framework will locate the appropriate spring-wired authorizer.
      protected boolean hasPermission(String taskName) {
          ProtocolTaskBase task = getNewProtocolTaskInstanceHook(taskName);
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected abstract ProtocolTaskBase getNewProtocolTaskInstanceHook(String taskName);
    
      
      
      
      protected boolean hasFollowupAction(String actionCode) {
          if (followupActionActions == null) {
              return false;
          }
          for (ValidProtocolActionActionBase action : followupActionActions) {
              if (StringUtils.equals(action.getFollowupActionCode(),actionCode)) {
                  return true;
              }
          }
          return false;
      }
      
       
  	protected boolean hasCanViewOnlineReviewersPermission() {
          return getReviewerCommentsService().canViewOnlineReviewers(getUserIdentifier(), getSelectedSubmission());
      }
      
      protected boolean hasCanViewOnlineReviewerCommentsPermission() {
          return getReviewerCommentsService().canViewOnlineReviewerComments(getUserIdentifier(), getSelectedSubmission());
      }
  
      protected TaskAuthorizationService getTaskAuthorizationService() {
          if (this.taskAuthorizationService == null) {
              this.taskAuthorizationService = KcServiceLocator.getService(TaskAuthorizationService.class);
          }
          return this.taskAuthorizationService;
      }
      
      public ProtocolSubmitAction getProtocolSubmitAction() {
          return protocolSubmitAction;
      }
  
      public ProtocolFormBase getProtocolForm() {
          return form;
      }
      
      public ProtocolBase getProtocol() {
          return form.getProtocolDocument().getProtocol();
      }
  
      public boolean getCanSubmitProtocol() {
          return canSubmitProtocol;
      }
      
      public boolean getCanSubmitProtocolUnavailable() {
          return canSubmitProtocolUnavailable;
      }
      /**
       * Get the userName of the user for the current session.
       * @return the current session's userName
       */
      protected String getUserIdentifier() {
           return GlobalVariables.getUserSession().getPrincipalId();
      }
  
      public String getSubmissionConstraint() {
          return submissionConstraint;
      }
  
      public ProtocolWithdrawBean getProtocolWithdrawBean() {
          return protocolWithdrawBean;
      }
      
      public ProtocolRequestBean getProtocolCloseRequestBean() {
          return protocolCloseRequestBean;
      }
  
      public ProtocolRequestBean getProtocolSuspendRequestBean() {
          return protocolSuspendRequestBean;
      }
      
      public ProtocolRequestBean getProtocolTerminateRequestBean(){
          return this.protocolTerminateRequestBean;
      }
      
      public ProtocolRequestBean getProtocolWithdrawCloseRequestBean() {
          return protocolWithdrawCloseRequestBean;
      }
  
      public void setProtocolWithdrawCloseRequestBean(ProtocolRequestBean protocolWithdrawCloseRequestBean) {
          this.protocolWithdrawCloseRequestBean = protocolWithdrawCloseRequestBean;
      }
  
      public ProtocolRequestBean getProtocolWithdrawSuspendRequestBean() {
          return protocolWithdrawSuspendRequestBean;
      }
  
      public void setProtocolWithdrawSuspendRequestBean(ProtocolRequestBean protocolWithdrawSuspendRequestBean) {
          this.protocolWithdrawSuspendRequestBean = protocolWithdrawSuspendRequestBean;
      }
  
  
  
  
      public ProtocolRequestBean getProtocolWithdrawTerminateRequestBean() {
          return protocolWithdrawTerminateRequestBean;
      }
  
  
  
  
      public void setProtocolWithdrawTerminateRequestBean(ProtocolRequestBean protocolWithdrawTerminateRequestBean) {
          this.protocolWithdrawTerminateRequestBean = protocolWithdrawTerminateRequestBean;
      }
  
  
  
  
      public ProtocolNotifyCommitteeBean getProtocolNotifyCommitteeBean() {
          return protocolNotifyCommitteeBean;
      }
      
      public ProtocolAmendmentBean getProtocolAmendmentBean() {
          return protocolAmendmentBean;
      }
      
      public void setProtocolAmendmentBean(ProtocolAmendmentBean protocolAmendmentBean) {
          this.protocolAmendmentBean = protocolAmendmentBean;
      }
      
      public ProtocolAmendmentBean getProtocolRenewAmendmentBean() {
          return protocolRenewAmendmentBean;
      }
      
      public ProtocolAmendmentBean getProtocolAmendmentSummaryBean() {
          return protocolAmendmentSummaryBean;
      }
      
      public ProtocolDeleteBean getProtocolDeleteBean() {
          return protocolDeleteBean;
      }
      
      public ProtocolAssignToAgendaBean getAssignToAgendaBean(){
          return this.assignToAgendaBean;
      }
      
      public ProtocolApproveBean getProtocolFullApprovalBean() {
          return protocolFullApprovalBean;
      }
      
      public ProtocolGenericActionBean getProtocolDisapproveBean() {
          return protocolDisapproveBean;
      }
      
      public ProtocolGenericActionBean getProtocolSMRBean() {
          return protocolSMRBean;
      }
      
      public ProtocolGenericActionBean getProtocolSRRBean() {
          return protocolSRRBean;
      }
  
      public ProtocolGenericActionBean getProtocolSuspendBean() {
          return protocolSuspendBean;
      }
      
      public ProtocolGenericActionBean getProtocolCloseBean() {
          return protocolCloseBean;
      }
      
      public ProtocolGenericActionBean getProtocolExpireBean() {
          return protocolExpireBean;
      }
      
      public ProtocolGenericActionBean getProtocolTerminateBean() {
          return protocolTerminateBean;
      }
      
      public AdminCorrectionBean getProtocolAdminCorrectionBean() {
          return protocolAdminCorrectionBean;
      }
      
      public UndoLastActionBean getUndoLastActionBean() {
          return undoLastActionBean;
      }
  
      public CommitteeDecision<?> getCommitteeDecision() {
          return committeeDecision;
      }
      
      protected abstract ProtocolTaskBase getModifySubmissionAvailableTaskHook();
      
      protected abstract ProtocolTaskBase getModifySubmissionUnavailableTaskHook();
      
      protected boolean hasCanModifySubmissionPermission() {
          ProtocolTaskBase task = getModifySubmissionAvailableTaskHook();
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
      
      protected boolean hasCanModifySubmissionUnavailablePermission() {
          ProtocolTaskBase task = getModifySubmissionUnavailableTaskHook();
          return getTaskAuthorizationService().isAuthorized(getUserIdentifier(), task);
      }
    
      public ProtocolGenericActionBean getProtocolManageReviewCommentsBean() {
          return protocolManageReviewCommentsBean;
      }
  
      public boolean getCanCreateAmendment() {
          return canCreateAmendment;
      }
      
      public boolean getCanCreateAmendmentUnavailable() {
          return canCreateAmendmentUnavailable;
      }
      
      public boolean getCanModifyAmendmentSections() {
          return canModifyAmendmentSections;
      }
  
      public boolean getCanModifyAmendmentSectionsUnavailable() {
          return canModifyAmendmentSectionsUnavailable;
      }
  
      public boolean getCanCreateRenewal() {
          return canCreateRenewal;
      }
  
      public boolean getCanCreateRenewalUnavailable() {
          return canCreateRenewalUnavailable;
      }
  
      public boolean getCanNotifyCommittee() {
          return canNotifyCommittee;
      }
      
      public boolean getCanNotifyCommitteeUnavailable() {
          return canNotifyCommitteeUnavailable;
      }
      
      public boolean getCanWithdraw() {
          return canWithdraw;
      }
      
      public boolean getCanWithdrawUnavailable() {
          return canWithdrawUnavailable;
      }
      
      public boolean getCanRequestSuspension() {
          return canRequestSuspension;
      }
      
      public boolean getCanRequestSuspensionUnavailable() {
          return canRequestSuspensionUnavailable;
      }
          
      public boolean getcanRequestTerminate(){
          return this.canRequestTerminate;
      }
      
      public boolean getcanRequestTerminateUnavailable(){
          return this.canRequestTerminateUnavailable;
      }
      
      public boolean getCanWithdrawSubmission(){
          return this.canWithdrawSubmission;
      }
      
      public boolean getCanWithdrawSubmissionUnavailable(){
          return this.canWithdrawSubmissionUnavailable;
      }
      
      public boolean getCanDeleteProtocolAmendRenew() {
          return canDeleteProtocolAmendRenew;
      }
      
      public boolean getCanDeleteProtocolAmendRenewUnavailable() {
          return canDeleteProtocolAmendRenewUnavailable;
      }
      
      public boolean getCanAssignToAgenda() {
          return canAssignToAgenda;
      }
      
      public boolean getCanAssignToAgendaUnavailable() {
          return canAssignToAgendaUnavailable;
      }
      
      public boolean getCanAssignCmtSched() {
          return canAssignCmtSched;
      }
      
      public boolean getCanAssignCmtSchedUnavailable() {
          return canAssignCmtSchedUnavailable;
      }
      
      public boolean getCanAssignReviewers() {
          return canAssignReviewers;
      }
      
      public boolean getCanAssignReviewersUnavailable() {
          return canAssignReviewersUnavailable;
      }
      
      public boolean getCanAssignReviewersCmtSel() {
          return canAssignReviewersCmtSel;
      }
      
      public boolean getCanApproveFull() {
          return canApproveFull;
      }
      
      public boolean getCanApproveFullUnavailable() {
          return canApproveFullUnavailable;
      }
      
      public boolean getCanApproveResponse() {
          return canApproveResponse;
      }
      
      public boolean getCanApproveResponseUnavailable() {
          return canApproveResponseUnavailable;
      }
      
      public boolean getCanDisapprove() {
          return canDisapprove;
      }
      
      public boolean getCanDisapproveUnavailable() {
          return canDisapproveUnavailable;
      }
      
      public boolean getCanReturnForSMR() {
          return canReturnForSMR;
      }
      
      public boolean getCanReturnForSMRUnavailable() {
          return canReturnForSMRUnavailable;
      }
      
      public boolean getCanReturnForSRR() {
          return canReturnForSRR;
      }
      
      public boolean getCanReturnForSRRUnavailable() {
          return canReturnForSRRUnavailable;
      }
      
      public boolean getCanSuspend() {
          return canSuspend;
      }
      
      public boolean getCanSuspendUnavailable() {
          return canSuspendUnavailable;
      }
  
      public boolean getCanClose() {
          return canClose;
      }
      
      public boolean getCanCloseUnavailable() {
          return canCloseUnavailable;
      }
      
      public boolean getCanExpire() {
          return canExpire;
      }
      
      public boolean getCanExpireUnavailable() {
          return canExpireUnavailable;
      }
      
      public boolean getCanTerminate() {
          return canTerminate;
      }
      
      public boolean getCanTerminateUnavailable() {
          return canTerminateUnavailable;
      }
      
      public boolean getCanPerformAdminDetermination() {
          return canPerformAdminDetermination;
      }
  
      public void setCanPerformAdminDetermination(boolean canPerformAdminDetermination) {
          this.canPerformAdminDetermination = canPerformAdminDetermination;
      }
  
      public boolean getCanPerformAdminDeterminationUnavailable() {
          return canPerformAdminDeterminationUnavailable;
      }
  
      public void setCanPerformAdminDeterminationUnavailable(boolean canPerformAdminDeterminationUnavailable) {
          this.canPerformAdminDeterminationUnavailable = canPerformAdminDeterminationUnavailable;
      }
  
      public boolean getCanAdministrativelyApprove() {
          return canAdministrativelyApprove;
      }
  
      public void setCanAdministrativelyApprove(boolean canAdministrativelyApprove) {
          this.canAdministrativelyApprove = canAdministrativelyApprove;
      }
  
      public boolean getCanAdministrativelyApproveUnavailable() {
          return canAdministrativelyApproveUnavailable;
      }
  
      public void setCanAdministrativelyApproveUnavailable(boolean canAdministrativelyApproveUnavailable) {
          this.canAdministrativelyApproveUnavailable = canAdministrativelyApproveUnavailable;
      }
  
      public boolean getCanAdministrativelyMarkIncomplete() {
          return canAdministrativelyMarkIncomplete;
      }
  
      public void setCanAdministrativelyMarkIncomplete(boolean canAdministrativelyMarkIncomplete) {
          this.canAdministrativelyMarkIncomplete = canAdministrativelyMarkIncomplete;
      }
  
      public boolean getCanAdministrativelyMarkIncompleteUnavailable() {
          return canAdministrativelyMarkIncompleteUnavailable;
      }
  
      public void setCanAdministrativelyMarkIncompleteUnavailable(boolean canAdministrativelyMarkIncompleteUnavailable) {
          this.canAdministrativelyMarkIncompleteUnavailable = canAdministrativelyMarkIncompleteUnavailable;
      }
  
      public boolean getCanAdministrativelyWithdraw() {
          return canAdministrativelyWithdraw;
      }
  
      public void setCanAdministrativelyWithdraw(boolean canAdministrativelyWithdraw) {
          this.canAdministrativelyWithdraw = canAdministrativelyWithdraw;
      }
  
      public boolean getCanAdministrativelyWithdrawUnavailable() {
          return canAdministrativelyWithdrawUnavailable;
      }
  
      public void setCanAdministrativelyWithdrawUnavailable(boolean canAdministrativelyWithdrawUnavailable) {
          this.canAdministrativelyWithdrawUnavailable = canAdministrativelyWithdrawUnavailable;
      }
      
      
      
  
      public void setProtocolAdminWithdrawBean(ProtocolAdministrativelyWithdrawBean protocolAdminWithdrawBean) {
          this.protocolAdminWithdrawBean = protocolAdminWithdrawBean;
      }
  
      public ProtocolAdministrativelyWithdrawBean getProtocolAdminWithdrawBean() {
          return protocolAdminWithdrawBean;
      }
  
      public void setProtocolAdminApprovalBean(ProtocolApproveBean protocolAdminApprovalBean) {
          this.protocolAdminApprovalBean = protocolAdminApprovalBean;
      }
  
      public ProtocolApproveBean getProtocolAdminApprovalBean() {
          return protocolAdminApprovalBean;
      }
  
      public void setProtocolAdminIncompleteBean(ProtocolAdministrativelyIncompleteBean protocolAdminIncompleteBean) {
          this.protocolAdminIncompleteBean = protocolAdminIncompleteBean;
      }
  
      public ProtocolAdministrativelyIncompleteBean getProtocolAdminIncompleteBean() {
          return protocolAdminIncompleteBean;
      }
  
      public boolean getCanMakeAdminCorrection() {
          return canMakeAdminCorrection;
      }
      
      public boolean getCanMakeAdminCorrectionUnavailable() {
          return canMakeAdminCorrectionUnavailable;
      }
      
      public boolean getCanUndoLastAction() {
          return canUndoLastAction;
      }
      
      public boolean getCanUndoLastActionUnavailable() {
          return canUndoLastActionUnavailable;
      }
      
      public boolean getCanRecordCommitteeDecision() {
          return canRecordCommitteeDecision;
      }
      
      public boolean getCanRecordCommitteeDecisionUnavailable() {
          return canRecordCommitteeDecisionUnavailable;
      }
      
      public boolean getCanModifyProtocolSubmission() {
          return this.canModifyProtocolSubmission;
      }
      
      public boolean getCanModifyProtocolSubmissionUnavailable() {
          return this.canModifyProtocolSubmissionUnavailable;
      }
      
      public boolean getCanManageReviewComments() {  
          return canManageReviewComments;
      }
      
      public boolean getCanManageReviewCommentsUnavailable() {  
          return canManageReviewCommentsUnavailable;
      }
      
      public boolean getCanApproveOther() {
          return canApproveOther;
      }
      
      public boolean getCanManageNotes() {
          return canManageNotes;
      }
  
      public boolean getCanManageNotesUnavailable() {
          return canManageNotesUnavailable;
      }
  
       
      public boolean getIsApproveOpenForFollowup() {
          return hasFollowupAction(getFullApprovalProtocolActionTypeHook());
      }
  
      
      public boolean getIsDisapproveOpenForFollowup() {
          return hasFollowupAction(getDisapprovedProtocolActionTypeHook());
      }
      
  
      public boolean getIsReturnForSMROpenForFollowup() {
          return hasFollowupAction(getSMRProtocolActionTypeHook());
      }
  
      public boolean getIsReturnForSRROpenForFollowup() {
          return hasFollowupAction(getSRRProtocolActionTypeHook());
      }
      
      /**
       * 
       * This method is one of the criteria to decide if there is a followup action for requested action panel to open
       * @return
       */
      public boolean isOpenForFollowup() {
          return getIsApproveOpenForFollowup() || getIsDisapproveOpenForFollowup() || getIsReturnForSMROpenForFollowup() || getIsReturnForSRROpenForFollowup();
      }
      
      public Map<String,Boolean> getFollowupActionMap() {
          return followupActionMap;
      }
      
      public boolean getCanViewOnlineReviewers() {
          return canViewOnlineReviewers;
      }
      
      public boolean getCanViewOnlineReviewerComments() {
          return canViewOnlineReviewerComments;
      }
      
      public boolean getCanAddSuspendReviewerComments() {
          return canAddSuspendReviewerComments;
      }
  
      public boolean getCanAddTerminateReviewerComments() {
          return canAddTerminateReviewerComments;
      }
  
      public ProtocolSummary getProtocolSummary() {
          return protocolSummary;
      }
      
      public ProtocolSummary getPrevProtocolSummary() {
          return prevProtocolSummary;
      }
      
      public void setSelectedHistoryItem(String selectedHistoryItem) {
          this.selectedHistoryItem = selectedHistoryItem;
      }
      
      public String getSelectedHistoryItem() {
          return selectedHistoryItem;
      }
      
      public Date getFilteredHistoryStartDate() {
          return filteredHistoryStartDate;
      }
      
      public void setFilteredHistoryStartDate(Date filteredHistoryStartDate) {
          this.filteredHistoryStartDate = filteredHistoryStartDate;
      }
      
      public Date getFilteredHistoryEndDate() {
          return filteredHistoryEndDate;
      }
      
      public void setFilteredHistoryEndDate(Date filteredHistoryEndDate) {
          this.filteredHistoryEndDate = filteredHistoryEndDate;
      }
           
      public ProtocolActionBase getLastPerformedAction() {
          List<ProtocolActionBase> protocolActions = form.getProtocolDocument().getProtocol().getProtocolActions();
          Collections.sort(protocolActions, new Comparator<ProtocolActionBase>() {
              public int compare(ProtocolActionBase action1, ProtocolActionBase action2) {
                  return action2.getActualActionDate().compareTo(action1.getActualActionDate());
              }
          });
       
          return protocolActions.size() > 0 ? protocolActions.get(0) : null;
      }
      
      /**
       * Prepares all protocol actions for being filtered by setting their isInFilterView attribute.
       */
      public void initFilterDatesView() {
          java.util.Date dayBeforeStartDate = null;
          java.util.Date dayAfterEndDate = null;
  
          if (filteredHistoryStartDate != null && filteredHistoryEndDate != null) {
              dayBeforeStartDate = DateUtils.addDays(filteredHistoryStartDate, -1);
              dayAfterEndDate = DateUtils.addDays(filteredHistoryEndDate, 1);
          }
  
          for (ProtocolActionBase protocolAction : getSortedProtocolActions()) {
              Timestamp actionDate = protocolAction.getActionDate();
              if (dayBeforeStartDate != null && dayAfterEndDate != null) {
                  protocolAction.setIsInFilterView(actionDate.after(dayBeforeStartDate) && actionDate.before(dayAfterEndDate));
              }
              else {
                  protocolAction.setIsInFilterView(true);
              }
              if (protocolAction.getIsInFilterView()) {
                  
              }
          }
      }
      
      /**
       * Prepares, sorts, and returns a list of protocol actions.
       * @return
       */
      public List<ProtocolActionBase> getSortedProtocolActions() {
          List<ProtocolActionBase> protocolActions = new ArrayList<ProtocolActionBase>();
          for (ProtocolActionBase protocolAction : form.getProtocolDocument().getProtocol().getProtocolActions()) {       
             if (protocolAction.getSubmissionNumber() != null) {
                 protocolAction.setProtocolSubmissionDocs(new ArrayList<ProtocolSubmissionDocBase>(getSubmissionDocs(protocolAction)));
             }
              protocolActions.add(protocolAction);
          }
          
          Collections.sort(protocolActions, new Comparator<ProtocolActionBase>() {
              public int compare(ProtocolActionBase action1, ProtocolActionBase action2) {
                  return action2.getActualActionDate().compareTo(action1.getActualActionDate());
              }
          });
       
          return protocolActions;
      }
  
      protected Collection<? extends ProtocolSubmissionDocBase> getSubmissionDocs(ProtocolActionBase protocolAction) {
          Map<String, Object> fieldValues = new HashMap<String, Object>();
          fieldValues.put("protocolNumber", protocolAction.getProtocolNumber());
          fieldValues.put("submissionNumber", protocolAction.getSubmissionNumber());
          return getBusinessObjectService().findMatchingOrderBy(getProtocolSubmissionDocClassHook(), fieldValues, "documentId", true);
      }
  
      
      
      protected abstract Class<? extends ProtocolSubmissionDocBase> getProtocolSubmissionDocClassHook();
  
      
      
      public ProtocolActionBase getSelectedProtocolAction() {
          for (ProtocolActionBase action : getProtocol().getProtocolActions()) {
              if (StringUtils.equals(action.getProtocolActionId().toString(), selectedHistoryItem)) {
                  return action;
              }
          }
          return null;
      }
      
      public void setCurrentSequenceNumber(int currentSequenceNumber) {
          this.currentSequenceNumber = currentSequenceNumber;
      }
      
      public int getCurrentSequenceNumber() {
          return currentSequenceNumber;
      }
      
      public int getSequenceCount() {
          return getProtocol().getSequenceNumber()  + 1;
      }
      
      /**
       * Looks up and returns the ParameterService.
       * @return the parameter service. 
       */
      protected ParameterService getParameterService() {
          if (this.parameterService == null) {
              this.parameterService = KcServiceLocator.getService(ParameterService.class);
          }
          return this.parameterService;
      }
  
      /**
       * Finds and returns the current selection based on the currentSubmissionNumber.
       * 
       * If the currentSubmissionNumber is invalid, it will return the current protocol's latest submission (which is always non-null); otherwise, it will get
       * the submission from the protocol based on the currentSubmissionNumber.
       * @return the currently selected submission
       */
      public ProtocolSubmissionBase getSelectedSubmission() {
          ProtocolSubmissionBase protocolSubmission = null;
          
          if (currentSubmissionNumber <= 0) {
              protocolSubmission = getProtocol().getProtocolSubmission();
          } else if (currentSubmissionNumber > 0) {
              for (ProtocolSubmissionBase submission : getProtocol().getProtocolSubmissions()) {
                  if (submission.getSubmissionNumber().intValue() == currentSubmissionNumber) {
                      protocolSubmission = submission;
                      break;
                  }
              }
              if (protocolSubmission == null) {
                  // undo last action may remove the last submission; so it can't be found
                  protocolSubmission = getProtocol().getProtocolSubmission();
                  currentSubmissionNumber = protocolSubmission.getSubmissionNumber();
              }
          }
          
          return protocolSubmission;
      }
  
  
      public List<CommitteeScheduleMinuteBase> getReviewComments() {
          return reviewComments;
      }
  
      // create getter for sorted comments to preserve old functionality
      public List<CommitteeScheduleMinuteBase> getSortedReviewComments() {
          List<CommitteeScheduleMinuteBase>results = new ArrayList<CommitteeScheduleMinuteBase>();
          results.addAll(reviewComments);
          Collections.sort(results, new Comparator<CommitteeScheduleMinuteBase>() {
              @Override
              public int compare(CommitteeScheduleMinuteBase o1, CommitteeScheduleMinuteBase o2) {
                  return o1.getEntryNumber().compareTo(o2.getEntryNumber());
              }
          });
          return results;
      }
  
      protected void setReviewComments(List<CommitteeScheduleMinuteBase> reviewComments) {
          this.reviewComments = reviewComments;
      }
  
      public List<ProtocolVoteAbstaineeBase> getAbstainees() {
          return abstainees;
      }
  
      public void setAbstainees(List<ProtocolVoteAbstaineeBase> abstainees) {
          this.abstainees = abstainees;
      }
      
      public BusinessObjectService getBusinessObjectService() {
          if (businessObjectService == null) {
              businessObjectService = KcServiceLocator.getService(BusinessObjectService.class);
          }
          return businessObjectService;
      }
      
      public FollowupActionService<?> getFollowupActionService() {
          if (followupActionService == null) {
              followupActionService = KcServiceLocator.getService(getFollowupActionServiceClassHook());
          }
          return followupActionService;
      }
      
      
      protected abstract Class<? extends FollowupActionService<?>> getFollowupActionServiceClassHook();
      
  
      protected ReviewCommentsService getReviewerCommentsService() {
          return getReviewCommentsService();
      }
      
      protected abstract CommitteeDecisionService<? extends CommitteeDecision<?> > getCommitteeDecisionService();
      
      protected KcPersonService getKcPersonService() {
          if (this.kcPersonService == null) {
              this.kcPersonService = KcServiceLocator.getService(KcPersonService.class);
          }
          
          return this.kcPersonService;
      }
      
      public int getCurrentSubmissionNumber() {
          return currentSubmissionNumber;
      }
  
      public void setCurrentSubmissionNumber(int currentSubmissionNumber) {
          this.currentSubmissionNumber = currentSubmissionNumber;
      }
      
      public abstract int getTotalSubmissions();
      
      /**
       * Sets up the summary details subpanel.
       * @throws Exception 
       */
      public void initSummaryDetails() throws Exception {
          if (currentSequenceNumber == -1) {
              currentSequenceNumber = getProtocol().getSequenceNumber();
          } else if (currentSequenceNumber > getProtocol().getSequenceNumber()) {
              currentSequenceNumber = getProtocol().getSequenceNumber();
          }
          
          protocolSummary =  null;
          String protocolNumber = getProtocol().getProtocolNumber();
          ProtocolBase protocol = getProtocolVersionService().getProtocolVersion(protocolNumber, currentSequenceNumber);
          if (protocol != null) {
              protocolSummary = protocol.getProtocolSummary();
          }
          
          prevProtocolSummary = null;
          if (currentSequenceNumber > 0) {
              protocol = getProtocolVersionService().getProtocolVersion(protocolNumber, currentSequenceNumber - 1);
              if (protocol != null) {
                  prevProtocolSummary = protocol.getProtocolSummary();
              }
          }
          
          if (protocolSummary != null && prevProtocolSummary != null) {
              protocolSummary.compare(prevProtocolSummary);
              prevProtocolSummary.compare(protocolSummary);
          }
  
          setSummaryQuestionnaireExist(hasAnsweredQuestionnaire((protocol.isAmendment() || protocol.isRenewal()) ? CoeusSubModule.AMENDMENT_RENEWAL : CoeusSubModule.ZERO_SUBMODULE, protocol.getSequenceNumber().toString()));
      }
  
      /**
       * Sets up dates for the submission details subpanel.
       */
      public void initSubmissionDetails() {
          if (currentSubmissionNumber <= 0) {
              currentSubmissionNumber = getTotalSubmissions();
          }
  
          if (CollectionUtils.isNotEmpty(getProtocol().getProtocolSubmissions()) && getProtocol().getProtocolSubmissions().size() > 1) {
              setPrevNextFlag();
          } else {
              setPrevDisabled(true);
              setNextDisabled(true);
          }
        
          setReviewComments(getReviewerCommentsService().getReviewerComments(getProtocol().getProtocolNumber(), currentSubmissionNumber));
          if (CollectionUtils.isNotEmpty(getReviewComments())) {
              // check if our comments bean has empty list of review comments, this can happen if the submission has no schedule assigned
              // also check that the list of deleted comments is empty, because deletion of comments can also lead to an empty list of review comments.
              if( (protocolManageReviewCommentsBean.getReviewCommentsBean().getReviewComments().size() == 0) 
                      && 
                  (protocolManageReviewCommentsBean.getReviewCommentsBean().getDeletedReviewComments().size() == 0) ) {
                  // TODO OPTIMIZATION perhaps the call below is not needed, can simply use getReviewComments since the review comments have been set above 
                  List<CommitteeScheduleMinuteBase> reviewComments = getReviewerCommentsService().getReviewerComments(getProtocol().getProtocolNumber(), currentSubmissionNumber);
                  Collections.sort(reviewComments, new Comparator<CommitteeScheduleMinuteBase>() {
  
                      @Override
                      public int compare(CommitteeScheduleMinuteBase csm1, CommitteeScheduleMinuteBase csm2) {
                          int retVal = 0;
                          if( (csm1 != null) && (csm2 != null) && (csm1.getEntryNumber() != null) && (csm2.getEntryNumber() != null) ) {
                              retVal = csm1.getEntryNumber().compareTo(csm2.getEntryNumber());
                          }
                          return retVal;
                      }
                      
                  });
                  protocolManageReviewCommentsBean.getReviewCommentsBean().setReviewComments(reviewComments);
                  getReviewerCommentsService().setHideReviewerName(reviewComments);
                  setHidePrivateFinalFlagsForPublicCommentsAttachments(getReviewerCommentsService().isHidePrivateFinalFlagsForPI(reviewComments));
              }
              getReviewerCommentsService().setHideReviewerName(getReviewComments());
              setHidePrivateFinalFlagsForPublicCommentsAttachments(getReviewerCommentsService().isHidePrivateFinalFlagsForPI(reviewComments));            
          }
          setReviewAttachments(getReviewerCommentsService().getReviewerAttachments(getProtocol().getProtocolNumber(), currentSubmissionNumber));
  