/**
   * Change the default read privileges to the anonymous group.
   *
   * <p>If getCollectionDefaultRead() returns -1 or the anonymous group then nothing is done.
   *
   * @param context The current DSpace context.
   * @param collectionID The collection id.
   * @return A process result's object.
   */
  public static FlowResult changeCollectionDefaultReadToAnonymous(Context context, int collectionID)
      throws SQLException, AuthorizeException, UIException {
    FlowResult result = new FlowResult();

    int roleID = getCollectionDefaultRead(context, collectionID);

    if (roleID < 1) {
      throw new UIException(
          "Unable to delete the default read role because the role is either already assigned to the anonymous group or multiple groups are assigned the default privileges.");
    }

    Collection collection = Collection.find(context, collectionID);
    Group role = Group.find(context, roleID);
    Group anonymous = Group.find(context, 0);

    // Delete the old role, this will remove the default privileges.
    role.delete();

    // Set anonymous as the default read group.
    AuthorizeManager.addPolicy(context, collection, Constants.DEFAULT_ITEM_READ, anonymous);
    AuthorizeManager.addPolicy(context, collection, Constants.DEFAULT_BITSTREAM_READ, anonymous);

    // Commit the changes
    context.commit();

    result.setContinue(true);
    result.setOutcome(true);
    result.setMessage(
        new Message(
            "default",
            "All new items submitted to this collection will default to anonymous read."));
    return result;
  }
  /**
   * Delete one of a community's roles
   *
   * @param context The current DSpace context.
   * @param communityID The community id.
   * @param roleName ADMIN.
   * @param groupID The id of the group associated with this role.
   * @return A process result's object.
   */
  public static FlowResult processDeleteCommunityRole(
      Context context, int communityID, String roleName, int groupID)
      throws SQLException, UIException, IOException, AuthorizeException {
    FlowResult result = new FlowResult();

    Community community = Community.find(context, communityID);
    Group role = Group.find(context, groupID);

    // First, unregister the role
    if (ROLE_ADMIN.equals(roleName)) {
      community.removeAdministrators();
    }

    // Second, remove all authorizations for this role by searching for all policies that this
    // group has on the collection and remove them otherwise the delete will fail because
    // there are dependencies.
    @SuppressWarnings("unchecked") // the cast is correct
    List<ResourcePolicy> policies = AuthorizeManager.getPolicies(context, community);
    for (ResourcePolicy policy : policies) {
      if (policy.getGroupID() == groupID) {
        policy.delete();
      }
    }

    // Finally, delete the role's actual group.
    community.update();
    role.delete();
    context.commit();

    result.setContinue(true);
    result.setOutcome(true);
    result.setMessage(new Message("default", "The role was successfully deleted."));
    return result;
  }
  /**
   * Use the collection's harvest settings to immediately perform a harvest cycle.
   *
   * @param context The current DSpace context.
   * @param collectionID The collection id.
   * @param request the Cocoon request object
   * @return A process result's object.
   * @throws TransformerException
   * @throws SAXException
   * @throws ParserConfigurationException
   * @throws CrosswalkException
   */
  public static FlowResult processRunCollectionHarvest(
      Context context, int collectionID, Request request)
      throws SQLException, IOException, AuthorizeException, CrosswalkException,
          ParserConfigurationException, SAXException, TransformerException {
    FlowResult result = new FlowResult();
    OAIHarvester harvester;
    List<String> testErrors = new ArrayList<String>();
    Collection collection = Collection.find(context, collectionID);
    HarvestedCollection hc = HarvestedCollection.find(context, collectionID);

    // TODO: is there a cleaner way to do this?
    try {
      if (!HarvestScheduler.hasStatus(HarvestScheduler.HARVESTER_STATUS_STOPPED)) {
        synchronized (HarvestScheduler.lock) {
          HarvestScheduler.setInterrupt(
              HarvestScheduler.HARVESTER_INTERRUPT_INSERT_THREAD, collectionID);
          HarvestScheduler.lock.notify();
        }
      } else {
        harvester = new OAIHarvester(context, collection, hc);
        harvester.runHarvest();
      }
    } catch (Exception e) {
      testErrors.add(e.getMessage());
      result.setErrors(testErrors);
      result.setContinue(false);
      return result;
    }

    result.setContinue(true);

    return result;
  }
  /**
   * Process the collection harvesting options form.
   *
   * @param context The current DSpace context.
   * @param collectionID The collection id.
   * @param request the Cocoon request object
   * @return A process result's object.
   */
  public static FlowResult processSetupCollectionHarvesting(
      Context context, int collectionID, Request request)
      throws SQLException, IOException, AuthorizeException {
    FlowResult result = new FlowResult();
    HarvestedCollection hc = HarvestedCollection.find(context, collectionID);

    String contentSource = request.getParameter("source");

    // First, if this is not a harvested collection (anymore), set the harvest type to 0; possibly
    // also wipe harvest settings
    if (contentSource.equals("source_normal")) {
      if (hc != null) {
        hc.delete();
      }

      result.setContinue(true);
    } else {
      FlowResult subResult = testOAISettings(context, request);

      // create a new harvest instance if all the settings check out
      if (hc == null) {
        hc = HarvestedCollection.create(context, collectionID);
      }

      // if the supplied options all check out, set the harvesting parameters on the collection
      if (subResult.getErrors().isEmpty()) {
        String oaiProvider = request.getParameter("oai_provider");
        boolean oaiAllSets = "all".equals(request.getParameter("oai-set-setting"));
        String oaiSetId;
        if (oaiAllSets) {
          oaiSetId = "all";
        } else {
          oaiSetId = request.getParameter("oai_setid");
        }

        String metadataKey = request.getParameter("metadata_format");
        String harvestType = request.getParameter("harvest_level");

        hc.setHarvestParams(Integer.parseInt(harvestType), oaiProvider, oaiSetId, metadataKey);
        hc.setHarvestStatus(HarvestedCollection.STATUS_READY);
      } else {
        result.setErrors(subResult.getErrors());
        result.setContinue(false);
        return result;
      }

      hc.update();
    }

    // Save everything
    context.commit();

    // No notice...
    // result.setMessage(new Message("default","Harvesting options successfully modified."));
    result.setOutcome(true);
    result.setContinue(true);

    return result;
  }
  /**
   * Delete one of collection's roles
   *
   * @param context The current DSpace context.
   * @param collectionID The collection id.
   * @param roleName ADMIN, WF_STEP1, WF_STEP2, WF_STEP3, SUBMIT, DEFAULT_READ.
   * @param groupID The id of the group associated with this role.
   * @return A process result's object.
   */
  public static FlowResult processDeleteCollectionRole(
      Context context, int collectionID, String roleName, int groupID)
      throws SQLException, UIException, IOException, AuthorizeException,
          WorkflowConfigurationException {
    FlowResult result = new FlowResult();

    Collection collection = Collection.find(context, collectionID);
    Group role = Group.find(context, groupID);

    // First, Unregister the role
    if (ROLE_ADMIN.equals(roleName)) {
      collection.removeAdministrators();
    } else if (ROLE_SUBMIT.equals(roleName)) {
      collection.removeSubmitters();
    } else {
      WorkflowUtils.deleteRoleGroup(context, collection, roleName);
    }
    //		else if (ROLE_WF_STEP1.equals(roleName))
    //		{
    //			collection.setWorkflowGroup(1, null);
    //		}
    //		else if (ROLE_WF_STEP2.equals(roleName))
    //		{
    //			collection.setWorkflowGroup(2, null);
    //		}
    //		else if (ROLE_WF_STEP3.equals(roleName))
    //		{
    //			collection.setWorkflowGroup(3, null);
    //
    //		}

    // Second, remove all authorizations for this role by searching for all policies that this
    // group has on the collection and remove them otherwise the delete will fail because
    // there are dependencies.
    @SuppressWarnings("unchecked") // the cast is correct
    List<ResourcePolicy> policies = AuthorizeManager.getPolicies(context, collection);
    for (ResourcePolicy policy : policies) {
      if (policy.getGroupID() == groupID) {
        policy.delete();
      }
    }

    // Finally, Delete the role's actual group.
    collection.update();
    role.delete();
    context.commit();

    result.setContinue(true);
    result.setOutcome(true);
    result.setMessage(new Message("default", "The role was successfully deleted."));
    return result;
  }
  /**
   * Delete a collection's template item (which is not a member of the collection).
   *
   * @param context
   * @param collectionID
   * @throws SQLException
   * @throws AuthorizeException
   * @throws IOException
   */
  public static FlowResult processDeleteTemplateItem(Context context, int collectionID)
      throws SQLException, AuthorizeException, IOException {
    FlowResult result = new FlowResult();

    Collection collection = Collection.find(context, collectionID);

    collection.removeTemplateItem();
    context.commit();

    result.setContinue(true);
    result.setOutcome(true);
    return result;
  }
  /**
   * Delete community itself
   *
   * @param context The current DSpace context.
   * @param communityID The community id.
   * @return A process result's object.
   */
  public static FlowResult processDeleteCommunity(Context context, int communityID)
      throws SQLException, AuthorizeException, IOException {
    FlowResult result = new FlowResult();

    Community community = Community.find(context, communityID);

    community.delete();
    context.commit();

    result.setContinue(true);
    result.setOutcome(true);
    result.setMessage(new Message("default", "The community was successfully deleted."));

    return result;
  }
  /**
   * Delete collection itself
   *
   * @param context The current DSpace context.
   * @param collectionID The collection id.
   * @return A process result's object.
   */
  public static FlowResult processDeleteCollection(Context context, int collectionID)
      throws SQLException, AuthorizeException, IOException {
    FlowResult result = new FlowResult();

    Collection collection = Collection.find(context, collectionID);

    Community[] parents = collection.getCommunities();

    for (Community parent : parents) {
      parent.removeCollection(collection);
      parent.update();
    }

    context.commit();

    result.setContinue(true);
    result.setOutcome(true);
    result.setMessage(new Message("default", "The collection was successfully deleted."));

    return result;
  }
  /**
   * Process the community metadata edit form.
   *
   * @param context The current DSpace context.
   * @param communityID The community id.
   * @param deleteLogo Determines if the logo should be deleted along with the metadata editing
   *     action.
   * @param request the Cocoon request object
   * @return A process result's object.
   */
  public static FlowResult processEditCommunity(
      Context context, int communityID, boolean deleteLogo, Request request)
      throws AuthorizeException, IOException, SQLException {
    FlowResult result = new FlowResult();

    Community community = Community.find(context, communityID);

    String name = request.getParameter("name");
    String shortDescription = request.getParameter("short_description");
    String introductoryText = request.getParameter("introductory_text");
    String copyrightText = request.getParameter("copyright_text");
    String sideBarText = request.getParameter("side_bar_text");

    // If they don't have a name then make it untitled.
    if (name == null || name.length() == 0) {
      name = "Untitled";
    }

    // If empty, make it null.
    if (shortDescription != null && shortDescription.length() == 0) {
      shortDescription = null;
    }
    if (introductoryText != null && introductoryText.length() == 0) {
      introductoryText = null;
    }
    if (copyrightText != null && copyrightText.length() == 0) {
      copyrightText = null;
    }
    if (sideBarText != null && sideBarText.length() == 0) {
      sideBarText = null;
    }

    // Save the data
    community.setMetadata("name", name);
    community.setMetadata("short_description", shortDescription);
    community.setMetadata("introductory_text", introductoryText);
    community.setMetadata("copyright_text", copyrightText);
    community.setMetadata("side_bar_text", sideBarText);

    if (deleteLogo) {
      // Remove the logo
      community.setLogo(null);
    } else {
      // Update the logo
      Object object = request.get("logo");
      Part filePart = null;
      if (object instanceof Part) {
        filePart = (Part) object;
      }

      if (filePart != null && filePart.getSize() > 0) {
        InputStream is = filePart.getInputStream();

        community.setLogo(is);
      }
    }

    // Save everything
    community.update();
    context.commit();

    // No notice...
    result.setContinue(true);
    return result;
  }
  /**
   * Create a new community
   *
   * @param context The current DSpace context.
   * @param communityID The id of the parent community (-1 for a top-level community).
   * @return A process result's object.
   */
  public static FlowResult processCreateCommunity(Context context, int communityID, Request request)
      throws AuthorizeException, IOException, SQLException {
    FlowResult result = new FlowResult();

    Community parent = Community.find(context, communityID);
    Community newCommunity;

    if (parent != null) {
      newCommunity = parent.createSubcommunity();
    } else {
      newCommunity = Community.create(null, context);
    }

    String name = request.getParameter("name");
    String shortDescription = request.getParameter("short_description");
    String introductoryText = request.getParameter("introductory_text");
    String copyrightText = request.getParameter("copyright_text");
    String sideBarText = request.getParameter("side_bar_text");

    // If they don't have a name then make it untitled.
    if (name == null || name.length() == 0) {
      name = "Untitled";
    }

    // If empty, make it null.
    if (shortDescription != null && shortDescription.length() == 0) {
      shortDescription = null;
    }
    if (introductoryText != null && introductoryText.length() == 0) {
      introductoryText = null;
    }
    if (copyrightText != null && copyrightText.length() == 0) {
      copyrightText = null;
    }
    if (sideBarText != null && sideBarText.length() == 0) {
      sideBarText = null;
    }

    newCommunity.setMetadata("name", name);
    newCommunity.setMetadata("short_description", shortDescription);
    newCommunity.setMetadata("introductory_text", introductoryText);
    newCommunity.setMetadata("copyright_text", copyrightText);
    newCommunity.setMetadata("side_bar_text", sideBarText);

    // Upload the logo
    Object object = request.get("logo");
    Part filePart = null;
    if (object instanceof Part) {
      filePart = (Part) object;
    }

    if (filePart != null && filePart.getSize() > 0) {
      InputStream is = filePart.getInputStream();

      newCommunity.setLogo(is);
    }

    // Save everything
    newCommunity.update();
    context.commit();
    // success
    result.setContinue(true);
    result.setOutcome(true);
    result.setMessage(new Message("default", "The community was successfully created."));
    result.setParameter("communityID", newCommunity.getID());

    return result;
  }
  /**
   * Test the supplied OAI settings.
   *
   * @param context
   * @param request
   */
  public static FlowResult testOAISettings(Context context, Request request) {
    FlowResult result = new FlowResult();

    String oaiProvider = request.getParameter("oai_provider");
    String oaiSetId = request.getParameter("oai_setid");
    oaiSetId = request.getParameter("oai-set-setting");
    if (!"all".equals(oaiSetId)) {
      oaiSetId = request.getParameter("oai_setid");
    }
    String metadataKey = request.getParameter("metadata_format");
    String harvestType = request.getParameter("harvest_level");
    int harvestTypeInt = 0;

    if (oaiProvider == null || oaiProvider.length() == 0) {
      result.addError("oai_provider");
    }
    if (oaiSetId == null || oaiSetId.length() == 0) {
      result.addError("oai_setid");
    }
    if (metadataKey == null || metadataKey.length() == 0) {
      result.addError("metadata_format");
    }
    if (harvestType == null || harvestType.length() == 0) {
      result.addError("harvest_level");
    } else {
      harvestTypeInt = Integer.parseInt(harvestType);
    }

    if (result.getErrors() == null) {
      List<String> testErrors =
          OAIHarvester.verifyOAIharvester(oaiProvider, oaiSetId, metadataKey, (harvestTypeInt > 1));
      result.setErrors(testErrors);
    }

    if (result.getErrors() == null || result.getErrors().isEmpty()) {
      result.setOutcome(true);
      // On a successful test we still want to stay in the loop, not continue out of it
      // result.setContinue(true);
      result.setMessage(new Message("default", "Harvesting settings are valid."));
    } else {
      result.setOutcome(false);
      result.setContinue(false);
      // don't really need a message when the errors are highlighted already
      // result.setMessage(new Message("default","Harvesting is not properly configured."));
    }

    return result;
  }