org.akaza.openclinica.control.submit.CreateDiscrepancyNoteServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.akaza.openclinica.control.submit.CreateDiscrepancyNoteServlet.java

Source

/*
 * OpenClinica is distributed under the
 * GNU Lesser General Public License (GNU LGPL).
    
 * For details see: http://www.openclinica.org/license
 * copyright 2003-2012 Akaza Research
 */
package org.akaza.openclinica.control.submit;

import java.text.DateFormat;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpSession;

import org.akaza.openclinica.bean.core.DiscrepancyNoteType;
import org.akaza.openclinica.bean.core.NumericComparisonOperator;
import org.akaza.openclinica.bean.core.ResolutionStatus;
import org.akaza.openclinica.bean.core.Role;
import org.akaza.openclinica.bean.core.Status;
import org.akaza.openclinica.bean.core.SubjectEventStatus;
import org.akaza.openclinica.bean.login.UserAccountBean;
import org.akaza.openclinica.bean.managestudy.DiscrepancyNoteBean;
import org.akaza.openclinica.bean.managestudy.StudyBean;
import org.akaza.openclinica.bean.managestudy.StudyEventBean;
import org.akaza.openclinica.bean.managestudy.StudySubjectBean;
import org.akaza.openclinica.bean.submit.EventCRFBean;
import org.akaza.openclinica.bean.submit.ItemBean;
import org.akaza.openclinica.bean.submit.ItemDataBean;
import org.akaza.openclinica.bean.submit.SectionBean;
import org.akaza.openclinica.bean.submit.SubjectBean;
import org.akaza.openclinica.control.core.SecureController;
import org.akaza.openclinica.control.form.FormDiscrepancyNotes;
import org.akaza.openclinica.control.form.FormProcessor;
import org.akaza.openclinica.control.form.Validator;
import org.akaza.openclinica.core.EmailEngine;
import org.akaza.openclinica.core.form.StringUtil;
import org.akaza.openclinica.dao.login.UserAccountDAO;
import org.akaza.openclinica.dao.managestudy.DiscrepancyNoteDAO;
import org.akaza.openclinica.dao.managestudy.StudyDAO;
import org.akaza.openclinica.dao.managestudy.StudyEventDAO;
import org.akaza.openclinica.dao.managestudy.StudySubjectDAO;
import org.akaza.openclinica.dao.submit.EventCRFDAO;
import org.akaza.openclinica.dao.submit.ItemDAO;
import org.akaza.openclinica.dao.submit.ItemDataDAO;
import org.akaza.openclinica.dao.submit.SectionDAO;
import org.akaza.openclinica.dao.submit.SubjectDAO;
import org.akaza.openclinica.i18n.core.LocaleResolver;
import org.akaza.openclinica.view.Page;
import org.akaza.openclinica.web.InsufficientPermissionException;
import org.akaza.openclinica.web.SQLInitServlet;
import org.apache.commons.lang.StringUtils;

/**
 * Create a discrepancy note for a data entity
 *
 * @author jxu
 *
 */
public class CreateDiscrepancyNoteServlet extends SecureController {

    Locale locale;
    // < ResourceBundleresexception,respage;

    public static final String DIS_TYPES = "discrepancyTypes";

    public static final String RES_STATUSES = "resolutionStatuses";

    public static final String ENTITY_ID = "id";

    public static final String SUBJECT_ID = "subjectId";

    public static final String ITEM_ID = "itemId";

    public static final String IS_GROUP_ITEM = "isGroup";

    public static final String PARENT_ID = "parentId";// parent note id

    public static final String ENTITY_TYPE = "name";

    public static final String ENTITY_COLUMN = "column";

    public static final String ENTITY_FIELD = "field";

    public static final String DIS_NOTE = "discrepancyNote";

    public static final String WRITE_TO_DB = "writeToDB";

    public static final String IS_REASON_FOR_CHANGE = "isRfc";

    public static final String PRESET_RES_STATUS = "strResStatus";

    public static final String CAN_MONITOR = "canMonitor";

    public static final String NEW_NOTE = "new";

    public static final String RES_STATUS_ID = "resStatusId";

    public static final String ERROR_FLAG = "errorFlag";// use to determine
    // discrepany note type,
    // whether a note's item
    // has validation error
    // or not

    public static final String USER_ACCOUNTS = "userAccounts"; // use to provide
    // a list of user
    // accounts

    public static final String USER_ACCOUNT_ID = "strUserAccountId"; // use to
    // provide a
    // single user
    // id, to whom
    // the query
    // is
    // assigned,
    // tbh 02/2009

    public static final String SUBMITTED_USER_ACCOUNT_ID = "userAccountId";

    public static final String PRESET_USER_ACCOUNT_ID = "preUserAccountId";

    public static final String EMAIL_USER_ACCOUNT = "sendEmail";

    public static final String WHICH_RES_STATUSES = "whichResStatus";

    public static final String EVENT_CRF_ID = "eventCRFId";
    public static final String PARENT_ROW_COUNT = "rowCount";

    public String exceptionName = resexception.getString("no_permission_to_create_discrepancy_note");
    public String noAccessMessage = respage.getString("you_may_not_create_discrepancy_note")
            + respage.getString("change_study_contact_sysadmin");

    public static final String FLAG_DISCREPANCY_RFC = "flagDNRFC";

    /*
     * (non-Javadoc)
     *
     * @see org.akaza.openclinica.control.core.SecureController#mayProceed()
     */
    @Override
    protected void mayProceed() throws InsufficientPermissionException {
        checkStudyLocked(Page.MENU_SERVLET, respage.getString("current_study_locked"));
        locale = LocaleResolver.getLocale(request);

        if (SubmitDataServlet.mayViewData(ub, currentRole)) {
            return;
        }

        addPageMessage(noAccessMessage);
        throw new InsufficientPermissionException(Page.MENU, exceptionName, "1");
    }

