package gov.va.vinci.dart.wf2;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import gov.va.vinci.dart.biz.Request;
import gov.va.vinci.dart.biz.RequestWorkflow;

/**
 * A resolver to find the appropriate workflow handler for a VINCI DART Request.
 * 
 */
@Service
public final class WorkflowResolver {

    /** The wfnds. */
    @Autowired
    private WfNDS wfnds;
    
    /** The wfoperationalrequest. */
    @Autowired
    private WfOperationalRequest wfoperationalrequest;
    
    /** The wfresearch request. */
    @Autowired
    private WfResearchRequest wfresearchRequest;
    
    /** The wf preparatory request. */
    @Autowired
    private WfPreparatoryRequest wfPreparatoryRequest;
    
    /** The wfindependent. */
    @Autowired
    private WfIndependent wfindependent;
    
    /** The Constant WF_OPERATIONAL_REQUEST. Constant values that appear in request.workflowId. */
    public static final int WF_OPERATIONAL_REQUEST = 1;
    
    /** The Constant WF_NDS. */
    public static final int WF_NDS = 2;
    
    /** The Constant WF_RESEARCH_REQUEST. */
    public static final int WF_RESEARCH_REQUEST = 3;
    
    /** The Constant WF_INDEPENDENT. */
    public static final int WF_INDEPENDENT = 4;
    
    /** The Constant WF_PREPARATORY_REQUEST. */
    public static final int WF_PREPARATORY_REQUEST = 5;

    /**
     * Find the appropriate workflow for a specific request (top-level workflow).
     *
     * @param request the request
     * @return Workflow
     * @throws WorkflowException the workflow exception
     */
    public Workflow resolve(final Request request) throws WorkflowException {

        if (request == null) {
            throw new WorkflowException("Error: cannot resolve the workflow type for a null request.");
        }// end if

        
        int key = request.getWorkflowTypeId(); // top-level workflow type
        // TODO note that if the workflow handlers have autowired member variables,
        // they should be autowired here as singleton beans.
        switch (key) {
        case WF_OPERATIONAL_REQUEST:
            return wfoperationalrequest;

        case WF_NDS:
            return wfnds;

        case WF_RESEARCH_REQUEST:
            return wfresearchRequest;

        case WF_INDEPENDENT:
            return wfindependent;

        case WF_PREPARATORY_REQUEST:
            return wfPreparatoryRequest;

        default:
            throw new WorkflowException("Error: unknown workflow type " + key);
        }
    }

    /**
     * Find the appropriate workflow engine for the specified workflow business object (child workflow).
     *
     * @param workflow the workflow
     * @return Workflow
     * @throws WorkflowException the workflow exception
     */
    public final Workflow resolve(final RequestWorkflow workflow) throws WorkflowException {

        if (workflow == null || workflow.getWorkflowTemplate() == null) {
            throw new WorkflowException("Error: cannot resolve the workflow type for a null object.");
        }// end if

        int key = workflow.getWorkflowTemplate().getWorkflowTypeId(); // workflow type

        // note that if the workflow handlers have autowired member variables,
        // they should be autowired here as singleton beans.
        switch (key) {
        case WF_OPERATIONAL_REQUEST:
            return wfoperationalrequest;

        case WF_NDS:
            return wfnds;

        case WF_RESEARCH_REQUEST:
            return wfresearchRequest;

        case WF_INDEPENDENT:
            return wfindependent;

        case WF_PREPARATORY_REQUEST:
            return wfPreparatoryRequest;

        default:
            throw new WorkflowException("Error: unknown workflow type " + key);
        }

    }

    /**
     * Gets the wfnds.
     *
     * @return the wfnds
     */
    public WfNDS getWfnds() {
        return wfnds;
    }

    /**
     * Sets the wfnds.
     *
     * @param wfnds the new wfnds
     */
    public void setWfnds(WfNDS wfnds) {
        this.wfnds = wfnds;
    }

    /**
     * Gets the wfoperationalrequest.
     *
     * @return the wfoperationalrequest
     */
    public WfOperationalRequest getWfoperationalrequest() {
        return wfoperationalrequest;
    }

    /**
     * Sets the wfoperationalrequest.
     *
     * @param wfoperationalrequest the new wfoperationalrequest
     */
    public void setWfoperationalrequest(WfOperationalRequest wfoperationalrequest) {
        this.wfoperationalrequest = wfoperationalrequest;
    }

    /**
     * Gets the wfresearch request.
     *
     * @return the wfresearch request
     */
    public WfResearchRequest getWfresearchRequest() {
        return wfresearchRequest;
    }

    /**
     * Sets the wfresearch request.
     *
     * @param wfresearchRequest the new wfresearch request
     */
    public void setWfresearchRequest(WfResearchRequest wfresearchRequest) {
        this.wfresearchRequest = wfresearchRequest;
    }

    /**
     * Gets the wfindependent.
     *
     * @return the wfindependent
     */
    public WfIndependent getWfindependent() {
        return wfindependent;
    }

    /**
     * Sets the wfindependent.
     *
     * @param wfindependent the new wfindependent
     */
    public void setWfindependent(WfIndependent wfindependent) {
        this.wfindependent = wfindependent;
    }

    /**
     * Gets the wf preparatory request.
     *
     * @return the wf preparatory request
     */
    public WfPreparatoryRequest getWfPreparatoryRequest() {
        return wfPreparatoryRequest;
    }

    /**
     * Sets the wf preparatory request.
     *
     * @param wfPreparatoryRequest the new wf preparatory request
     */
    public void setWfPreparatoryRequest(WfPreparatoryRequest wfPreparatoryRequest) {
        this.wfPreparatoryRequest = wfPreparatoryRequest;
    }
}
