package gov.va.vinci.dart.rule;

import gov.va.vinci.dart.biz.DartRequest;
import gov.va.vinci.dart.biz.DataSource;
import gov.va.vinci.dart.biz.DocumentTemplate;
import gov.va.vinci.dart.biz.Group;
import gov.va.vinci.dart.biz.Location;
import gov.va.vinci.dart.biz.OperationalRequest;
import gov.va.vinci.dart.biz.Participant;
import gov.va.vinci.dart.biz.PreparatoryRequest;
import gov.va.vinci.dart.biz.Request;


/**
 * Abstract expert system rule.
 *
 */
public abstract class AbstractDocumentRuleEvaluator implements DocumentRuleEvaluator {

    /** The Constant PREPARATORY_TO_RESEARCH_MEMORANDUM. */
    protected static final String PREPARATORY_TO_RESEARCH_MEMORANDUM = "Preparatory to Research Memorandum";

    /** The Constant DART_ORD_ADMINISTRATORS. */
    protected static final String DART_ORD_ADMINISTRATORS = "DART ORD Administrators";

    /** The Constant ORD_9957. */
    protected static final String ORD_9957 = "ORD 9957";

    /** The Constant DART_PRIVACY_ADMINISTRATORS. */
    protected static final String DART_PRIVACY_ADMINISTRATORS = "DART Privacy Administrators";

    /** The Constant RESEARCH_PRIVACY_REVIEW_CHECKLIST. */
    protected static final String RESEARCH_PRIVACY_REVIEW_CHECKLIST = "Research Privacy Review Checklist";

    /** The Constant DART_NDS_ADMINISTRATORS. */
    protected static final String DART_NDS_ADMINISTRATORS = "DART NDS Administrators";

    /** The Constant NDS_DATA_USE_AGREEMENT. */
    protected static final String NDS_DATA_USE_AGREEMENT = "NDS Data Use Agreement";

    /** The Constant RESEARCH_STUDY_INSTITUTIONAL_REVIEW_BOARD_IRB_APPROVAL. */
    protected static final String RESEARCH_STUDY_INSTITUTIONAL_REVIEW_BOARD_IRB_APPROVAL =
            "Research Study Institutional Review Board (IRB) Approval";

    /** The Constant RESEARCH_AND_DEVELOPMENT_RD_COMMITTEE_APPROVAL. */
    protected static final String RESEARCH_AND_DEVELOPMENT_RD_COMMITTEE_APPROVAL =
            "Research and Development (RD) Committee Approval";

    /** The Constant IRB_APPROVAL_OF_WAIVER_OF_HIPAA. */
    protected static final String IRB_APPROVAL_OF_WAIVER_OF_HIPAA = "IRB Approval of Waiver of HIPAA";

    /** The Constant RESEARCH_REQUEST_MEMO. */
    protected static final String RESEARCH_REQUEST_MEMO = "Research Request Memo";

    /** The Constant SAMPLE_INFORMED_CONSENT. */
    protected static final String SAMPLE_INFORMED_CONSENT = "Sample Informed Consent";

    /** The Constant DATA_USE_AGREEMENT. */
    protected static final String DATA_USE_AGREEMENT = "Data Use Agreement";

    /** The Constant RESEARCH_PROTOCOL. */
    protected static final String RESEARCH_PROTOCOL = "Research Protocol";

    /** The Constant REAL_SSN_ACCESS_REQUEST. */
    protected static final String REAL_SSN_ACCESS_REQUEST = "Real SSN Access Request";