    @Override
    protected void processRequest() throws Exception {
        FormProcessor fp = new FormProcessor(request);
        DiscrepancyNoteDAO dndao = new DiscrepancyNoteDAO(sm.getDataSource());
        List<DiscrepancyNoteType> types = DiscrepancyNoteType.list;

        request.setAttribute(DIS_TYPES, types);
        request.setAttribute(RES_STATUSES, ResolutionStatus.list);

        boolean writeToDB = fp.getBoolean(WRITE_TO_DB, true); //this should be set based on a new property of DisplayItemBean
        boolean isReasonForChange = fp.getBoolean(IS_REASON_FOR_CHANGE);
        int entityId = fp.getInt(ENTITY_ID);
        // subjectId has to be added to the database when disc notes area saved
        // as entity_type 'subject'
        int subjectId = fp.getInt(SUBJECT_ID);
        int itemId = fp.getInt(ITEM_ID);
        String entityType = fp.getString(ENTITY_TYPE);

        String field = fp.getString(ENTITY_FIELD);
        String column = fp.getString(ENTITY_COLUMN);
        int parentId = fp.getInt(PARENT_ID);

        //patch for repeating groups and RFC on empty fields

        int isGroup = fp.getInt(IS_GROUP_ITEM);
        //  request.setAttribute(IS_GROUP_ITEM, new Integer(isGroup));
        int eventCRFId = fp.getInt(EVENT_CRF_ID);
        request.setAttribute(EVENT_CRF_ID, new Integer(eventCRFId));
        int rowCount = fp.getInt(PARENT_ROW_COUNT);
        // run only once: try to recalculate writeToDB
        if (!StringUtils.isBlank(entityType) && "itemData".equalsIgnoreCase(entityType) && isGroup != 0
                && eventCRFId != 0) {
            //  request.setAttribute(PARENT_ROW_COUNT, new Integer(eventCRFId));
            int ordinal_for_repeating_group_field = calculateOrdinal(isGroup, field, eventCRFId, rowCount);
            int writeToDBStatus = isWriteToDB(isGroup, field, entityId, itemId, ordinal_for_repeating_group_field,
                    eventCRFId);
            writeToDB = (writeToDBStatus == -1) ? false : ((writeToDBStatus == 1) ? true : writeToDB);
        }
        boolean isInError = fp.getBoolean(ERROR_FLAG);

        boolean isNew = fp.getBoolean(NEW_NOTE);
        request.setAttribute(NEW_NOTE, isNew ? "1" : "0");

        String strResStatus = fp.getString(PRESET_RES_STATUS);
        if (!strResStatus.equals("")) {
            request.setAttribute(PRESET_RES_STATUS, strResStatus);
        }

        String monitor = fp.getString("monitor");
        String enterData = fp.getString("enterData");
        request.setAttribute("enterData", enterData);

        boolean enteringData = false;
        if (enterData != null && "1".equalsIgnoreCase(enterData)) {
            // variables are not set in JSP, so not from viewing data and from
            // entering data
            request.setAttribute(CAN_MONITOR, "1");
            request.setAttribute("monitor", monitor);

            enteringData = true;
        } else if ("1".equalsIgnoreCase(monitor)) {// change to allow user to
            // enter note for all items,
            // not just blank items

            request.setAttribute(CAN_MONITOR, "1");
            request.setAttribute("monitor", monitor);

        } else {
            request.setAttribute(CAN_MONITOR, "0");

        }

        if ("itemData".equalsIgnoreCase(entityType) && enteringData) {
            request.setAttribute("enterItemData", "yes");
        }

        DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
        int preUserId = 0;
        if (!StringUtils.isBlank(entityType)) {
            if ("itemData".equalsIgnoreCase(entityType) || "itemdata".equalsIgnoreCase(entityType)) {
                ItemBean item = (ItemBean) new ItemDAO(sm.getDataSource()).findByPK(itemId);
                ItemDataBean itemData = (ItemDataBean) new ItemDataDAO(sm.getDataSource()).findByPK(entityId);
                request.setAttribute("entityValue", itemData.getValue());
                request.setAttribute("entityName", item.getName());
                EventCRFDAO ecdao = new EventCRFDAO(sm.getDataSource());
                EventCRFBean ec = (EventCRFBean) ecdao.findByPK(itemData.getEventCRFId());
                preUserId = ec.getOwnerId();
            } else if ("studySub".equalsIgnoreCase(entityType)) {
                StudySubjectBean ssub = (StudySubjectBean) new StudySubjectDAO(sm.getDataSource())
                        .findByPK(entityId);
                SubjectBean sub = (SubjectBean) new SubjectDAO(sm.getDataSource()).findByPK(ssub.getSubjectId());
                preUserId = ssub.getOwnerId();
                if (!StringUtils.isBlank(column)) {
                    if ("enrollment_date".equalsIgnoreCase(column)) {
                        if (ssub.getEnrollmentDate() != null) {
                            request.setAttribute("entityValue", dateFormatter.format(ssub.getEnrollmentDate()));
                        } else {
                            request.setAttribute("entityValue", resword.getString("N/A"));
                        }
                        request.setAttribute("entityName", resword.getString("enrollment_date"));
                    } else if ("gender".equalsIgnoreCase(column)) {
                        request.setAttribute("entityValue", sub.getGender() + "");
                        request.setAttribute("entityName", resword.getString("gender"));
                    } else if ("date_of_birth".equalsIgnoreCase(column)) {
                        if (sub.getDateOfBirth() != null) {
                            request.setAttribute("entityValue", dateFormatter.format(sub.getDateOfBirth()));
                        } else {
                            request.setAttribute("entityValue", resword.getString("N/A"));
                        }
                        request.setAttribute("entityName", resword.getString("date_of_birth"));
                    } else if ("unique_identifier".equalsIgnoreCase(column)) {
                        if (sub.getUniqueIdentifier() != null) {
                            request.setAttribute("entityValue", sub.getUniqueIdentifier());
                        }
                        request.setAttribute("entityName", resword.getString("unique_identifier"));
                    }
                }
            } else if ("subject".equalsIgnoreCase(entityType)) {
                SubjectBean sub = (SubjectBean) new SubjectDAO(sm.getDataSource()).findByPK(entityId);
                preUserId = sub.getOwnerId();
                if (!StringUtils.isBlank(column)) {
                    if ("gender".equalsIgnoreCase(column)) {
                        request.setAttribute("entityValue", sub.getGender() + "");
                        request.setAttribute("entityName", resword.getString("gender"));
                    } else if ("date_of_birth".equalsIgnoreCase(column)) {
                        if (sub.getDateOfBirth() != null) {
                            request.setAttribute("entityValue", dateFormatter.format(sub.getDateOfBirth()));
                        }
                        request.setAttribute("entityName", resword.getString("date_of_birth"));
                    } else if ("unique_identifier".equalsIgnoreCase(column)) {
                        request.setAttribute("entityValue", sub.getUniqueIdentifier());
                        request.setAttribute("entityName", resword.getString("unique_identifier"));
                    }
                }
            } else if ("studyEvent".equalsIgnoreCase(entityType)) {
                StudyEventBean se = (StudyEventBean) new StudyEventDAO(sm.getDataSource()).findByPK(entityId);
                preUserId = se.getOwnerId();
                if (!StringUtils.isBlank(column)) {
                    if ("location".equalsIgnoreCase(column)) {
                        request.setAttribute("entityValue",
                                se.getLocation().equals("") || se.getLocation() == null ? resword.getString("N/A")
                                        : se.getLocation());
                        request.setAttribute("entityName", resword.getString("location"));
                    } else if ("start_date".equalsIgnoreCase(column)) {
                        if (se.getDateStarted() != null) {
                            request.setAttribute("entityValue", dateFormatter.format(se.getDateStarted()));
                        } else {
                            request.setAttribute("entityValue", resword.getString("N/A"));
                        }
                        request.setAttribute("entityName", resword.getString("start_date"));
                    } else if ("end_date".equalsIgnoreCase(column)) {
                        if (se.getDateEnded() != null) {
                            request.setAttribute("entityValue", dateFormatter.format(se.getDateEnded()));
                        } else {
                            request.setAttribute("entityValue", resword.getString("N/A"));
                        }
                        request.setAttribute("entityName", resword.getString("end_date"));
                    }
                }
            } else if ("eventCrf".equalsIgnoreCase(entityType)) {
                EventCRFBean ec = (EventCRFBean) new EventCRFDAO(sm.getDataSource()).findByPK(entityId);
                preUserId = ec.getOwnerId();
                if (!StringUtils.isBlank(column)) {
                    if ("date_interviewed".equals(column)) {
                        if (ec.getDateInterviewed() != null) {
                            request.setAttribute("entityValue", dateFormatter.format(ec.getDateInterviewed()));
                        } else {
                            request.setAttribute("entityValue", resword.getString("N/A"));
                        }
                        request.setAttribute("entityName", resword.getString("date_interviewed"));
                    } else if ("interviewer_name".equals(column)) {
                        request.setAttribute("entityValue", ec.getInterviewerName());
                        request.setAttribute("entityName", resword.getString("interviewer_name"));
                    }
                }
            }

        }

        // finds all the related notes
        ArrayList notes = (ArrayList) dndao.findAllByEntityAndColumn(entityType, entityId, column);

        DiscrepancyNoteBean parent = new DiscrepancyNoteBean();
        if (parentId > 0) {
            dndao.setFetchMapping(true);
            parent = (DiscrepancyNoteBean) dndao.findByPK(parentId);
            if (parent.isActive()) {
                request.setAttribute("parent", parent);
            }
            dndao.setFetchMapping(false);
        }
        FormDiscrepancyNotes newNotes = (FormDiscrepancyNotes) session
                .getAttribute(AddNewSubjectServlet.FORM_DISCREPANCY_NOTES_NAME);

        if (newNotes == null) {
            newNotes = new FormDiscrepancyNotes();
        }
        boolean isNotesExistInSession = (!newNotes.getNotes(field).isEmpty()) ? true
                : (!newNotes.getNotes(eventCRFId + "_" + field).isEmpty()) ? true : false;
        if (!notes.isEmpty() || isNotesExistInSession) {
            request.setAttribute("hasNotes", "yes");
        } else {
            request.setAttribute("hasNotes", "no");
            logger.debug("has notes:" + "no");
        }

        //only for adding a new thread
        if (currentRole.getRole().equals(Role.RESEARCHASSISTANT)
                || currentRole.getRole().equals(Role.RESEARCHASSISTANT2)
                || currentRole.getRole().equals(Role.INVESTIGATOR)) {
            ArrayList<ResolutionStatus> resStatuses = new ArrayList<ResolutionStatus>();
            resStatuses.add(ResolutionStatus.OPEN);
            resStatuses.add(ResolutionStatus.RESOLVED);
            request.setAttribute(RES_STATUSES, resStatuses);
            List<DiscrepancyNoteType> types2 = new ArrayList<DiscrepancyNoteType>(DiscrepancyNoteType.list);
            types2.remove(DiscrepancyNoteType.QUERY);
            request.setAttribute(DIS_TYPES, types2);
            request.setAttribute(WHICH_RES_STATUSES, "22");
        } else if (currentRole.getRole().equals(Role.MONITOR)) {
            ArrayList<ResolutionStatus> resStatuses = new ArrayList();
            resStatuses.add(ResolutionStatus.OPEN);
            resStatuses.add(ResolutionStatus.UPDATED);
            resStatuses.add(ResolutionStatus.CLOSED);
            request.setAttribute(RES_STATUSES, resStatuses);
            request.setAttribute(WHICH_RES_STATUSES, "1");
            ArrayList<DiscrepancyNoteType> types2 = new ArrayList<DiscrepancyNoteType>();
            types2.add(DiscrepancyNoteType.QUERY);
            request.setAttribute(DIS_TYPES, types2);
        } else {//Role.STUDYDIRECTOR Role.COORDINATOR
            List<ResolutionStatus> resStatuses = new ArrayList<ResolutionStatus>(ResolutionStatus.list);
            resStatuses.remove(ResolutionStatus.NOT_APPLICABLE);
            request.setAttribute(RES_STATUSES, resStatuses);
            ;
            request.setAttribute(WHICH_RES_STATUSES, "2");
        }

        if (!fp.isSubmitted()) {
            DiscrepancyNoteBean dnb = new DiscrepancyNoteBean();

            if (subjectId > 0) {
                // BWP: this doesn't seem correct, because the SubjectId should
                // be the id for
                // the SubjectBean, different from StudySubjectBean
                StudySubjectDAO ssdao = new StudySubjectDAO(sm.getDataSource());
                StudySubjectBean ssub = (StudySubjectBean) ssdao.findByPK(subjectId);
                dnb.setSubjectName(ssub.getName());
                dnb.setSubjectId(ssub.getId());
                dnb.setStudySub(ssub);
                StudyDAO studyDAO = new StudyDAO(sm.getDataSource());
                int parentStudyForSubject = 0;
                StudyBean studyBeanSub = (StudyBean) studyDAO.findByPK(ssub.getStudyId());
                if (null != studyBeanSub) {
                    parentStudyForSubject = studyBeanSub.getParentStudyId();
                }
                if (ssub.getStudyId() != currentStudy.getId() && currentStudy.getId() != parentStudyForSubject) {
                    addPageMessage(noAccessMessage);
                    throw new InsufficientPermissionException(Page.MENU_SERVLET, exceptionName, "1");
                }

            }
            if (itemId > 0) {
                ItemBean item = (ItemBean) new ItemDAO(sm.getDataSource()).findByPK(itemId);
                dnb.setEntityName(item.getName());
                request.setAttribute("item", item);
            }
            dnb.setEntityType(entityType);
            dnb.setColumn(column);
            dnb.setEntityId(entityId);
            dnb.setField(field);
            dnb.setParentDnId(parent.getId());
            dnb.setCreatedDate(new Date());

            // When a user is performing Data Entry, Initial Data Entry or
            // Double Data Entry and
            // have not received any validation warnings or messages for a
            // particular item,
            // they will see Annotation as the default type in the Add
            // Discrepancy note window.

            // When a user is performing Data Entry, Initial Data Entry or
            // Double Data Entry and they
            // have received a validation warning or message for a particular
            // item,
            // they can click on the flag and the default type should be Failed
            // Validation Check

            // When a user is viewing a CRF and they click on the flag icon, the
            // default type should be query.

            // when the type is query, we should also get the user id for the
            // person who completed data entry

            /* Mantis issue: tbh 08/31/2009
             * 0004092: CRCs and Investigators allowed to close a Query
               CRCs and Investigators are allowed to choose Closed for a Query. they are also allowed to choose New.
                
               They should only be allowed to choose Updated or Resolution Proposed.
             */

            // above extra business rule here, tbh

            if (parent.getId() == 0 || isNew) {// no parent, new note thread
                if (enteringData) {
                    if (isInError) {
                        dnb.setDiscrepancyNoteTypeId(DiscrepancyNoteType.FAILEDVAL.getId());
                    } else {
                        dnb.setDiscrepancyNoteTypeId(DiscrepancyNoteType.ANNOTATION.getId());
                        dnb.setResolutionStatusId(ResolutionStatus.NOT_APPLICABLE.getId());
                        // >> tbh WHO bug: set an assigned user for the parent
                        // note
                        // dnb.setAssignedUser(ub);
                        // dnb.setAssignedUserId(ub.getId());
                        // << tbh 08/2009
                    }
                    if (isReasonForChange) {
                        dnb.setDiscrepancyNoteTypeId(DiscrepancyNoteType.REASON_FOR_CHANGE.getId());
                        dnb.setResolutionStatusId(ResolutionStatus.NOT_APPLICABLE.getId());
                    }
                    // << tbh 02/2010, trumps failed evaluation error checks
                    // can we put this in admin editing
                    request.setAttribute("autoView", "0");
                    // above set to automatically open up the user panel
                } else {
                    // when the user is a CRC and is adding a note to the thread
                    // it should default to Resolution Proposed,
                    // and the assigned should be the user who logged the query,
                    // NOT the one who is proposing the solution, tbh 02/2009
                    // if (currentRole.getRole().equals(Role.COORDINATOR)) {
                    // dnb.setDiscrepancyNoteTypeId(DiscrepancyNoteType.
                    // REASON_FOR_CHANGE.getId());
                    // request.setAttribute("autoView", "1");
                    // // above set to automatically open up the user panel
                    // } else {
                    dnb.setDiscrepancyNoteTypeId(DiscrepancyNoteType.QUERY.getId());
                    // remove this option for CRCs and Investigators
                    //if (currentRole.getRole().equals(Role.RESEARCHASSISTANT) && currentStudy.getId() != currentStudy.getParentStudyId()
                    if (currentRole.getRole().equals(Role.RESEARCHASSISTANT)
                            || currentRole.getRole().equals(Role.RESEARCHASSISTANT2)
                            || currentRole.getRole().equals(Role.INVESTIGATOR)) {
                        request.setAttribute("autoView", "0");
                    } else {
                        request.setAttribute("autoView", "1");
                        dnb.setAssignedUserId(preUserId);
                    }
                    // above set to automatically open up the user panel
                    // }
                }

            }

            else if (parent.getDiscrepancyNoteTypeId() > 0) {
                dnb.setDiscrepancyNoteTypeId(parent.getDiscrepancyNoteTypeId());

                // if it is a CRC then we should automatically propose a
                // solution, tbh

                // adding second rule here, tbh 08/2009
                if ((currentRole.getRole().equals(Role.RESEARCHASSISTANT)
                        || currentRole.getRole().equals(Role.RESEARCHASSISTANT2))
                        && currentStudy.getId() != currentStudy.getParentStudyId()) {
                    dnb.setResolutionStatusId(ResolutionStatus.RESOLVED.getId());
                    request.setAttribute("autoView", "0");
                    // hide the panel, tbh
                } else {
                    dnb.setResolutionStatusId(ResolutionStatus.UPDATED.getId());
                }

            }
            dnb.setOwnerId(parent.getOwnerId());
            String detailedDes = fp.getString("strErrMsg");
            if (detailedDes != null) {
                dnb.setDetailedNotes(detailedDes);
                logger.debug("found strErrMsg: " + fp.getString("strErrMsg"));
            }
            // #4346 TBH 10/2009

            //If the data entry form has not been saved yet, collecting info from parent page.
            dnb = getNoteInfo(dnb);// populate note infos
            if (dnb.getEventName() == null || dnb.getEventName().equals("")) {
                dnb.setEventName(fp.getString("eventName"));
            }
            if (dnb.getEventStart() == null) {
                dnb.setEventStart(fp.getDate("eventDate"));
            }
            if (dnb.getCrfName() == null || dnb.getCrfName().equals("")) {
                dnb.setCrfName(fp.getString("crfName"));
            }
            //            // #4346 TBH 10/2009
            request.setAttribute(DIS_NOTE, dnb);
            request.setAttribute("unlock", "0");
            request.setAttribute(WRITE_TO_DB, writeToDB ? "1" : "0");//this should go from UI & here
            ArrayList userAccounts = this.generateUserAccounts(ub.getActiveStudyId(), subjectId);
            request.setAttribute(USER_ACCOUNTS, userAccounts);

            // ideally should be only two cases
            if ((currentRole.getRole().equals(Role.RESEARCHASSISTANT)
                    || currentRole.getRole().equals(Role.RESEARCHASSISTANT2))
                    && currentStudy.getId() != currentStudy.getParentStudyId()) { // assigning back to OP, tbh
                request.setAttribute(USER_ACCOUNT_ID, Integer.valueOf(parent.getOwnerId()).toString());
                logger.debug("assigned owner id: " + parent.getOwnerId());
            } else if (dnb.getEventCRFId() > 0) {
                logger.debug("found a event crf id: " + dnb.getEventCRFId());
                EventCRFDAO eventCrfDAO = new EventCRFDAO(sm.getDataSource());
                EventCRFBean eventCrfBean = new EventCRFBean();
                eventCrfBean = (EventCRFBean) eventCrfDAO.findByPK(dnb.getEventCRFId());
                request.setAttribute(USER_ACCOUNT_ID, Integer.valueOf(eventCrfBean.getOwnerId()).toString());
                logger.debug("assigned owner id: " + eventCrfBean.getOwnerId());
            } else {
                // the end case

            }

            // set the user account id for the user who completed data entry
            forwardPage(Page.ADD_DISCREPANCY_NOTE);

        } else {
            FormDiscrepancyNotes noteTree = (FormDiscrepancyNotes) session
                    .getAttribute(AddNewSubjectServlet.FORM_DISCREPANCY_NOTES_NAME);
            FormDiscrepancyNotes noteTree_RFC_REPEAT = (FormDiscrepancyNotes) session
                    .getAttribute(FLAG_DISCREPANCY_RFC);
            ;

            if (noteTree_RFC_REPEAT == null)
                noteTree_RFC_REPEAT = new FormDiscrepancyNotes();

            if (noteTree == null) {
                noteTree = new FormDiscrepancyNotes();
                logger.debug("No note tree initailized in session");
            }

            Validator v = new Validator(request);
            String description = fp.getString("description");
            int typeId = fp.getInt("typeId");
            int assignedUserAccountId = fp.getInt(SUBMITTED_USER_ACCOUNT_ID);
            int resStatusId = fp.getInt(RES_STATUS_ID);
            String detailedDes = fp.getString("detailedDes");
            int sectionId = fp.getInt("sectionId");
            DiscrepancyNoteBean note = new DiscrepancyNoteBean();
            v.addValidation("description", Validator.NO_BLANKS);
            v.addValidation("description", Validator.LENGTH_NUMERIC_COMPARISON,
                    NumericComparisonOperator.LESS_THAN_OR_EQUAL_TO, 255);
            v.addValidation("detailedDes", Validator.LENGTH_NUMERIC_COMPARISON,
                    NumericComparisonOperator.LESS_THAN_OR_EQUAL_TO, 1000);

            v.addValidation("typeId", Validator.NO_BLANKS);

            HashMap errors = v.validate();
            note.setDescription(description);
            note.setDetailedNotes(detailedDes);
            note.setOwner(ub);
            note.setOwnerId(ub.getId());
            note.setCreatedDate(new Date());
            note.setResolutionStatusId(resStatusId);
            note.setDiscrepancyNoteTypeId(typeId);
            note.setParentDnId(parent.getId());

            if (typeId != DiscrepancyNoteType.ANNOTATION.getId() && typeId != DiscrepancyNoteType.FAILEDVAL.getId()
                    && typeId != DiscrepancyNoteType.REASON_FOR_CHANGE.getId()) {
                if (assignedUserAccountId > 0) {
                    note.setAssignedUserId(assignedUserAccountId);
                    logger.debug("^^^ found assigned user id: " + assignedUserAccountId);

                } else {
                    // a little bit of a workaround, should ideally be always from
                    // the form
                    note.setAssignedUserId(parent.getOwnerId());
                    logger.debug("found user assigned id, in the PARENT OWNER ID: " + parent.getOwnerId()
                            + " note that user assgined id did not work: " + assignedUserAccountId);
                }
            }

            note.setField(field);
            if (DiscrepancyNoteType.ANNOTATION.getId() == note.getDiscrepancyNoteTypeId()) {
                updateStudyEvent(entityType, entityId);
                updateStudySubjectStatus(entityType, entityId);
            }
            if (DiscrepancyNoteType.ANNOTATION.getId() == note.getDiscrepancyNoteTypeId()
                    || DiscrepancyNoteType.REASON_FOR_CHANGE.getId() == note.getDiscrepancyNoteTypeId()) {
                note.setResStatus(ResolutionStatus.NOT_APPLICABLE);
                note.setResolutionStatusId(ResolutionStatus.NOT_APPLICABLE.getId());
            }
            if (DiscrepancyNoteType.FAILEDVAL.getId() == note.getDiscrepancyNoteTypeId()
                    || DiscrepancyNoteType.QUERY.getId() == note.getDiscrepancyNoteTypeId()) {
                if (ResolutionStatus.NOT_APPLICABLE.getId() == note.getResolutionStatusId()) {
                    Validator.addError(errors, RES_STATUS_ID, restext.getString("not_valid_res_status"));
                }
            }

            if (!parent.isActive()) {
                note.setEntityId(entityId);
                note.setEntityType(entityType);
                note.setColumn(column);
            } else {
                note.setEntityId(parent.getEntityId());
                note.setEntityType(parent.getEntityType());
                if (!StringUtils.isBlank(parent.getColumn())) {
                    note.setColumn(parent.getColumn());
                } else {
                    note.setColumn(column);
                }
                note.setParentDnId(parent.getId());
            }

            note.setStudyId(currentStudy.getId());

            note = getNoteInfo(note);// populate note infos

            request.setAttribute(DIS_NOTE, note);
            request.setAttribute(WRITE_TO_DB, writeToDB ? "1" : "0");//this should go from UI & here
            ArrayList userAccounts = this.generateUserAccounts(ub.getActiveStudyId(), subjectId);

            request.setAttribute(USER_ACCOUNT_ID, Integer.valueOf(note.getAssignedUserId()).toString());
            // formality more than anything else, we should go to say the note
            // is done

            Role r = currentRole.getRole();
            if (r.equals(Role.MONITOR) || r.equals(Role.INVESTIGATOR) || r.equals(Role.RESEARCHASSISTANT)
                    || r.equals(Role.RESEARCHASSISTANT2) || r.equals(Role.COORDINATOR)) { // investigator
                request.setAttribute("unlock", "1");
                logger.debug("set UNLOCK to ONE");
            } else {
                request.setAttribute("unlock", "0");
                logger.debug("set UNLOCK to ZERO");
            }

            request.setAttribute(USER_ACCOUNTS, userAccounts);

            if (errors.isEmpty()) {

                if (!writeToDB) {
                    noteTree.addNote(field, note);
                    noteTree.addIdNote(note.getEntityId(), field);
                    noteTree_RFC_REPEAT.addNote(EVENT_CRF_ID + "_" + field, note);
                    noteTree_RFC_REPEAT.addIdNote(note.getEntityId(), field);

                    //-> catcher                //   FORM_DISCREPANCY_NOTES_NAME
                    session.setAttribute(AddNewSubjectServlet.FORM_DISCREPANCY_NOTES_NAME, noteTree);
                    session.setAttribute(FLAG_DISCREPANCY_RFC, noteTree_RFC_REPEAT);

                    //
                    /*Setting a marker to check later while saving administrative edited data. This is needed to make
                    * sure the system flags error while changing data for items which already has a DiscrepanyNote*/
                    manageReasonForChangeState(session, eventCRFId + "_" + field);
                    forwardPage(Page.ADD_DISCREPANCY_NOTE_DONE);
                } else {
                    // if not creating a new thread(note), update exsiting notes
                    // if necessary
                    //if ("itemData".equalsIgnoreCase(entityType) && !isNew) {
                    int pdnId = note != null ? note.getParentDnId() : 0;
                    if (pdnId > 0) {
                        logger.debug("Create:find parent note for item data:" + note.getEntityId());

                        DiscrepancyNoteBean pNote = (DiscrepancyNoteBean) dndao.findByPK(pdnId);

                        logger.debug("setting DN owner id: " + pNote.getOwnerId());

                        note.setOwnerId(pNote.getOwnerId());

                        if (note.getDiscrepancyNoteTypeId() == pNote.getDiscrepancyNoteTypeId()) {

                            if (note.getResolutionStatusId() != pNote.getResolutionStatusId()) {
                                pNote.setResolutionStatusId(note.getResolutionStatusId());
                                dndao.update(pNote);
                            }

                            if (note.getAssignedUserId() != pNote.getAssignedUserId()) {
                                pNote.setAssignedUserId(note.getAssignedUserId());
                                if (pNote.getAssignedUserId() > 0) {
                                    dndao.updateAssignedUser(pNote);
                                } else {
                                    dndao.updateAssignedUserToNull(pNote);
                                }
                            }

                        }

                    }
                    note = (DiscrepancyNoteBean) dndao.create(note);

                    dndao.createMapping(note);

                    request.setAttribute(DIS_NOTE, note);

                    if (note.getParentDnId() == 0) {
                        // see issue 2659 this is a new thread, we will create
                        // two notes in this case,
                        // This way one can be the parent that updates as the
                        // status changes, but one also stays as New.
                        note.setParentDnId(note.getId());
                        note = (DiscrepancyNoteBean) dndao.create(note);
                        dndao.createMapping(note);
                    }

                    /*Setting a marker to check later while saving administrative edited data. This is needed to make
                    * sure the system flags error while changing data for items which already has a DiscrepanyNote*/
                    //session.setAttribute(DataEntryServlet.NOTE_SUBMITTED, true);
                    //session.setAttribute(DataEntryServlet.NOTE_SUBMITTED, true);
                    // String field_id_for_RFC_hash = buildDiscrepancyNoteIdForRFCHash(eventCRFId,entityId, isGroup, field, ordinal_for_repeating_group_field);
                    String field_id_for_RFC_hash = eventCRFId + "_" + field;

                    manageReasonForChangeState(session, field_id_for_RFC_hash);

                    logger.debug("found resolution status: " + note.getResolutionStatusId());

                    String email = fp.getString(EMAIL_USER_ACCOUNT);

                    logger.debug("found email: " + email);
                    if (note.getAssignedUserId() > 0 && "1".equals(email.trim())
                            && DiscrepancyNoteType.QUERY.getId() == note.getDiscrepancyNoteTypeId()) {

                        logger.debug("++++++ found our way here: " + note.getDiscrepancyNoteTypeId()
                                + " id number and " + note.getDisType().getName());
                        // generate email for user here
                        StringBuffer message = new StringBuffer();

                        // generate message here
                        UserAccountDAO userAccountDAO = new UserAccountDAO(sm.getDataSource());
                        ItemDAO itemDAO = new ItemDAO(sm.getDataSource());
                        ItemDataDAO iddao = new ItemDataDAO(sm.getDataSource());
                        ItemBean item = new ItemBean();
                        ItemDataBean itemData = new ItemDataBean();
                        SectionBean section = new SectionBean();

                        StudyDAO studyDAO = new StudyDAO(sm.getDataSource());
                        UserAccountBean assignedUser = (UserAccountBean) userAccountDAO
                                .findByPK(note.getAssignedUserId());
                        String alertEmail = assignedUser.getEmail();
                        message.append(MessageFormat.format(respage.getString("mailDNHeader"),
                                assignedUser.getFirstName(), assignedUser.getLastName()));
                        message.append("<A HREF='" + SQLInitServlet.getField("sysURL.base")
                                + "ViewNotes?module=submit&listNotes_f_discrepancyNoteBean.user="
                                + assignedUser.getName() + "&listNotes_f_entityName=" + note.getEntityName() + "'>"
                                + SQLInitServlet.getField("sysURL.base") + "</A><BR/>");
                        message.append(respage.getString("you_received_this_from"));
                        StudyBean study = (StudyBean) studyDAO.findByPK(note.getStudyId());
                        SectionDAO sectionDAO = new SectionDAO(sm.getDataSource());

                        if ("itemData".equalsIgnoreCase(entityType)) {
                            itemData = (ItemDataBean) iddao.findByPK(note.getEntityId());
                            item = (ItemBean) itemDAO.findByPK(itemData.getItemId());
                            if (sectionId > 0) {
                                section = (SectionBean) sectionDAO.findByPK(sectionId);
                            } else {
                                //Todo section should be initialized when sectionId = 0
                            }
                        }

                        message.append(respage.getString("email_body_separator"));
                        message.append(respage.getString("disc_note_info"));
                        message.append(respage.getString("email_body_separator"));
                        message.append(MessageFormat.format(respage.getString("mailDNParameters1"),
                                note.getDescription(), note.getDetailedNotes(), ub.getName()));
                        message.append(respage.getString("email_body_separator"));
                        message.append(respage.getString("entity_information"));
                        message.append(respage.getString("email_body_separator"));
                        message.append(MessageFormat.format(respage.getString("mailDNParameters2"), study.getName(),
                                note.getSubjectName()));

                        if (!("studySub".equalsIgnoreCase(entityType) || "subject".equalsIgnoreCase(entityType))) {
                            message.append(MessageFormat.format(respage.getString("mailDNParameters3"),
                                    note.getEventName()));
                            if (!"studyEvent".equalsIgnoreCase(note.getEntityType())) {
                                message.append(MessageFormat.format(respage.getString("mailDNParameters4"),
                                        note.getCrfName()));
                                if (!"eventCrf".equalsIgnoreCase(note.getEntityType())) {
                                    if (sectionId > 0) {
                                        message.append(MessageFormat.format(respage.getString("mailDNParameters5"),
                                                section.getName()));
                                    }
                                    message.append(MessageFormat.format(respage.getString("mailDNParameters6"),
                                            item.getName()));
                                }
                            }
                        }

                        message.append(respage.getString("email_body_separator"));
                        message.append(MessageFormat.format(respage.getString("mailDNThanks"), study.getName()));
                        message.append(respage.getString("email_body_separator"));
                        message.append(respage.getString("disclaimer"));
                        message.append(respage.getString("email_body_separator"));
                        message.append(respage.getString("email_footer"));

                        String emailBodyString = message.toString();
                        sendEmail(alertEmail.trim(), EmailEngine.getAdminEmail(), MessageFormat
                                .format(respage.getString("mailDNSubject"), study.getName(), note.getEntityName()),
                                emailBodyString, true, null, null, true);

                    } else {
                        logger.debug("did not send email, but did save DN");
                    }
                    // addPageMessage(
                    // "Your discrepancy note has been saved into database.");
                    addPageMessage(respage.getString("note_saved_into_db"));
                    addPageMessage(respage.getString("page_close_automatically"));
                    forwardPage(Page.ADD_DISCREPANCY_NOTE_SAVE_DONE);
                }

            } else {
                if (parentId > 0) {
                    if (note.getResolutionStatusId() == ResolutionStatus.NOT_APPLICABLE.getId()) {
                        request.setAttribute("autoView", "0");
                    }
                } else {
                    if (note.getDiscrepancyNoteTypeId() == DiscrepancyNoteType.QUERY.getId()) {
                        request.setAttribute("autoView", "1");
                    } else {
                        request.setAttribute("autoView", "0");
                    }
                }
                setInputMessages(errors);
                forwardPage(Page.ADD_DISCREPANCY_NOTE);
            }

        }

    }

