/**
   * Return the workflow item to the workspace of the submitter. The workflow item is removed, and a
   * workspace item created.
   *
   * @param c Context
   * @param wfi WorkflowItem to be 'dismantled'
   * @return the workspace item
   */
  protected WorkspaceItem returnToWorkspace(Context c, BasicWorkflowItem wfi)
      throws SQLException, IOException, AuthorizeException {
    // FIXME: How should this interact with the workflow system?
    // FIXME: Remove license
    // FIXME: Provenance statement?
    // Create the new workspace item row
    WorkspaceItem workspaceItem = workspaceItemService.create(c, wfi);

    workspaceItem.setMultipleFiles(wfi.hasMultipleFiles());
    workspaceItem.setMultipleTitles(wfi.hasMultipleTitles());
    workspaceItem.setPublishedBefore(wfi.isPublishedBefore());
    workspaceItemService.update(c, workspaceItem);

    // myitem.update();
    log.info(
        LogManager.getHeader(
            c,
            "return_to_workspace",
            "workflow_item_id=" + wfi.getID() + "workspace_item_id=" + workspaceItem.getID()));

    // Now remove the workflow object manually from the database
    workflowItemService.deleteWrapper(c, wfi);

    return workspaceItem;
  }
  @Override
  public WorkspaceItem abort(Context c, XmlWorkflowItem wi, EPerson e)
      throws AuthorizeException, SQLException, IOException {
    if (!authorizeService.isAdmin(c)) {
      throw new AuthorizeException("You must be an admin to abort a workflow");
    }

    c.turnOffAuthorisationSystem();
    // Restore permissions for the submitter
    // convert into personal workspace
    WorkspaceItem wsi = returnToWorkspace(c, wi);

    log.info(
        LogManager.getHeader(
            c,
            "abort_workflow",
            "workflow_item_id="
                + wi.getID()
                + "item_id="
                + wsi.getItem().getID()
                + "collection_id="
                + wi.getCollection().getID()
                + "eperson_id="
                + e.getID()));

    c.restoreAuthSystemState();
    return wsi;
  }
  @Override
  public BasicWorkflowItem startWithoutNotify(Context c, WorkspaceItem wsi)
      throws SQLException, AuthorizeException, IOException {
    // make a hash table entry with item ID for no notify
    // notify code checks no notify hash for item id
    noEMail.put(wsi.getItem().getID(), Boolean.TRUE);

    return start(c, wsi);
  }
  /**
   * Return the workflow item to the workspace of the submitter. The workflow item is removed, and a
   * workspace item created.
   *
   * @param c Context
   * @param wfi WorkflowItem to be 'dismantled'
   * @return the workspace item
   * @throws java.io.IOException ...
   * @throws java.sql.SQLException ...
   * @throws org.dspace.authorize.AuthorizeException ...
   */
  protected WorkspaceItem returnToWorkspace(Context c, XmlWorkflowItem wfi)
      throws SQLException, IOException, AuthorizeException {
    // authorize a DSpaceActions.REJECT
    // stop workflow
    deleteAllTasks(c, wfi);

    c.turnOffAuthorisationSystem();
    // Also clear all info for this step
    workflowRequirementsService.clearInProgressUsers(c, wfi);

    // Remove (if any) the workflowItemroles for this item
    workflowItemRoleService.deleteForWorkflowItem(c, wfi);

    Item myitem = wfi.getItem();
    // Restore permissions for the submitter
    grantUserAllItemPolicies(c, myitem, myitem.getSubmitter());

    // FIXME: How should this interact with the workflow system?
    // FIXME: Remove license
    // FIXME: Provenance statement?
    // Create the new workspace item row
    WorkspaceItem workspaceItem = workspaceItemService.create(c, wfi);
    workspaceItem.setMultipleFiles(wfi.hasMultipleFiles());
    workspaceItem.setMultipleTitles(wfi.hasMultipleTitles());
    workspaceItem.setPublishedBefore(wfi.isPublishedBefore());
    workspaceItemService.update(c, workspaceItem);

    // myitem.update();
    log.info(
        LogManager.getHeader(
            c,
            "return_to_workspace",
            "workflow_item_id=" + wfi.getID() + "workspace_item_id=" + workspaceItem.getID()));

    // Now remove the workflow object manually from the database
    xmlWorkflowItemService.deleteWrapper(c, wfi);
    return workspaceItem;
  }
  @Override
  public XmlWorkflowItem start(Context context, WorkspaceItem wsi)
      throws SQLException, AuthorizeException, IOException, WorkflowException {
    try {
      Item myitem = wsi.getItem();
      Collection collection = wsi.getCollection();
      Workflow wf = xmlWorkflowFactory.getWorkflow(collection);

      XmlWorkflowItem wfi = xmlWorkflowItemService.create(context, myitem, collection);
      wfi.setMultipleFiles(wsi.hasMultipleFiles());
      wfi.setMultipleTitles(wsi.hasMultipleTitles());
      wfi.setPublishedBefore(wsi.isPublishedBefore());
      xmlWorkflowItemService.update(context, wfi);
      removeUserItemPolicies(context, myitem, myitem.getSubmitter());
      grantSubmitterReadPolicies(context, myitem);

      context.turnOffAuthorisationSystem();
      Step firstStep = wf.getFirstStep();
      if (firstStep.isValidStep(context, wfi)) {
        activateFirstStep(context, wf, firstStep, wfi);
      } else {
        // Get our next step, if none is found, archive our item
        firstStep = wf.getNextStep(context, wfi, firstStep, ActionResult.OUTCOME_COMPLETE);
        if (firstStep == null) {
          archive(context, wfi);
        } else {
          activateFirstStep(context, wf, firstStep, wfi);
        }
      }
      // remove the WorkspaceItem
      workspaceItemService.deleteWrapper(context, wsi);
      context.restoreAuthSystemState();
      return wfi;
    } catch (WorkflowConfigurationException e) {
      throw new WorkflowException(e);
    }
  }
  @Override
  public BasicWorkflowItem start(Context context, WorkspaceItem wsi)
      throws SQLException, AuthorizeException, IOException {
    // FIXME Check auth
    Item myitem = wsi.getItem();
    Collection collection = wsi.getCollection();

    log.info(
        LogManager.getHeader(
            context,
            "start_workflow",
            "workspace_item_id="
                + wsi.getID()
                + "item_id="
                + myitem.getID()
                + "collection_id="
                + collection.getID()));

    // record the start of the workflow w/provenance message
    recordStart(context, myitem);

    // create the WorkflowItem
    BasicWorkflowItem wfi = workflowItemService.create(context, myitem, collection);
    wfi.setMultipleFiles(wsi.hasMultipleFiles());
    wfi.setMultipleTitles(wsi.hasMultipleTitles());
    wfi.setPublishedBefore(wsi.isPublishedBefore());

    // remove the WorkspaceItem
    workspaceItemService.deleteWrapper(context, wsi);

    // now get the workflow started
    wfi.setState(WFSTATE_SUBMIT);
    advance(context, wfi, null);

    // Return the workflow item
    return wfi;
  }
  @Override
  public void addInitialWorkspaceItemPolicies(Context context, WorkspaceItem workspaceItem)
      throws SQLException, AuthorizeException {
    // Now create the policies for the submitter and workflow
    // users to modify item and contents
    // contents = bitstreams, bundles
    // FIXME: icky hardcoded workflow steps
    Collection collection = workspaceItem.getCollection();
    Group step1group = collectionService.getWorkflowGroup(collection, 1);
    Group step2group = collectionService.getWorkflowGroup(collection, 2);
    Group step3group = collectionService.getWorkflowGroup(collection, 3);

    Item item = workspaceItem.getItem();

    if (step1group != null) {
      authorizeService.addPolicy(
          context, item, Constants.READ, step1group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step2group != null) {
      authorizeService.addPolicy(
          context, item, Constants.READ, step2group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step3group != null) {
      authorizeService.addPolicy(
          context, item, Constants.READ, step3group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step1group != null) {
      authorizeService.addPolicy(
          context, item, Constants.WRITE, step1group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step2group != null) {
      authorizeService.addPolicy(
          context, item, Constants.WRITE, step2group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step3group != null) {
      authorizeService.addPolicy(
          context, item, Constants.WRITE, step3group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step1group != null) {
      authorizeService.addPolicy(
          context, item, Constants.ADD, step1group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step2group != null) {
      authorizeService.addPolicy(
          context, item, Constants.ADD, step2group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step3group != null) {
      authorizeService.addPolicy(
          context, item, Constants.ADD, step3group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step1group != null) {
      authorizeService.addPolicy(
          context, item, Constants.REMOVE, step1group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step2group != null) {
      authorizeService.addPolicy(
          context, item, Constants.REMOVE, step2group, ResourcePolicy.TYPE_WORKFLOW);
    }

    if (step3group != null) {
      authorizeService.addPolicy(
          context, item, Constants.REMOVE, step3group, ResourcePolicy.TYPE_WORKFLOW);
    }
  }
  @Override
  public WorkspaceItem sendWorkflowItemBackSubmission(
      Context context,
      BasicWorkflowItem workflowItem,
      EPerson ePerson,
      String provenancePrefix,
      String rejection_message)
      throws SQLException, AuthorizeException, IOException {

    int oldState = workflowItem.getState();
    // authorize a DSpaceActions.REJECT
    // stop workflow
    taskListItemService.deleteByWorkflowItem(context, workflowItem);

    // rejection provenance
    Item myitem = workflowItem.getItem();

    // Get current date
    String now = DCDate.getCurrent().toString();

    // Get user's name + email address
    String usersName = getEPersonName(ePerson);

    // Here's what happened
    String provDescription =
        "Rejected by " + usersName + ", reason: " + rejection_message + " on " + now + " (GMT) ";

    // Add to item as a DC field
    itemService.addMetadata(
        context,
        myitem,
        MetadataSchema.DC_SCHEMA,
        "description",
        "provenance",
        "en",
        provDescription);
    itemService.update(context, myitem);

    // convert into personal workspace
    WorkspaceItem wsi = returnToWorkspace(context, workflowItem);

    // notify that it's been rejected
    notifyOfReject(context, workflowItem, ePerson, rejection_message);

    log.info(
        LogManager.getHeader(
            context,
            "reject_workflow",
            "workflow_item_id="
                + workflowItem.getID()
                + "item_id="
                + workflowItem.getItem().getID()
                + "collection_id="
                + workflowItem.getCollection().getID()
                + "eperson_id="
                + ePerson.getID()));

    logWorkflowEvent(
        context,
        wsi.getItem(),
        workflowItem,
        ePerson,
        WFSTATE_SUBMIT,
        null,
        wsi.getCollection(),
        oldState,
        null);

    return wsi;
  }