    /**
     * Is a specific document required for a location?
     * 
     * Here's the rules: For a DART request, the following documents are required for all sites. 1) Research and Development
     * (RD) Committee Approval 2) Research Study Institutional Review Board (IRB) Approval
     * 
     * The following documents are required for all sites if the requestor indicated that a HIPAA waiver is required 1) IRB
     * Approval of Waiver of HIPAA
     * 
     * The following documents are required for all primary sites. 1) Research Request Memo 2) Data Use Agreement 3) Research
     * Protocol
     * 
     * The following document is required of all primary sites if the requestor indicated a HIPAA consent form is required. 1)
     * Sample Informed Consent
     *
     * @param request
     *            the request
     * @param dataSource
     *            the data source
     * @param documentTemplate
     *            the document template
     * @param location
     *            the location
     * @param isIndependentOnly
     *            the is independent only
     * @return true, if is required
     */
    @Override
    public boolean isRequired(final Request request, final DataSource dataSource, final DocumentTemplate documentTemplate,
            final Location location, final boolean isIndependentOnly) {

        if (request == null) {
            return false;
        }

        Location primarySite = request.getPrimaryLocation();

        if (isDartRequest(request)) {
            if (isRequiredByDartRequest(request, documentTemplate, location, isIndependentOnly, primarySite)) {
                return true;
            }
        } else if (isPreparatoryRequest(request)) {

            if (primarySite != null) {

                // Research Request Memo is required for the primary site
                if (documentTemplate.getName().startsWith(PREPARATORY_TO_RESEARCH_MEMORANDUM)
                        && location.getId() == primarySite.getId()) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Checks if is required by dart request.
     *
     * @param request
     *            the request
     * @param documentTemplate
     *            the document template
     * @param location
     *            the location
     * @param isIndependentOnly
     *            the is independent only
     * @param primarySite
     *            the primary site
     * @return true, if is required by dart request
     */
    private boolean isRequiredByDartRequest(final Request request, final DocumentTemplate documentTemplate,
            final Location location, final boolean isIndependentOnly, Location primarySite) {
        DartRequest dartRequest = (DartRequest) request;

        // IRB Approval of Waiver of HIPAA is required of all sites if the HIPAA waiver is true
        if (documentTemplate.getName().startsWith(IRB_APPROVAL_OF_WAIVER_OF_HIPAA) && dartRequest.isHipaaWaiver()) {
            return true;
        }

        // Research and Development (RD) Committee Approval is required of all sites
        if (documentTemplate.getName().startsWith(RESEARCH_AND_DEVELOPMENT_RD_COMMITTEE_APPROVAL)) {
            return true;
        }

        // Research Study Institutional Review Board (IRB) Approval is required of all sites
        if (documentTemplate.getName().startsWith(RESEARCH_STUDY_INSTITUTIONAL_REVIEW_BOARD_IRB_APPROVAL)) {
            return true;
        }

        if (primarySite != null) {
            if (isRequiredByPrimarySite(documentTemplate, location, isIndependentOnly, primarySite, dartRequest)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks if is required by primary site.
     *
     * @param documentTemplate
     *            the document template
     * @param location
     *            the location
     * @param isIndependentOnly
     *            the is independent only
     * @param primarySite
     *            the primary site
     * @param dartRequest
     *            the dart request
     * @return true, if is required by primary site
     */
    private boolean isRequiredByPrimarySite(final DocumentTemplate documentTemplate, final Location location,
            final boolean isIndependentOnly, Location primarySite, DartRequest dartRequest) {

        if (location.getId() == primarySite.getId()) {
            // Research Request Memo is required for the primary site
            if (documentTemplate.getName().startsWith(RESEARCH_REQUEST_MEMO)) {
                return true;
            }

            // Sample Informed Consent is required for the primary site if the HIPAA patient consent is true
            if (documentTemplate.getName().startsWith(SAMPLE_INFORMED_CONSENT) && dartRequest.isHipaaConsent()) {
                return true;
            }

            // As per DUA document item 1.10, include DUA if transferredexternal = true
            // Data Use Agreement is required for the primary site
            if (documentTemplate.getName().startsWith(DATA_USE_AGREEMENT) && dartRequest.isTransferredExternal()) {
                return true;
            }

            // Research Protocol is required for the primary site
            if (documentTemplate.getName().startsWith(RESEARCH_PROTOCOL)) {
                return true;
            }

            // As of 8/13/2014 (Real SSN BRD item 1.2):
            // Real SSN Access Request is required for the primary site, if realSSN is selected
            if (documentTemplate.getName().startsWith(REAL_SSN_ACCESS_REQUEST) && dartRequest.isRealSSN()) {

                // As of 2/25/2015: Real SSN Access Request no longer required for any Independent Approver Workflow
                // if( dartRequest.getWorkflowTypeId() == WorkflowResolver.WF_NDS ) {
                if (!isIndependentOnly) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Is a specific document required for a participant? Here's the rules:
     * 
     * The following documents are required for all participants if they are principal investigators or if they have data access
     * 1) VA Form 9957.
     *
     * @param req
     *            the req
     * @param ds
     *            the ds
     * @param temp
     *            the temp
     * @param participant
     *            the participant
     * @param isIndependentOnly
     *            the is independent only
     * @return true, if is required
     */
    @Override
    public boolean isRequired(final Request req, final DataSource ds, final DocumentTemplate temp,
            final Participant participant, final boolean isIndependentOnly) {

        return false;
    }

    /**
     * Is a specific administrator document required for a site?
     * 
     * Here's the rules:
     * 
     * The following documents are required for all primary sites. for the NDS Admin group 1) NDS Data Use Agreement
     * 
     * The following documents are required for all primary sites. for the privacy group 1) Research Privacy Review Checklist
     *
     * @param req
     *            the req
     * @param ds
     *            the ds
     * @param temp
     *            the temp
     * @param admin
     *            the admin
     * @param site
     *            the site
     * @param isIndependentOnly
     *            the is independent only
     * @return true, if is required
     */
    @Override
    public boolean isRequired(final Request req, final DataSource ds, final DocumentTemplate temp, final Group admin,
            final Location site, final boolean isIndependentOnly) {

        Location primarySite = req.getPrimaryLocation();
        if (primarySite != null) {

            // NDS Data Use Agreement is required from NDS for the primary site
            if (temp.getName().startsWith(NDS_DATA_USE_AGREEMENT) && primarySite.getId() == site.getId()
                    && admin.getName().equals(DART_NDS_ADMINISTRATORS)) {
                return true;
            }

            // Research Privacy Review Checklist is required from Privacy for the primary site
            if (temp.getName().startsWith(RESEARCH_PRIVACY_REVIEW_CHECKLIST) && primarySite.getId() == site.getId()
                    && admin.getName().equals(DART_PRIVACY_ADMINISTRATORS)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Is a specific administrator document required for a participant?
     * 
     * Here's the rules:
     * 
     * The following documents are required for all principal investigators in primary sites for the ORD group 1) ORD 9957.
     *
     * @param req
     *            the req
     * @param ds
     *            the ds
     * @param temp
     *            the temp
     * @param admin
     *            the admin
     * @param participant
     *            the participant
     * @param isIndependentOnly
     *            the is independent only
     * @return true, if is required
     */
    @Override
    public boolean isRequired(final Request req, final DataSource ds, final DocumentTemplate temp, final Group admin,
            final Participant participant, final boolean isIndependentOnly) {
        Participant primarySitePrimaryInvestigator = null;

        Location primarySite = req.getPrimaryLocation();
        if (primarySite != null) {

            for (Participant part : req.getParticipants()) {
                if (part.getPrincipalInvestigator() && part.getLocation().getId() == primarySite.getId()) {
                    primarySitePrimaryInvestigator = part;
                    break;
                }
            }

            if (primarySitePrimaryInvestigator != null) {

                // Note: as of 3/1, they don't want to require the Data Access Agreement
                // // VHA Privacy DAA is required from NDS for the primary investigator at the primary site
                // if (temp.getName().startsWith("VHA Privacy DAA") && primarySitePrimaryInvestigator.getId() ==
                // participant.getId() && admin.getName().equals("DART NDS Administrators")) {
                // return true;
                // }

                // ORD 9957 is required from ORD for the primary investigator at the primary site
                if (temp.getName().startsWith(ORD_9957) && primarySitePrimaryInvestigator.getId() == participant.getId()
                        && admin.getName().equals(DART_ORD_ADMINISTRATORS)) {
                    return true;
                }
            }

        }// end if

        return false;
    }

    /**
     * Find the primary investigator for the primary site for a request.
     *
     * @param req
     *            the req
     * @return the primary site primary investigator
     */
    protected Participant getPrimarySitePrimaryInvestigator(final Request req) {
        Participant primarySitePrimaryInvestigator = null;

        Location primarySite = req.getPrimaryLocation();
        if (primarySite != null) {

            for (Participant part : req.getParticipants()) {
                if (part.getPrincipalInvestigator() && part.getLocation().getId() == primarySite.getId()) {
                    primarySitePrimaryInvestigator = part;
                    break;
                }
            }

        }// end if

        return primarySitePrimaryInvestigator;
    }

    /**
     * Checks if is dart request.
     *
     * @param req
     *            the req
     * @return true, if is dart request
     */
    protected static boolean isDartRequest(final Request req) {
        return DartRequest.class.isAssignableFrom(req.getClass());
    }

    /**
     * Checks if is operational request.
     *
     * @param req
     *            the req
     * @return true, if is operational request
     */
    protected static boolean isOperationalRequest(final Request req) {
        return OperationalRequest.class.isAssignableFrom(req.getClass());
    }

    /**
     * method isPreparatoryRequest.
     * 
     * @param req
     *            - the request
     * @return boolean - true if request type is Preparatory
     */
    protected static boolean isPreparatoryRequest(final Request req) {
        return PreparatoryRequest.class.isAssignableFrom(req.getClass());
    }

}
