/**
   * Moves a dataset containing an image owned by another user and an image owned.
   *
   * @param source The permissions of the source group.
   * @param target The permissions of the destination group.
   * @param sourceRole The user's role in the source group.
   * @param targetRole The user's role in the target group.
   * @throws Exception Thrown if an error occurred.
   */
  private void moveDatasetAndImage(String source, String target, int sourceRole, int targetLevel)
      throws Exception {
    // Step 1
    // Create a new group
    EventContext ctx = newUserAndGroup(source);
    // Create an image.
    Image img1 = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage());
    long user1 = img1.getDetails().getOwner().getId().getValue();
    disconnect();

    // Step 2
    // create a new user and add it to the group
    ctx = newUserInGroup(ctx);
    switch (sourceRole) {
      case GROUP_OWNER:
        makeGroupOwner();
        break;
      case ADMIN:
        logRootIntoGroup(ctx);
    }

    loginUser(ctx);
    // Create a dataset
    Dataset d = (Dataset) iUpdate.saveAndReturnObject(mmFactory.simpleDatasetData().asIObject());
    // link the dataset and the image
    DatasetImageLink link = new DatasetImageLinkI();
    link.setChild(img1);
    link.setParent(new DatasetI(d.getId().getValue(), false));
    iUpdate.saveAndReturnObject(link);

    Image img2 = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage());
    link = new DatasetImageLinkI();
    link.setChild(img2);
    link.setParent(new DatasetI(d.getId().getValue(), false));
    iUpdate.saveAndReturnObject(link);

    long user2 = d.getDetails().getOwner().getId().getValue();
    assertTrue(user1 != user2);
    disconnect();

    // Step 3
    // Create a new group, the user is now a member of the new group.
    ExperimenterGroup g = newGroupAddUser(target, ctx.userId);
    loginUser(g);

    disconnect();

    // Step 4
    // reconnect to the source group.
    switch (sourceRole) {
      case MEMBER:
      case GROUP_OWNER:
      default:
        loginUser(ctx);
        break;
      case ADMIN:
        logRootIntoGroup(ctx.groupId);
    }
    // Create commands to move and create the link in target
    final Chgrp2 dc = Requests.chgrp("Dataset", d.getId().getValue(), g.getId().getValue());
    callback(true, client, dc);

    // Check if the dataset has been removed.
    ParametersI param = new ParametersI();
    param.addId(d.getId().getValue());
    String sql = "select i from Dataset as i where i.id = :id";
    assertNull(iQuery.findByQuery(sql, param));

    List<Long> ids = new ArrayList<Long>();
    ids.add(img1.getId().getValue());
    ids.add(img2.getId().getValue());

    param = new ParametersI();
    param.addIds(ids);
    sql = "select i from Image as i where i.id in (:ids)";
    List<IObject> results = iQuery.findAllByQuery(sql, param);
    assertEquals(results.size(), 0);

    // log out from source group
    disconnect();

    // Step 5
    // log into source group to perform the move
    switch (sourceRole) {
      case MEMBER:
      case GROUP_OWNER:
      default:
        loginUser(g);
        break;
      case ADMIN:
        logRootIntoGroup(g.getId().getValue());
    }
    param = new ParametersI();
    param.addId(d.getId().getValue());
    sql = "select i from Dataset as i where i.id = :id";

    // Check if the dataset is in the target group.
    assertNotNull(iQuery.findByQuery(sql, param));

    // Check
    param = new ParametersI();
    param.addIds(ids);
    sql = "select i from Image as i where i.id in (:ids)";
    results = iQuery.findAllByQuery(sql, param);
    assertEquals(results.size(), ids.size());
    Iterator<IObject> i = results.iterator();
    int count = 0;
    while (i.hasNext()) {
      if (ids.contains(i.next().getId().getValue())) count++;
    }
    assertEquals(count, ids.size());
    disconnect();
  }