text: /*
   * Copyright (c) SiteWhere, LLC. All rights reserved. http://www.sitewhere.com
   *
   * The software in this package is published under the terms of the CPAL v1.0
   * license, a copy of which has been included with this distribution in the
   * LICENSE.txt file.
   */
  package com.sitewhere.web.rest.controllers;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import javax.inject.Inject;
  import javax.ws.rs.Consumes;
  import javax.ws.rs.DELETE;
  import javax.ws.rs.DefaultValue;
  import javax.ws.rs.GET;
  import javax.ws.rs.POST;
  import javax.ws.rs.PUT;
  import javax.ws.rs.Path;
  import javax.ws.rs.PathParam;
  import javax.ws.rs.Produces;
  import javax.ws.rs.QueryParam;
  import javax.ws.rs.core.MediaType;
  import javax.ws.rs.core.Response;
  import javax.ws.rs.core.Response.Status;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.eclipse.microprofile.openapi.annotations.Operation;
  import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
  import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
  import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
  import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirements;
  import org.eclipse.microprofile.openapi.annotations.tags.Tag;
  
  import com.sitewhere.instance.spi.microservice.IInstanceManagementMicroservice;
  import com.sitewhere.microservice.api.device.DeviceTypeMarshalHelper;
  import com.sitewhere.microservice.api.device.IDeviceManagement;
  import com.sitewhere.microservice.api.label.ILabelGeneration;
  import com.sitewhere.rest.model.device.request.DeviceCommandCreateRequest;
  import com.sitewhere.rest.model.device.request.DeviceStatusCreateRequest;
  import com.sitewhere.rest.model.device.request.DeviceTypeCreateRequest;
  import com.sitewhere.rest.model.search.SearchCriteria;
  import com.sitewhere.rest.model.search.SearchResults;
  import com.sitewhere.spi.SiteWhereException;
  import com.sitewhere.spi.SiteWhereSystemException;
  import com.sitewhere.spi.device.IDeviceStatus;
  import com.sitewhere.spi.device.IDeviceType;
  import com.sitewhere.spi.device.command.IDeviceCommand;
  import com.sitewhere.spi.error.ErrorCode;
  import com.sitewhere.spi.error.ErrorLevel;
  import com.sitewhere.spi.label.ILabel;
  import com.sitewhere.spi.search.ISearchResults;
  
  import io.swagger.annotations.Api;
  
  /**
   * Controller for device specification operations.
   */
  @Path("/api/devicetypes")
  @Produces(MediaType.APPLICATION_JSON)
  @Consumes(MediaType.APPLICATION_JSON)
  @Api(value = "devicetypes")
  @Tag(name = "Device Types", description = "Device types define common characteristics for related devices.")
  @SecurityRequirements({ @SecurityRequirement(name = "jwtAuth", scopes = {}),
  	@SecurityRequirement(name = "tenantIdHeader", scopes = {}),
  	@SecurityRequirement(name = "tenantAuthHeader", scopes = {}) })
  public class DeviceTypes {
  
      /** Static logger instance */
      @SuppressWarnings("unused")
      private static Log LOGGER = LogFactory.getLog(DeviceTypes.class);
  
      @Inject
      private IInstanceManagementMicroservice<?> microservice;
  
      /**
       * Create a device type.
       * 
       * @param request
       * @return
       */
      @POST
      @Operation(summary = "Create new device type", description = "Create new device type")
      public Response createDeviceType(@RequestBody DeviceTypeCreateRequest request) throws SiteWhereException {
  	IDeviceType result = getDeviceManagement().createDeviceType(request);
  	DeviceTypeMarshalHelper helper = new DeviceTypeMarshalHelper(getDeviceManagement());
  	return Response.ok(helper.convert(result)).build();
      }
  
      /**
       * Get a device type by unique token.
       * 
       * @param token
       * @param includeAsset
       * @return
       * @throws SiteWhereException
       */
      @GET
      @Path("/{token}")
      @Operation(summary = "Get device type by unique token", description = "Get device type by unique token")
      public Response getDeviceTypeByToken(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @Parameter(description = "Include detailed asset information", required = false) @QueryParam("includeAsset") @DefaultValue("true") boolean includeAsset)
  	    throws SiteWhereException {
  	IDeviceType result = assertDeviceTypeByToken(token);
  	DeviceTypeMarshalHelper helper = new DeviceTypeMarshalHelper(getDeviceManagement());
  	return Response.ok(helper.convert(result)).build();
      }
  
      /**
       * Update an existing device type.
       * 
       * @param token
       * @param request
       * @return
       * @throws SiteWhereException
       */
      @PUT
      @Path("/{token}")
      @Operation(summary = "Update existing device type", description = "Update existing device type")
      public Response updateDeviceType(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @RequestBody DeviceTypeCreateRequest request) throws SiteWhereException {
  	IDeviceType deviceType = assertDeviceTypeByToken(token);
  	IDeviceType result = getDeviceManagement().updateDeviceType(deviceType.getId(), request);
  	DeviceTypeMarshalHelper helper = new DeviceTypeMarshalHelper(getDeviceManagement());
  	return Response.ok(helper.convert(result)).build();
      }
  
      /**
       * Get label for device type based on a specific generator.
       * 
       * @param token
       * @param generatorId
       * @return
       * @throws SiteWhereException
       */
      @GET
      @Path("/{token}/label/{generatorId}")
      @Operation(summary = "Get label for device type", description = "Get label for device type")
      public Response getDeviceTypeLabel(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @Parameter(description = "Generator id", required = true) @PathParam("generatorId") String generatorId)
  	    throws SiteWhereException {
  	IDeviceType deviceType = assertDeviceTypeByToken(token);
  	ILabel label = getLabelGeneration().getDeviceTypeLabel(generatorId, deviceType.getId());
  	if (label == null) {
  	    return Response.status(Status.NOT_FOUND).build();
  	}
  	return Response.ok(label.getContent()).build();
      }
  
      /**
       * List device types that meet the given criteria.
       * 
       * @param token
       * @param page
       * @param pageSize
       * @return
       * @throws SiteWhereException
       */
      @GET
      @Operation(summary = "List device types that match criteria", description = "List device types that match criteria")
      public Response listDeviceTypes(
  	    @Parameter(description = "Page number", required = false) @QueryParam("page") @DefaultValue("1") int page,
  	    @Parameter(description = "Page size", required = false) @QueryParam("pageSize") @DefaultValue("100") int pageSize)
  	    throws SiteWhereException {
  	SearchCriteria criteria = new SearchCriteria(page, pageSize);
  	ISearchResults<? extends IDeviceType> results = getDeviceManagement().listDeviceTypes(criteria);
  	DeviceTypeMarshalHelper helper = new DeviceTypeMarshalHelper(getDeviceManagement());
  	List<IDeviceType> typesConv = new ArrayList<IDeviceType>();
  	for (IDeviceType type : results.getResults()) {
  	    typesConv.add(helper.convert(type));
  	}
  	return Response.ok(new SearchResults<IDeviceType>(typesConv, results.getNumResults())).build();
      }
  
      /**
       * Delete an existing device type.
       * 
       * @param token
       * @return
       * @throws SiteWhereException
       */
      @DELETE
      @Path("/{token}")
      @Operation(summary = "Delete existing device type", description = "Delete existing device type")
      public Response deleteDeviceType(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token)
  	    throws SiteWhereException {
  	IDeviceType existing = assertDeviceTypeByToken(token);
  	IDeviceType result = getDeviceManagement().deleteDeviceType(existing.getId());
  	DeviceTypeMarshalHelper helper = new DeviceTypeMarshalHelper(getDeviceManagement());
  	return Response.ok(helper.convert(result)).build();
      }
  
      /**
       * Create a device command.
       * 
       * @param token
       * @param request
       * @return
       * @throws SiteWhereException
       */
      @POST
      @Path("/{token}/commands")
      @Operation(summary = "Create device command", description = "Create device command")
      public Response createDeviceCommand(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @RequestBody DeviceCommandCreateRequest request) throws SiteWhereException {
  	return Response.ok(getDeviceManagement().createDeviceCommand(request)).build();
      }
  
      /**
       * Get a device command by unique token.
       * 
       * @param token
       * @param commandToken
       * @return
       * @throws SiteWhereException
       */
      @GET
      @Path("/{token}/commands/{commandToken}")
      @Operation(summary = "Get device command by unique token", description = "Get device command by unique token")
      public Response getDeviceCommandByToken(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @Parameter(description = "Command Token", required = true) @PathParam("commandToken") String commandToken)
  	    throws SiteWhereException {
  	IDeviceType existing = assertDeviceTypeByToken(token);
  	IDeviceCommand command = getDeviceManagement().getDeviceCommandByToken(existing.getId(), commandToken);
  	return Response.ok(command).build();
      }
  
      /**
       * Update an existing device command.
       * 
       * @param token
       * @param commandToken
       * @param request
       * @return
       * @throws SiteWhereException
       */
      @PUT
      @Path("/{token}/commands/{commandToken}")
      @Operation(summary = "Update an existing device command", description = "Update an existing device command")
      public Response updateDeviceCommand(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @Parameter(description = "Command Token", required = true) @PathParam("commandToken") String commandToken,
  	    @RequestBody DeviceCommandCreateRequest request) throws SiteWhereException {
  	IDeviceType existing = assertDeviceTypeByToken(token);
  	IDeviceCommand command = getDeviceManagement().getDeviceCommandByToken(existing.getId(), commandToken);
  	return Response.ok(getDeviceManagement().updateDeviceCommand(command.getId(), request)).build();
      }
  
      /**
       * Delete an existing device command.
       * 
       * @param token
       * @param commandToken
       * @return
       * @throws SiteWhereException
       */
      @DELETE
      @Path("/{token}/commands/{commandToken}")
      @Operation(summary = "Delete device command", description = "Delete device command by unique token")
      public Response deleteDeviceCommand(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @Parameter(description = "Command Token", required = true) @PathParam("commandToken") String commandToken)
  	    throws SiteWhereException {
  	IDeviceType existing = assertDeviceTypeByToken(token);
  	IDeviceCommand command = getDeviceManagement().getDeviceCommandByToken(existing.getId(), commandToken);
  	return Response.ok(getDeviceManagement().deleteDeviceCommand(command.getId())).build();
      }
  
      /**
       * Create a device status.
       * 
       * @param token
       * @param request
       * @return
       * @throws SiteWhereException
       */
      @POST
      @Path("/{token}/statuses")
      @Operation(summary = "Create device status", description = "Create device status")
      public Response createDeviceStatus(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @RequestBody DeviceStatusCreateRequest request) throws SiteWhereException {
  	return Response.ok(getDeviceManagement().createDeviceStatus(request)).build();
      }
  
      /**
       * Get device status by unique token.
       * 
       * @param token
       * @param statusToken
       * @return
       * @throws SiteWhereException
       */
      @GET
      @Path("/{token}/statuses/{statusToken}")
      @Operation(summary = "Get device status by unique token", description = "Get device status by unique token")
      public Response getDeviceStatusByToken(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @Parameter(description = "Status Token", required = true) @PathParam("statusToken") String statusToken)
  	    throws SiteWhereException {
  	IDeviceType existing = assertDeviceTypeByToken(token);
  	IDeviceStatus status = getDeviceManagement().getDeviceStatusByToken(existing.getId(), statusToken);
  	return Response.ok(status).build();
      }
  
      /**
       * Update an existing device status.
       * 
       * @param token
       * @param statusToken
       * @param request
       * @return
       * @throws SiteWhereException
       */
      @PUT
      @Path("/{token}/statuses/{statusToken}")
      @Operation(summary = "Update an existing device status", description = "Update an existing device status")
      public Response updateDeviceStatus(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @Parameter(description = "Status Token", required = true) @PathParam("statusToken") String statusToken,
  	    @RequestBody DeviceStatusCreateRequest request) throws SiteWhereException {
  	IDeviceType existing = assertDeviceTypeByToken(token);
  	IDeviceStatus status = getDeviceManagement().getDeviceStatusByToken(existing.getId(), statusToken);
  	return Response.ok(getDeviceManagement().updateDeviceStatus(status.getId(), request)).build();
      }
  
      /**
       * Delete an existing device command.
       * 
       * @param token
       * @param statusToken
       * @return
       * @throws SiteWhereException
       */
      @DELETE
      @Path("/{token}/statuses/{statusToken}")
      @Operation(summary = "Delete device status", description = "Delete device status by unique token")
      public Response deleteDeviceStatus(
  	    @Parameter(description = "Token", required = true) @PathParam("token") String token,
  	    @Parameter(description = "Status Token", required = true) @PathParam("statusToken") String statusToken)
  	    throws SiteWhereException {
  	IDeviceType existing = assertDeviceTypeByToken(token);
  	IDeviceStatus status = getDeviceManagement().getDeviceStatusByToken(existing.getId(), statusToken);
  	return Response.ok(getDeviceManagement().deleteDeviceStatus(status.getId())).build();
      }
  
      /**
       * Gets a device type by token and throws an exception if not found.
       * 
       * @param token
       * @return
       * @throws SiteWhereException
       */
      protected IDeviceType assertDeviceTypeByToken(String token) throws SiteWhereException {
  	IDeviceType result = getDeviceManagement().getDeviceTypeByToken(token);
  	if (result == null) {
  	    throw new SiteWhereSystemException(ErrorCode.InvalidDeviceTypeToken, ErrorLevel.ERROR);
  	}
  	return result;
      }
  
      protected IDeviceManagement getDeviceManagement() {
  	return getMicroservice().getDeviceManagement();
      }
  
      protected ILabelGeneration getLabelGeneration() {
  	return getMicroservice().getLabelGenerationApiChannel();
      }
  
      protected IInstanceManagementMicroservice<?> getMicroservice() {
  	return microservice;
      }
  }