private MetadataRestInfo addQueueGroups(
      List<OpenAcdQueueGroupRestInfoFull> queueGroupsRestInfo,
      List<OpenAcdQueueGroup> queueGroups) {
    List<OpenAcdSkillRestInfo> skillsRestInfo;
    List<OpenAcdAgentGroupRestInfo> agentGroupRestInfo;
    List<OpenAcdRecipeStepRestInfo> recipeStepRestInfo;
    // determine pagination
    PaginationInfo paginationInfo = RestUtilities.calculatePagination(m_form, queueGroups.size());

    // create list of group restinfos
    for (int index = paginationInfo.startIndex; index <= paginationInfo.endIndex; index++) {
      OpenAcdQueueGroup queueGroup = queueGroups.get(index);

      skillsRestInfo = createSkillsRestInfo(queueGroup.getSkills());
      agentGroupRestInfo = createAgentGroupsRestInfo(queueGroup);
      recipeStepRestInfo = createRecipeStepsRestInfo(queueGroup);

      OpenAcdQueueGroupRestInfoFull queueGroupRestInfo =
          new OpenAcdQueueGroupRestInfoFull(
              queueGroup, skillsRestInfo, agentGroupRestInfo, recipeStepRestInfo);
      queueGroupsRestInfo.add(queueGroupRestInfo);
    }

    // create metadata about agent groups
    MetadataRestInfo metadata = new MetadataRestInfo(paginationInfo);
    return metadata;
  }
  @Override
  public void removeRepresentations() throws ResourceException {
    OpenAcdQueueGroup queueGroup;

    // get id then delete a single group
    String idString = (String) getRequest().getAttributes().get("id");

    if (idString != null) {
      try {
        int idInt = RestUtilities.getIntFromAttribute(idString);
        queueGroup = m_openAcdContext.getQueueGroupById(idInt);
      } catch (Exception exception) {
        RestUtilities.setResponseError(
            getResponse(), ResponseCode.ERROR_BAD_INPUT, "ID " + idString + " not found.");
        return;
      }

      m_openAcdContext.deleteQueueGroup(queueGroup);

      RestUtilities.setResponse(
          getResponse(), ResponseCode.SUCCESS_DELETED, "Deleted Queue Group", queueGroup.getId());

      return;
    }

    // no id string
    RestUtilities.setResponse(getResponse(), ResponseCode.ERROR_MISSING_INPUT, "ID value missing");
  }
  private OpenAcdQueueGroup createQueueGroup(OpenAcdQueueGroupRestInfoFull queueGroupRestInfo) {
    OpenAcdQueueGroup queueGroup = new OpenAcdQueueGroup();

    // copy fields from rest info
    queueGroup.setName(queueGroupRestInfo.getName());
    queueGroup.setDescription(queueGroupRestInfo.getDescription());

    addLists(queueGroup, queueGroupRestInfo);

    return queueGroup;
  }
  private void updateQueueGroup(
      OpenAcdQueueGroup queueGroup, OpenAcdQueueGroupRestInfoFull queueGroupRestInfo) {
    String tempString;

    // do not allow empty name
    tempString = queueGroupRestInfo.getName();
    if (!tempString.isEmpty()) {
      queueGroup.setName(tempString);
    }

    queueGroup.setDescription(queueGroupRestInfo.getDescription());

    addLists(queueGroup, queueGroupRestInfo);
  }
  private OpenAcdQueueGroupRestInfoFull createQueueGroupRestInfo(int id) throws ResourceException {
    OpenAcdQueueGroupRestInfoFull queueGroupRestInfo;
    List<OpenAcdSkillRestInfo> skillsRestInfo;
    List<OpenAcdAgentGroupRestInfo> agentGroupRestInfo;
    List<OpenAcdRecipeStepRestInfo> recipeStepRestInfo;

    OpenAcdQueueGroup queueGroup = m_openAcdContext.getQueueGroupById(id);
    skillsRestInfo = createSkillsRestInfo(queueGroup.getSkills());
    agentGroupRestInfo = createAgentGroupsRestInfo(queueGroup);
    recipeStepRestInfo = createRecipeStepsRestInfo(queueGroup);
    queueGroupRestInfo =
        new OpenAcdQueueGroupRestInfoFull(
            queueGroup, skillsRestInfo, agentGroupRestInfo, recipeStepRestInfo);

    return queueGroupRestInfo;
  }
  private List<OpenAcdAgentGroupRestInfo> createAgentGroupsRestInfo(OpenAcdQueueGroup queueGroup) {
    List<OpenAcdAgentGroupRestInfo> agentGroupsRestInfo;
    OpenAcdAgentGroupRestInfo agentGroupRestInfo;

    // create list of agent group restinfos for single group
    Set<OpenAcdAgentGroup> groupAgentGroups = queueGroup.getAgentGroups();
    agentGroupsRestInfo = new ArrayList<OpenAcdAgentGroupRestInfo>(groupAgentGroups.size());

    for (OpenAcdAgentGroup groupAgentGroup : groupAgentGroups) {
      agentGroupRestInfo = new OpenAcdAgentGroupRestInfo(groupAgentGroup);
      agentGroupsRestInfo.add(agentGroupRestInfo);
    }

    return agentGroupsRestInfo;
  }
  private List<OpenAcdRecipeStepRestInfo> createRecipeStepsRestInfo(OpenAcdQueueGroup queueGroup) {
    List<OpenAcdRecipeStepRestInfo> recipeStepsRestInfo;
    OpenAcdRecipeStepRestInfo recipeStepRestInfo;

    Set<OpenAcdRecipeStep> groupRecipeSteps = queueGroup.getSteps();
    recipeStepsRestInfo = new ArrayList<OpenAcdRecipeStepRestInfo>(groupRecipeSteps.size());

    for (OpenAcdRecipeStep groupRecipeStep : groupRecipeSteps) {
      recipeStepRestInfo =
          new OpenAcdRecipeStepRestInfo(
              groupRecipeStep,
              createRecipeActionRestInfo(groupRecipeStep),
              createRecipeConditionsRestInfo(groupRecipeStep));
      recipeStepsRestInfo.add(recipeStepRestInfo);
    }
    return recipeStepsRestInfo;
  }
  private void addLists(
      OpenAcdQueueGroup queueGroup, OpenAcdQueueGroupRestInfoFull queueGroupRestInfo) {
    // remove all skills
    queueGroup.getSkills().clear();

    // set skills
    OpenAcdSkill skill;
    List<OpenAcdSkillRestInfo> skillsRestInfo = queueGroupRestInfo.getSkills();
    for (OpenAcdSkillRestInfo skillRestInfo : skillsRestInfo) {
      skill = m_openAcdContext.getSkillById(skillRestInfo.getId());
      queueGroup.addSkill(skill);
    }

    // remove all agent groups
    queueGroup.getAgentGroups().clear();

    // set agent groups
    OpenAcdAgentGroup agentGroup;
    List<OpenAcdAgentGroupRestInfo> agentGroupsRestInfo = queueGroupRestInfo.getAgentGroups();
    for (OpenAcdAgentGroupRestInfo agentGroupRestInfo : agentGroupsRestInfo) {
      agentGroup = m_openAcdContext.getAgentGroupById(agentGroupRestInfo.getId());
      queueGroup.addAgentGroup(agentGroup);
    }

    // remove all current steps
    queueGroup.getSteps().clear();

    // set steps
    OpenAcdRecipeStep step;
    OpenAcdRecipeCondition condition;
    OpenAcdRecipeAction action;
    OpenAcdRecipeActionRestInfo actionRestInfo;

    List<OpenAcdRecipeStepRestInfo> recipeStepsRestInfo = queueGroupRestInfo.getSteps();
    for (OpenAcdRecipeStepRestInfo recipeStepRestInfo : recipeStepsRestInfo) {
      step = new OpenAcdRecipeStep();
      step.setFrequency(recipeStepRestInfo.getFrequency());

      // add conditions
      step.getConditions().clear();
      for (OpenAcdRecipeConditionRestInfo recipeConditionRestInfo :
          recipeStepRestInfo.getConditions()) {
        condition = new OpenAcdRecipeCondition();
        condition.setCondition(recipeConditionRestInfo.getCondition());
        condition.setRelation(recipeConditionRestInfo.getRelation());
        condition.setValueCondition(recipeConditionRestInfo.getValueCondition());

        step.addCondition(condition);
      }

      // add action
      action = new OpenAcdRecipeAction();
      actionRestInfo = recipeStepRestInfo.getAction();
      action.setAction(actionRestInfo.getAction());
      action.setActionValue(actionRestInfo.getActionValue());

      // set action skills (separate from skills assigned to queue
      for (OpenAcdSkillRestInfo skillRestInfo : actionRestInfo.getSkills()) {
        skill = m_openAcdContext.getSkillById(skillRestInfo.getId());
        action.addSkill(skill);
      }

      step.setAction(action);

      queueGroup.addStep(step);
    }
  }
  @Override
  public void storeRepresentation(Representation entity) throws ResourceException {
    // get group from body
    OpenAcdQueueGroupRepresentation representation = new OpenAcdQueueGroupRepresentation(entity);
    OpenAcdQueueGroupRestInfoFull queueGroupRestInfo = representation.getObject();
    OpenAcdQueueGroup queueGroup;

    // validate input for update or create
    ValidationInfo validationInfo = validate(queueGroupRestInfo);

    if (!validationInfo.valid) {
      RestUtilities.setResponseError(
          getResponse(), validationInfo.responseCode, validationInfo.message);
      return;
    }

    // if have id then update a single group
    String idString = (String) getRequest().getAttributes().get("id");

    if (idString != null) {
      try {
        int idInt = RestUtilities.getIntFromAttribute(idString);
        queueGroup = m_openAcdContext.getQueueGroupById(idInt);
      } catch (Exception exception) {
        RestUtilities.setResponseError(
            getResponse(), ResponseCode.ERROR_BAD_INPUT, "ID " + idString + " not found.");
        return;
      }

      // copy values over to existing group
      try {
        updateQueueGroup(queueGroup, queueGroupRestInfo);
        m_openAcdContext.saveQueueGroup(queueGroup);
      } catch (Exception exception) {
        RestUtilities.setResponseError(
            getResponse(),
            ResponseCode.ERROR_WRITE_FAILED,
            "Update Queue Group failed",
            exception.getLocalizedMessage());
        return;
      }

      RestUtilities.setResponse(
          getResponse(), ResponseCode.SUCCESS_UPDATED, "Updated Queue", queueGroup.getId());

      return;
    }

    // otherwise add new agent group
    try {
      queueGroup = createQueueGroup(queueGroupRestInfo);
      m_openAcdContext.saveQueueGroup(queueGroup);
    } catch (Exception exception) {
      RestUtilities.setResponseError(
          getResponse(),
          RestUtilities.ResponseCode.ERROR_WRITE_FAILED,
          "Create Queue Group failed",
          exception.getLocalizedMessage());
      return;
    }

    RestUtilities.setResponse(
        getResponse(),
        RestUtilities.ResponseCode.SUCCESS_CREATED,
        "Created Queue Group",
        queueGroup.getId());
  }