    /**
     * Constructs a url for creating new note on 'view note list' page
     *
     * @param note
     * @param preset
     * @return
     */
    public static String getAddChildURL(DiscrepancyNoteBean note, ResolutionStatus preset, boolean toView) {
        ArrayList<String> arguments = new ArrayList<String>();

        arguments.add(ENTITY_TYPE + "=" + note.getEntityType());
        arguments.add(ENTITY_ID + "=" + note.getEntityId());
        arguments.add(WRITE_TO_DB + "=" + "1");
        arguments.add("monitor" + "=" + 1);// of course, when resolving a note,
        // we have monitor privilege

        if (preset.isActive()) {
            arguments.add(PRESET_RES_STATUS + "=" + String.valueOf(preset.getId()));
        }

        if (toView) {
            // BWP 3/19/2009 3166: <<
            String columnValue = "".equalsIgnoreCase(note.getColumn()) ? "value" : note.getColumn();
            // >>
            arguments.add(ENTITY_COLUMN + "=" + columnValue);
            arguments.add(SUBJECT_ID + "=" + note.getSubjectId());
            arguments.add(ITEM_ID + "=" + note.getItemId());
            String queryString = StringUtil.join("&", arguments);
            return "ViewDiscrepancyNote?" + queryString;
        } else {
            arguments.add(PARENT_ID + "=" + note.getId());
            String queryString = StringUtil.join("&", arguments);
            return "CreateDiscrepancyNote?" + queryString;
        }
    }

