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 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);
    }
  }
  // basic interface level validation of data provided through REST interface for creation or update
  // may also contain clean up of input data
  // may create another validation function if different rules needed for update v. create
  private ValidationInfo validate(OpenAcdQueueGroupRestInfoFull restInfo) {
    ValidationInfo validationInfo = new ValidationInfo();
    List<String> relation = Arrays.asList("is", "isNot");
    List<String> condition1 =
        Arrays.asList(
            "available_agents",
            "eligible_agents",
            "calls_queued",
            "queue_position",
            "hour",
            "weekday",
            "client_calls_queued");
    List<String> condition2 =
        Arrays.asList("ticks", "client", "media_type", "caller_id", "caller_name");
    List<String> equalityRelation = Arrays.asList("is", "greater", "less");
    List<String> mediaValues = Arrays.asList("voice", "email", "voicemail", "chat");

    String name = restInfo.getName();

    // rest mods the hours with 24 to give a new hour, so allow over 23

    for (int i = 0; i < name.length(); i++) {
      if ((!Character.isLetterOrDigit(name.charAt(i))
              && !(Character.getType(name.charAt(i)) == Character.CONNECTOR_PUNCTUATION))
          && name.charAt(i) != '-') {
        validationInfo.valid = false;
        validationInfo.message =
            "Validation Error: 'Name' must only contain letters, numbers, dashes, and underscores";
        validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
      }
    }

    for (int i = 0; i < restInfo.getSteps().size(); i++) {
      if (restInfo.getSteps().get(i).getAction().getAction().isEmpty()) {
        validationInfo.valid = false;
        validationInfo.message =
            "Validation Error: 'Action' cannot be empty and must only contain numbers and *";
        validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
      }

      if (restInfo.getSteps().get(i).getAction().getAction().equals("announce")
          || restInfo.getSteps().get(i).getAction().getAction().equals("set_priority")) {
        if (restInfo.getSteps().get(i).getAction().getActionValue().isEmpty()) {
          validationInfo.valid = false;
          validationInfo.message =
              "Validation Error: 'Action Value' cannot be empty and must only contain numbers and *";
          validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
        }
      }

      for (int j = 0; j < m_openAcdContext.getClients().size(); j++) {
        if (m_openAcdContext
            .getClients()
            .get(j)
            .getIdentity()
            .equals(restInfo.getSteps().get(i).getAction().getActionValue())) {
          validationInfo.valid = false;
          validationInfo.message = "Validation Error: Client Does not Exist";
          validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
        }
      }

      if (restInfo.getSteps().get(i).getAction().getAction().equals("set_priority")) {
        for (int j = 0; j < restInfo.getSteps().get(i).getAction().getActionValue().length(); j++) {
          char c = restInfo.getSteps().get(i).getAction().getActionValue().charAt(j);
          if (!Character.isDigit(c) && c != '*') {
            validationInfo.valid = false;
            validationInfo.message =
                "Validation Error: 'Action Value' must only contain numbers and *";
            validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
          }
        }
      }

      for (int k = 0; k < restInfo.getSteps().get(i).getConditions().size(); k++) {
        if (restInfo.getSteps().get(i).getConditions().get(k).getCondition().isEmpty()
            || restInfo.getSteps().get(i).getConditions().get(k).getRelation().isEmpty()
            || restInfo.getSteps().get(i).getConditions().get(k).getValueCondition().isEmpty()) {
          validationInfo.valid = false;
          validationInfo.message = "Validation Error: 'Condtion' cannot be empty";
          validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
        }

        if (condition2.contains(restInfo.getSteps().get(i).getConditions().get(k).getCondition())) {
          if (!(relation.contains(
              restInfo.getSteps().get(i).getConditions().get(k).getRelation()))) {
            validationInfo.valid = false;
            validationInfo.message = "Validation Error: 'Relation' must only be 'is' or 'isNot'";
            validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
          }
        }

        if (condition1.contains(restInfo.getSteps().get(i).getConditions().get(k).getCondition())) {
          if (!(equalityRelation.contains(
              restInfo.getSteps().get(i).getConditions().get(k).getRelation()))) {
            validationInfo.valid = false;
            validationInfo.message =
                "Validation Error: 'Relation' must only be 'is', 'greater', or 'less'";
            validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
          }
        }

        if (restInfo.getSteps().get(i).getConditions().get(k).getCondition().equals("media_type")) {
          if (!(mediaValues.contains(
              restInfo.getSteps().get(i).getConditions().get(k).getValueCondition()))) {
            validationInfo.valid = false;
            validationInfo.message =
                "Validation Error: 'Value Condition' can only be 'voice', 'email', 'voicemail', or 'chat'";
            validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
          }
        }

        if (restInfo.getSteps().get(i).getConditions().get(k).getCondition().equals("weekday")) {
          if (Integer.parseInt(
                      restInfo.getSteps().get(i).getConditions().get(k).getValueCondition())
                  < 1
              || Integer.parseInt(
                      restInfo.getSteps().get(i).getConditions().get(k).getValueCondition())
                  > 7) {
            validationInfo.valid = false;
            validationInfo.message = "Validation Error: 'Value Condition' must be between 1 and 7";
            validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
          }
        }

        if (!(restInfo.getSteps().get(i).getConditions().get(k).getCondition().equals("caller_id")
            || restInfo
                .getSteps()
                .get(i)
                .getConditions()
                .get(k)
                .getCondition()
                .equals("caller_name")
            || restInfo.getSteps().get(i).getConditions().get(k).getCondition().equals("media_type")
            || restInfo.getSteps().get(i).getConditions().get(k).getCondition().equals("client"))) {
          for (int j = 0;
              j < restInfo.getSteps().get(i).getConditions().get(k).getValueCondition().length();
              j++) {
            char c =
                restInfo.getSteps().get(i).getConditions().get(k).getValueCondition().charAt(j);
            if (!Character.isDigit(c) && c != '*') {
              validationInfo.valid = false;
              validationInfo.message =
                  "Validation Error: 'Value Condition' must only contain numbers and *";
              validationInfo.responseCode = ResponseCode.ERROR_BAD_INPUT;
            }
          }
        }
      }
    }

    return validationInfo;
  }