/**
   * Gets a SerialMessage with the PROTECTION_SET command
   *
   * @return the serial message, or null if the supported command is not supported.
   */
  public SerialMessage setValueMessage(LocalProtectionType localMode, RfProtectionType rfMode) {
    logger.debug("NODE {}: Creating new message for command PROTECTION_SET", getNode().getNodeId());

    SerialMessage result =
        new SerialMessage(
            getNode().getNodeId(),
            SerialMessageClass.SendData,
            SerialMessageType.Request,
            SerialMessageClass.SendData,
            SerialMessagePriority.Set);

    LocalProtectionType newLocalMode = localMode != null ? localMode : currentLocalMode;

    ByteArrayOutputStream outputData = new ByteArrayOutputStream();
    if (getVersion() < 2 || rfMode == null) {
      outputData.write(getNode().getNodeId());
      outputData.write(3);
      outputData.write(getCommandClass().getKey());
      outputData.write(PROTECTION_SET);
      outputData.write(newLocalMode.ordinal());
    } else {
      outputData.write(getNode().getNodeId());
      outputData.write(4);
      outputData.write(getCommandClass().getKey());
      outputData.write(PROTECTION_SET);
      outputData.write(newLocalMode.ordinal());
      outputData.write(rfMode.ordinal());
    }
    result.setMessagePayload(outputData.toByteArray());
    return result;
  }
  /**
   * {@inheritDoc}
   *
   * @throws ZWaveSerialMessageException
   */
  @Override
  public void handleApplicationCommandRequest(SerialMessage serialMessage, int offset, int endpoint)
      throws ZWaveSerialMessageException {
    logger.debug("NODE {}: Received PROTECTION command V{}", getNode().getNodeId(), getVersion());
    int command = serialMessage.getMessagePayloadByte(offset);
    switch (command) {
      case PROTECTION_REPORT:
        int localMode = serialMessage.getMessagePayloadByte(offset + 1) & 0x0f;

        if (localMode < LocalProtectionType.values().length) {
          currentLocalMode = LocalProtectionType.values()[localMode];
          ZWaveCommandClassValueEvent zEvent =
              new ZWaveCommandClassValueEvent(
                  getNode().getNodeId(),
                  endpoint,
                  getCommandClass(),
                  currentLocalMode,
                  Type.PROTECTION_LOCAL);
          getController().notifyEventListeners(zEvent);
        }
        if (getVersion() > 1) {
          int rfMode = serialMessage.getMessagePayloadByte(offset + 2) & 0x0f;
          if (rfMode < RfProtectionType.values().length) {
            ZWaveCommandClassValueEvent zEvent =
                new ZWaveCommandClassValueEvent(
                    getNode().getNodeId(),
                    endpoint,
                    getCommandClass(),
                    RfProtectionType.values()[rfMode],
                    Type.PROTECTION_RF);
            getController().notifyEventListeners(zEvent);
          }
          logger.debug(
              "NODE {}: Received protection report local:{} rf:{}",
              getNode().getNodeId(),
              LocalProtectionType.values()[localMode],
              RfProtectionType.values()[rfMode]);
        } else {
          logger.debug(
              "NODE {}: Received protection report local:{}",
              getNode().getNodeId(),
              LocalProtectionType.values()[localMode]);
        }

        dynamicDone = true;
        break;
      case PROTECTION_SUPPORTED_REPORT:
        boolean exclusive =
            ((serialMessage.getMessagePayloadByte(offset + 1) & EXCLUSIVE_CONTROL_BITMASK) != 0);
        boolean timeout =
            ((serialMessage.getMessagePayloadByte(offset + 1) & TIMEOUT_BITMASK) != 0);

        int localStateMask =
            (serialMessage.getMessagePayloadByte(offset + 2)
                | serialMessage.getMessagePayloadByte(offset + 3) << 8);
        int rfStateMask =
            (serialMessage.getMessagePayloadByte(offset + 4)
                | serialMessage.getMessagePayloadByte(offset + 5) << 8);

        LocalProtectionType localTypes[] = LocalProtectionType.values();
        for (int i = 0; i < localTypes.length; i++) {
          if ((localStateMask >> i & 0x01) > 0) {
            localModes.add(localTypes[i]);
          }
        }
        RfProtectionType rfTypes[] = RfProtectionType.values();
        for (int i = 0; i < rfTypes.length; i++) {
          if ((rfStateMask >> i & 0x01) > 0) {
            rfModes.add(rfTypes[i]);
          }
        }

        logger.debug(
            "NODE {}: Received protection supported report Exclusive({}), Timeout({}},  Local states={}, RF states={}",
            getNode().getNodeId(),
            exclusive ? "supported" : "Not supported",
            timeout ? "supported" : "Not supported",
            localModes,
            rfModes);
        supportedInitialised = true;
        break;

      default:
        logger.warn(
            String.format(
                "NODE %d: Unsupported Command %d for command class %s (0x%02X).",
                getNode().getNodeId(),
                command,
                getCommandClass().getLabel(),
                getCommandClass().getKey()));
    }
  }