    /**
     * Pulls the note related information from database according to note type
     *
     * @param note
     */

    private void updateStudySubjectStatus(String entityType, int entityId) {
        if ("itemData".equalsIgnoreCase(entityType)) {
            int itemDataId = entityId;
            ItemDataDAO iddao = new ItemDataDAO(sm.getDataSource());
            ItemDataBean itemData = (ItemDataBean) iddao.findByPK(itemDataId);
            EventCRFDAO ecdao = new EventCRFDAO(sm.getDataSource());
            StudyEventDAO svdao = new StudyEventDAO(sm.getDataSource());
            StudySubjectDAO studySubjectDAO = new StudySubjectDAO(sm.getDataSource());
            EventCRFBean ec = (EventCRFBean) ecdao.findByPK(itemData.getEventCRFId());
            StudyEventBean event = (StudyEventBean) svdao.findByPK(ec.getStudyEventId());
            StudySubjectBean studySubject = (StudySubjectBean) studySubjectDAO.findByPK(event.getStudySubjectId());
            if (studySubject.getStatus() != null && studySubject.getStatus().equals(Status.SIGNED)) {
                studySubject.setStatus(Status.AVAILABLE);
                studySubject.setUpdater(ub);
                studySubject.setUpdatedDate(new Date());
                studySubjectDAO.update(studySubject);
            }
            if (ec.isSdvStatus()) {
                studySubject.setStatus(Status.AVAILABLE);
                studySubject.setUpdater(ub);
                studySubject.setUpdatedDate(new Date());
                studySubjectDAO.update(studySubject);
                ec.setSdvStatus(false);
                ec.setSdvUpdateId(ub.getId());
                ecdao.update(ec);
            }

        }
    }

