/**
   * Checks that a given concept map type object is valid.
   *
   * @see org.springframework.validation.Validator#validate(java.lang.Object,
   *     org.springframework.validation.Errors)
   * @should fail if the concept map type object is null
   * @should fail if the name is null
   * @should fail if the name is an empty string
   * @should fail if the name is a white space character
   * @should fail if the concept map type name is a duplicate
   * @should pass if the name is unique amongst all concept map type names
   * @should pass validation if field lengths are correct
   * @should fail validation if field lengths are not correct
   */
  public void validate(Object obj, Errors errors) {

    if (obj == null || !(obj instanceof ConceptMapType)) {
      throw new IllegalArgumentException(
          "The parameter obj should not be null and must be of type" + ConceptMapType.class);
    }

    ConceptMapType conceptMapType = (ConceptMapType) obj;
    String name = conceptMapType.getName();
    if (!StringUtils.hasText(name)) {
      errors.rejectValue(
          "name",
          "ConceptMapType.error.nameRequired",
          "The name property is required for a concept map type");
      return;
    }

    name = name.trim();
    ConceptMapType duplicate = Context.getConceptService().getConceptMapTypeByName(name);
    if (duplicate != null
        && !OpenmrsUtil.nullSafeEquals(duplicate.getUuid(), conceptMapType.getUuid())) {
      errors.rejectValue(
          "name", "ConceptMapType.duplicate.name", "Duplicate concept map type name: " + name);
    }
    ValidateUtil.validateFieldLengths(
        errors, obj.getClass(), "name", "description", "retireReason");
  }
  /**
   * Processes requests to save/update a concept map type
   *
   * @param request the {@link WebRequest} object
   * @param conceptMapType the concept map type object to save/update
   * @param result the {@link BindingResult} object
   * @return the url to redirect to
   */
  @RequestMapping(method = RequestMethod.POST, value = CONCEPT_MAP_TYPE_FORM_URL)
  public String saveConceptMapType(
      WebRequest request,
      @ModelAttribute("conceptMapType") ConceptMapType conceptMapType,
      BindingResult result) {

    new ConceptMapTypeValidator().validate(conceptMapType, result);
    if (!result.hasErrors()) {
      try {
        Context.getConceptService().saveConceptMapType(conceptMapType);
        if (log.isDebugEnabled()) {
          log.debug("Saved concept map type: " + conceptMapType.toString());
        }
        request.setAttribute(
            WebConstants.OPENMRS_MSG_ATTR, "ConceptMapType.saved", WebRequest.SCOPE_SESSION);

        return "redirect:" + CONCEPT_MAP_TYPE_LIST_URL + ".list";
      } catch (APIException e) {
        log.error("Error while saving concept map type(s)", e);
        request.setAttribute(
            WebConstants.OPENMRS_ERROR_ATTR, "ConceptMapType.save.error", WebRequest.SCOPE_SESSION);
      }
    }

    // there was an error
    return CONCEPT_MAP_TYPE_FORM;
  }
  /**
   * Processes requests to unretire a concept map type
   *
   * @param request the {@link WebRequest} object
   * @param conceptMapType the concept map type object to unretire
   * @return the url to redirect to
   */
  @RequestMapping(method = RequestMethod.POST, value = "/admin/concepts/unretireConceptMapType")
  public String unretireConceptMapType(
      WebRequest request, @ModelAttribute(value = "conceptMapType") ConceptMapType conceptMapType) {

    try {
      Context.getConceptService().unretireConceptMapType(conceptMapType);
      if (log.isDebugEnabled()) {
        log.debug("Unretired concept map type with id: " + conceptMapType.getId());
      }
      request.setAttribute(
          WebConstants.OPENMRS_MSG_ATTR,
          Context.getMessageSourceService().getMessage("ConceptMapType.unretired"),
          WebRequest.SCOPE_SESSION);

      return "redirect:" + CONCEPT_MAP_TYPE_LIST_URL + ".list";
    } catch (APIException e) {
      log.error("Error occurred while attempting to unretire concept map type", e);
      request.setAttribute(
          WebConstants.OPENMRS_ERROR_ATTR,
          Context.getMessageSourceService().getMessage("ConceptMapType.unretire.error"),
          WebRequest.SCOPE_SESSION);
    }

    // an error occurred
    return CONCEPT_MAP_TYPE_FORM;
  }
  /**
   * Processes requests to retire a concept map type
   *
   * @param request the {@link WebRequest} object
   * @param conceptMapType the concept map type object to retire
   * @param retireReason the reason why the concept map type is getting retired
   * @return the url to redirect to
   */
  @RequestMapping(method = RequestMethod.POST, value = "/admin/concepts/retireConceptMapType")
  public String retireConceptMapType(
      WebRequest request,
      @ModelAttribute(value = "conceptMapType") ConceptMapType conceptMapType,
      @RequestParam(required = false, value = "retireReason") String retireReason) {

    if (!StringUtils.hasText(retireReason)) {
      retireReason = Context.getMessageSourceService().getMessage("general.default.retireReason");
    }

    try {
      Context.getConceptService().retireConceptMapType(conceptMapType, retireReason);
      if (log.isDebugEnabled()) {
        log.debug("Retired concept map type with id: " + conceptMapType.getId());
      }
      request.setAttribute(
          WebConstants.OPENMRS_MSG_ATTR,
          Context.getMessageSourceService().getMessage("ConceptMapType.retired"),
          WebRequest.SCOPE_SESSION);

      return "redirect:" + CONCEPT_MAP_TYPE_LIST_URL + ".list";
    } catch (APIException e) {
      log.error("Error occurred while attempting to retire concept map type", e);
      request.setAttribute(
          WebConstants.OPENMRS_ERROR_ATTR,
          Context.getMessageSourceService().getMessage("ConceptMapType.retire.error"),
          WebRequest.SCOPE_SESSION);
    }

    // an error occurred
    return CONCEPT_MAP_TYPE_FORM;
  }
  /**
   * Processes requests to purge a concept map type
   *
   * @param request the {@link WebRequest} object
   * @param conceptMapType
   * @return the url to forward to
   */
  @RequestMapping(method = RequestMethod.POST, value = "/admin/concepts/purgeConceptMapType")
  public String purgeTerm(
      WebRequest request, @ModelAttribute(value = "conceptMapType") ConceptMapType conceptMapType) {
    Integer id = conceptMapType.getId();
    try {
      Context.getConceptService().purgeConceptMapType(conceptMapType);
      if (log.isDebugEnabled()) {
        log.debug("Purged concept map type with id: " + id);
      }
      request.setAttribute(
          WebConstants.OPENMRS_MSG_ATTR,
          Context.getMessageSourceService().getMessage("ConceptMapType.purged"),
          WebRequest.SCOPE_SESSION);
      return "redirect:" + CONCEPT_MAP_TYPE_LIST_URL + ".list";
    } catch (APIException e) {
      log.warn("Error occurred while attempting to purge concept map type", e);
      request.setAttribute(
          WebConstants.OPENMRS_ERROR_ATTR,
          Context.getMessageSourceService().getMessage("ConceptMapType.purge.error"),
          WebRequest.SCOPE_SESSION);
    }

    return "redirect:" + CONCEPT_MAP_TYPE_FORM_URL + ".form?conceptMapTypeId=" + id;
  }