/*
   * This endpoint can be tested with:
   *
   * $ mvn clean spring-boot:run $ curl -iH "Accept: application/json;v=1" -H
   * "Content-Type: application/json" -X PUT -d \
   * '{"reportVersion":{"reportVersionId":
   * "7ff1da11-a229-45c5-90be-79417a628125"},"orderIndex":999,\
   * "controlType":0,"promptText":"New prompt text","required":false,\
   * "defaultValue":"new default value","displayName":"new display name",\
   * "helpText":"new help text","displayFormat":"new display format",\
   * "alignment":3,"allowNewValues":true,\
   * "parameterGroup":{"parameterGroupId":
   * "abc81f46-3940-44bb-a401-d937c55a10bc"}}' \
   * http://localhost:8080/rest/reportParameters/fecd8f20-5ff0-4b0f-ae0c-
   * 0829cea1c938
   *
   * All UUID values must be replaced here with actual resource id's from the
   * report server database, of course.
   *
   * If the ReportParameter to be updated is not linked to a ParameterGroup,
   * then the "parameterGroup" attribute in the PUT data should be omitted
   * entirely.
   */
  @Path("/{id}")
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  @PreAuthorize("hasAuthority('" + Authority.AUTHORITY_NAME_MANAGE_REPORTS + "')")
  public Response updateById(
      ReportParameterResource reportParameterResource,
      @PathParam("id") final UUID id,
      @HeaderParam("Accept") final String acceptHeader,
      @QueryParam(ResourcePath.EXPAND_QP_NAME) final List<String> expand,
      @QueryParam(ResourcePath.SHOWALL_QP_NAME) final List<String> showAll,
      @Context final ServletContext servletContext,
      @Context final UriInfo uriInfo) {
    Map<String, List<String>> queryParams = new HashMap<>();
    queryParams.put(ResourcePath.EXPAND_QP_KEY, expand);
    queryParams.put(ResourcePath.SHOWALL_QP_KEY, showAll);
    RestApiVersion apiVersion = RestUtils.extractAPIVersion(acceptHeader, RestApiVersion.v1);

    /*
     * Retrieve ReportParameter entity to be updated.
     */
    ReportParameter reportParameter = reportParameterRepository.findOne(id);
    RestUtils.ifNullThen404(reportParameter, ReportParameter.class, "reportId", id.toString());

    /*
     * Treat attributes of reportParameterResource that are effectively
     * required. These attributes can be omitted in the PUT data, but in
     * that case they are then set here to the CURRENT values from the
     * ReportParameter entity. These are that attributes that are required,
     * but if their value does not need to be changed, they do not need to
     * be included in the PUT data.
     */
    if (reportParameterResource.getOrderIndex() == null) {
      reportParameterResource.setOrderIndex(reportParameter.getOrderIndex());
    }
    if (reportParameterResource.getControlType() == null) {
      reportParameterResource.setControlType(reportParameter.getControlType());
    }
    if (reportParameterResource.getValueConcealed() == null) {
      reportParameterResource.setValueConcealed(reportParameter.getValueConcealed());
    }
    if (reportParameterResource.getAllowNewValues() == null) {
      reportParameterResource.setAllowNewValues(reportParameter.getAllowNewValues());
    }
    if (reportParameterResource.getAlignment() == null) {
      reportParameterResource.setAlignment(reportParameter.getAlignment());
    }
    if (reportParameterResource.getPromptText() == null) {
      reportParameterResource.setPromptText(reportParameter.getPromptText());
    }

    /*
     * The values for the following attributes cannot be changed. These
     * attributes should not appear in the PUT data, but if any do, their
     * values will not be used because they will be overridden here by
     * forcing their values to be the same as the current value stored for
     * the ReportParameter entity.
     */
    reportParameterResource.setReportParameterId(reportParameter.getReportParameterId());
    reportParameterResource.setName(reportParameter.getName());
    reportParameterResource.setDataType(reportParameter.getDataType());
    reportParameterResource.setRequired(reportParameter.getRequired());
    reportParameterResource.setMultivalued(reportParameter.getMultivalued());
    reportParameterResource.setHidden(reportParameter.getHidden());
    reportParameterResource.setDisplayInFixedOrder(reportParameter.getDisplayInFixedOrder());
    reportParameterResource.setParameterType(reportParameter.getParameterType());
    reportParameterResource.setSelectionListType(reportParameter.getSelectionListType());
    reportParameterResource.setAutoSuggestThreshold(reportParameter.getAutoSuggestThreshold());
    reportParameterResource.setValueExpr(reportParameter.getValueExpr());
    reportParameterResource.setCreatedOn(reportParameter.getCreatedOn());
    /*
     * Construct a ReportVersionResource to specify the CURRENTLY
     * selected ReportVersion.
     */
    UUID currentReportVersionId = reportParameter.getReportVersion().getReportVersionId();
    ReportVersionResource reportVersionResource = new ReportVersionResource();
    reportVersionResource.setReportVersionId(currentReportVersionId);
    reportParameterResource.setReportVersionResource(reportVersionResource);

    /*
     * The values of the following attributes be *cleared* if they do not
     * appear in the PUT data. These are attributes where SQL NULL is a
     * legal value in the underlying database [report_parameter] table.
     *
     *   defaultValue
     *   displayFormat
     *   parameterGroup
     *   displayName
     *   helpText
     */

    /*
     * Although the parameterGroup attribute can be omitted from the PUT
     * data, if it *is* present, the ParameterGroupResource resource *must*
     * have a value for its parameterGroupId attribute.
     */
    if (reportParameterResource.getParameterGroupResource() != null) {
      /*
       * If a "reportParameterResource" attribute *is* supplied in the PUT
       * data, it *must* have a value set for its "reportParameterId"
       * attribute...
       */
      RestUtils.ifAttrNullOrBlankThen403(
          reportParameterResource.getParameterGroupResource().getParameterGroupId(),
          ParameterGroup.class,
          "parameterGroupId");
      /*
       * ... and the value for "parameterGroupId" must correspond to an
       * existing ParameterGroup entity.
       */
      UUID parameterGroupId =
          reportParameterResource.getParameterGroupResource().getParameterGroupId();
      RestUtils.ifNullThen404(
          parameterGroupRepository.findOne(parameterGroupId),
          ParameterGroup.class,
          "parameterGroupId",
          parameterGroupId.toString());
    }

    /*
     * Save updated entity.
     */
    reportParameter = reportParameterService.saveExistingFromResource(reportParameterResource);

    return Response.status(Response.Status.OK).build();
  }