    private ArrayList generateUserAccounts(int studyId, int subjectId) {
        UserAccountDAO userAccountDAO = new UserAccountDAO(sm.getDataSource());
        StudyDAO studyDAO = new StudyDAO(sm.getDataSource());
        StudyBean subjectStudy = studyDAO.findByStudySubjectId(subjectId);
        // study id, tbh 03/2009
        ArrayList userAccounts = new ArrayList();
        if (currentStudy.getParentStudyId() > 0) {
            userAccounts = userAccountDAO.findAllUsersByStudyOrSite(studyId, currentStudy.getParentStudyId(),
                    subjectId);
        } else if (subjectStudy.getParentStudyId() > 0) {
            userAccounts = userAccountDAO.findAllUsersByStudyOrSite(subjectStudy.getId(),
                    subjectStudy.getParentStudyId(), subjectId);
        } else {
            userAccounts = userAccountDAO.findAllUsersByStudyOrSite(studyId, 0, subjectId);
        }
        return userAccounts;
    }

    private void updateStudyEvent(String entityType, int entityId) {
        if ("itemData".equalsIgnoreCase(entityType)) {
            int itemDataId = entityId;
            ItemDataDAO iddao = new ItemDataDAO(sm.getDataSource());
            ItemDataBean itemData = (ItemDataBean) iddao.findByPK(itemDataId);
            EventCRFDAO ecdao = new EventCRFDAO(sm.getDataSource());
            StudyEventDAO svdao = new StudyEventDAO(sm.getDataSource());
            EventCRFBean ec = (EventCRFBean) ecdao.findByPK(itemData.getEventCRFId());
            StudyEventBean event = (StudyEventBean) svdao.findByPK(ec.getStudyEventId());
            if (event.getSubjectEventStatus().equals(SubjectEventStatus.SIGNED)) {
                event.setSubjectEventStatus(SubjectEventStatus.COMPLETED);
                event.setUpdater(ub);
                event.setUpdatedDate(new Date());
                svdao.update(event);
            }
        } else if ("eventCrf".equalsIgnoreCase(entityType)) {
            int eventCRFId = entityId;
            EventCRFDAO ecdao = new EventCRFDAO(sm.getDataSource());
            StudyEventDAO svdao = new StudyEventDAO(sm.getDataSource());

            EventCRFBean ec = (EventCRFBean) ecdao.findByPK(eventCRFId);
            StudyEventBean event = (StudyEventBean) svdao.findByPK(ec.getStudyEventId());
            if (event.getSubjectEventStatus().equals(SubjectEventStatus.SIGNED)) {
                event.setSubjectEventStatus(SubjectEventStatus.COMPLETED);
                event.setUpdater(ub);
                event.setUpdatedDate(new Date());
                svdao.update(event);
            }
        }
    }

    private void manageReasonForChangeState(HttpSession session, String itemDataBeanId) {
        @SuppressWarnings("unchecked")
        HashMap<String, Boolean> noteSubmitted = (HashMap<String, Boolean>) session
                .getAttribute(DataEntryServlet.NOTE_SUBMITTED);
        if (noteSubmitted == null) {
            noteSubmitted = new HashMap<String, Boolean>();
        }
        noteSubmitted.put(itemDataBeanId, Boolean.TRUE);
        session.setAttribute(DataEntryServlet.NOTE_SUBMITTED, noteSubmitted);
    }

    /*
     * @return 0 - not defined; 1 - yes, -1 - no
     * 
     */
    private int isWriteToDB(int isGroup, String field, int item_data_id, int item_id,
            int ordinal_for_repeating_group_field, int event_crf_id) {
        if (item_data_id > 0 && isGroup == -1) {//non repeating group; coming from showItemInput.jsp
            return 1;
        } else if (item_data_id < 0 && isGroup == -1) {//non repeating group; coming from showItemInput.jsp
            return -1;
        } else if (isGroup == 1) {// repeating group; 
            //initial data entry or if template cell is empty (last row)
            if (item_data_id < 0) {
                return -1;
            }
            if (item_data_id > 0) {
                // first row IG_TEST__GROUP1_6727_0input320
                // row without X     IG_TEST__GROUP1_6727_manual1input320
                // row with X         IG_TEST__GROUP1_6727_1input320
                if (field.contains("_0input") || field.contains("manual")) {
                    //get ordinal
                    ItemDataDAO iddao = new ItemDataDAO(sm.getDataSource(), locale);

                    boolean isExistInDB = iddao.isItemExists(item_id, ordinal_for_repeating_group_field,
                            event_crf_id);
                    return (isExistInDB) ? 1 : -1;
                } else if (field.contains("input")) {
                    return -1;
                }
            }
        }
        return 0;
    }

    public int calculateOrdinal(int isGroup, String field_name, int event_crf_id, int rowCount) {
        // first row IG_TEST__GROUP1_6727_0input320
        // row without X     IG_TEST__GROUP1_6727_manual1input320
        // row with X         IG_TEST__GROUP1_6727_1input320
        int ordinal = 0;
        int start = -1;
        int end = -1;
        if (isGroup == -1) {
            return 1;
        }
        if (field_name.contains("_0input")) {
            return 1;
        }
        try {
            if (field_name.contains("manual")) {
                start = field_name.indexOf("manual") + 5;
                end = field_name.indexOf("input");
                if (start == 4 || end == -1) {
                    return 0;
                }
                ordinal = Integer.valueOf(field_name.substring(start + 1, end));
                return ordinal + 1;

            } else {
                //get max ordinal from DB
                ItemDataDAO iddao = new ItemDataDAO(sm.getDataSource(), locale);
                //IG_TEST__GROUP1_6727_manual1input320
                String[] field_name_items = field_name.split("_");

                String group_oid = field_name.substring(0,
                        field_name.indexOf(field_name_items[field_name_items.length - 1]) - 1);
                int maxOrdinal = iddao.getMaxOrdinalForGroupByGroupOID(group_oid, event_crf_id);

                //get ordinal from field
                end = field_name.indexOf("input");
                start = field_name.lastIndexOf("_");
                if (end == -1 || start == -1) {
                    return 0;
                }
                ordinal = Integer.valueOf(field_name.substring(start + 1, end));
                return ordinal + maxOrdinal + rowCount;
            }
        } catch (NumberFormatException e) {
            //DO NOTHING
        }

        return ordinal;

    }

    ///place holder

    //this method should recalculate the ordinals
}