/**
 * Copyright (c) 2016-2017 by the respective copyright holders.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package com.zsmartsystems.zwave.commandclass.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Class to implement the Z-Wave command class <b>COMMAND_CLASS_HUMIDITY_CONTROL_SETPOINT</b> version <b>1</b>.
 * <p>
 * Command Class Humidity Control Setpoint
 * <p>
 * This class provides static methods for processing received messages (message handler) and
 * methods to get a message to send on the Z-Wave network.
 * <p>
 * Command class key is 0x64.
 * <p>
 * Note that this code is autogenerated. Manual changes may be overwritten.
 *
 * @author Chris Jackson - Initial contribution of Java code generator
 */
public class CommandClassHumidityControlSetpointV1 {
    private static final Logger logger = LoggerFactory.getLogger(CommandClassHumidityControlSetpointV1.class);

    /**
     * Integer command class key for COMMAND_CLASS_HUMIDITY_CONTROL_SETPOINT
     */
    public final static int COMMAND_CLASS_KEY = 0x64;

    /**
     * Humidity Control Setpoint Set Command Constant
     */
    public final static int HUMIDITY_CONTROL_SETPOINT_SET = 0x01;
    /**
     * Humidity Control Setpoint Get Command Constant
     */
    public final static int HUMIDITY_CONTROL_SETPOINT_GET = 0x02;
    /**
     * Humidity Control Setpoint Report Command Constant
     */
    public final static int HUMIDITY_CONTROL_SETPOINT_REPORT = 0x03;
    /**
     * Humidity Control Setpoint Supported Get Command Constant
     */
    public final static int HUMIDITY_CONTROL_SETPOINT_SUPPORTED_GET = 0x04;
    /**
     * Humidity Control Setpoint Supported Report Command Constant
     */
    public final static int HUMIDITY_CONTROL_SETPOINT_SUPPORTED_REPORT = 0x05;
    /**
     * Humidity Control Setpoint Scale Supported Get Command Constant
     */
    public final static int HUMIDITY_CONTROL_SETPOINT_SCALE_SUPPORTED_GET = 0x06;
    /**
     * Humidity Control Setpoint Scale Supported Report Command Constant
     */
    public final static int HUMIDITY_CONTROL_SETPOINT_SCALE_SUPPORTED_REPORT = 0x07;
    /**
     * Humidity Control Setpoint Capabilities Get Command Constant
     */
    public final static int HUMIDITY_CONTROL_SETPOINT_CAPABILITIES_GET = 0x08;
    /**
     * Humidity Control Setpoint Capabilities Report Command Constant
     */
    public final static int HUMIDITY_CONTROL_SETPOINT_CAPABILITIES_REPORT = 0x09;

    /**
     * Map holding constants for HumidityControlSetpointGetSetpointType
     */
    private static Map<Integer, String> constantHumidityControlSetpointGetSetpointType = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointCapabilitiesGetSetpointType
     */
    private static Map<Integer, String> constantHumidityControlSetpointCapabilitiesGetSetpointType = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointSupportedReportBitMask
     */
    private static Map<Integer, String> constantHumidityControlSetpointSupportedReportBitMask = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointScaleSupportedGetSetpointType
     */
    private static Map<Integer, String> constantHumidityControlSetpointScaleSupportedGetSetpointType = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointSetSetpointType
     */
    private static Map<Integer, String> constantHumidityControlSetpointSetSetpointType = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointReportScale
     */
    private static Map<Integer, String> constantHumidityControlSetpointReportScale = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointCapabilitiesReportSetpointType
     */
    private static Map<Integer, String> constantHumidityControlSetpointCapabilitiesReportSetpointType = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointReportSetpointType
     */
    private static Map<Integer, String> constantHumidityControlSetpointReportSetpointType = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointCapabilitiesReportScale2
     */
    private static Map<Integer, String> constantHumidityControlSetpointCapabilitiesReportScale2 = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointCapabilitiesReportScale1
     */
    private static Map<Integer, String> constantHumidityControlSetpointCapabilitiesReportScale1 = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointScaleSupportedReportScaleBitMask
     */
    private static Map<Integer, String> constantHumidityControlSetpointScaleSupportedReportScaleBitMask = new HashMap<Integer, String>();

    /**
     * Map holding constants for HumidityControlSetpointSetScale
     */
    private static Map<Integer, String> constantHumidityControlSetpointSetScale = new HashMap<Integer, String>();

    static {
        // Constants for HumidityControlSetpointGetSetpointType
        constantHumidityControlSetpointGetSetpointType.put(0x00, "HUMIDIFIER");
        constantHumidityControlSetpointGetSetpointType.put(0x01, "DEHUMIDIFIER");

        // Constants for HumidityControlSetpointCapabilitiesGetSetpointType
        constantHumidityControlSetpointCapabilitiesGetSetpointType.put(0x00, "HUMIDIFIER");
        constantHumidityControlSetpointCapabilitiesGetSetpointType.put(0x01, "DEHUMIDIFIER");

        // Constants for HumidityControlSetpointSupportedReportBitMask
        constantHumidityControlSetpointSupportedReportBitMask.put(0x01, "HUMIDIFIER");
        constantHumidityControlSetpointSupportedReportBitMask.put(0x02, "DEHUMIDIFIER");

        // Constants for HumidityControlSetpointScaleSupportedGetSetpointType
        constantHumidityControlSetpointScaleSupportedGetSetpointType.put(0x00, "HUMIDIFIER");
        constantHumidityControlSetpointScaleSupportedGetSetpointType.put(0x01, "DEHUMIDIFIER");

        // Constants for HumidityControlSetpointSetSetpointType
        constantHumidityControlSetpointSetSetpointType.put(0x00, "HUMIDIFIER");
        constantHumidityControlSetpointSetSetpointType.put(0x01, "DEHUMIDIFIER");

        // Constants for HumidityControlSetpointReportScale
        constantHumidityControlSetpointReportScale.put(0x00, "PERCENTAGE");
        constantHumidityControlSetpointReportScale.put(0x01, "ABSOLUTE");

        // Constants for HumidityControlSetpointCapabilitiesReportSetpointType
        constantHumidityControlSetpointCapabilitiesReportSetpointType.put(0x00, "HUMIDIFIER");
        constantHumidityControlSetpointCapabilitiesReportSetpointType.put(0x01, "DEHUMIDIFIER");

        // Constants for HumidityControlSetpointReportSetpointType
        constantHumidityControlSetpointReportSetpointType.put(0x00, "HUMIDIFIER");
        constantHumidityControlSetpointReportSetpointType.put(0x01, "DEHUMIDIFIER");

        // Constants for HumidityControlSetpointCapabilitiesReportScale2
        constantHumidityControlSetpointCapabilitiesReportScale2.put(0x00, "PERCENTAGE");
        constantHumidityControlSetpointCapabilitiesReportScale2.put(0x01, "ABSOLUTE");

        // Constants for HumidityControlSetpointCapabilitiesReportScale1
        constantHumidityControlSetpointCapabilitiesReportScale1.put(0x00, "PERCENTAGE");
        constantHumidityControlSetpointCapabilitiesReportScale1.put(0x01, "ABSOLUTE");

        // Constants for HumidityControlSetpointScaleSupportedReportScaleBitMask
        constantHumidityControlSetpointScaleSupportedReportScaleBitMask.put(0x00, "PERCENTAGE");
        constantHumidityControlSetpointScaleSupportedReportScaleBitMask.put(0x01, "ABSOLUTE");

        // Constants for HumidityControlSetpointSetScale
        constantHumidityControlSetpointSetScale.put(0x00, "PERCENTAGE");
        constantHumidityControlSetpointSetScale.put(0x01, "ABSOLUTE");
    }

    /**
     * Creates a new message with the HUMIDITY_CONTROL_SETPOINT_SET command.
     * <p>
     * Humidity Control Setpoint Set
     *
     * @param setpointType {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>HUMIDIFIER
     *            <li>DEHUMIDIFIER
     *            </ul>
     * @param scale {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>PERCENTAGE
     *            <li>ABSOLUTE
     *            </ul>
     * @param precision {@link Integer}
     * @param value {@link byte[]}
     * @return the {@link byte[]} array with the command to send
     */
    static public byte[] getHumidityControlSetpointSet(String setpointType, String scale, Integer precision,
            byte[] value) {
        logger.debug("Creating command message HUMIDITY_CONTROL_SETPOINT_SET version 1");

        ByteArrayOutputStream outputData = new ByteArrayOutputStream();
        outputData.write(COMMAND_CLASS_KEY);
        outputData.write(HUMIDITY_CONTROL_SETPOINT_SET);

        // Process 'Properties1'
        int varSetpointType = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointSetSetpointType.keySet()) {
            if (constantHumidityControlSetpointSetSetpointType.get(entry).equals(setpointType)) {
                varSetpointType = entry;
                break;
            }
        }
        if (varSetpointType == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + setpointType + "' for setpointType");
        }
        outputData.write(varSetpointType & 0x0F);

        // Process 'Properties2'
        // Size is used by 'Value'
        int size = value.length;
        int valProperties2 = 0;
        valProperties2 |= size & 0x07;
        int varScale = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointSetScale.keySet()) {
            if (constantHumidityControlSetpointSetScale.get(entry).equals(scale)) {
                varScale = entry;
                break;
            }
        }
        if (varScale == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + scale + "' for scale");
        }
        valProperties2 |= varScale << 3 & 0x18;
        valProperties2 |= ((precision << 5) & 0xE0);
        outputData.write(valProperties2);

        // Process 'Value'
        if (value != null) {
            try {
                outputData.write(value);
            } catch (IOException e) {
            }
        }

        return outputData.toByteArray();
    }

    /**
     * Processes a received frame with the HUMIDITY_CONTROL_SETPOINT_SET command.
     * <p>
     * Humidity Control Setpoint Set
     * <p>
     * The output data {@link Map} has the following properties -:
     *
     * <ul>
     * <li>SETPOINT_TYPE {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>HUMIDIFIER
     * <li>DEHUMIDIFIER
     * </ul>
     * <li>SCALE {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>PERCENTAGE
     * <li>ABSOLUTE
     * </ul>
     * <li>PRECISION {@link Integer}
     * <li>VALUE {@link byte[]}
     * </ul>
     *
     * @param payload the {@link byte[]} payload data to process
     * @return a {@link Map} of processed response data
     */
    public static Map<String, Object> handleHumidityControlSetpointSet(byte[] payload) {
        // Create our response map
        Map<String, Object> response = new HashMap<String, Object>();

        // We're using variable length fields, so track the offset
        int msgOffset = 2;

        // Process 'Properties1'
        response.put("SETPOINT_TYPE", constantHumidityControlSetpointSetSetpointType.get(payload[msgOffset] & 0x0F));
        msgOffset += 1;

        // Process 'Properties2'
        // Size is used by 'Value'
        int varSize = payload[msgOffset] & 0x07;
        response.put("SCALE", constantHumidityControlSetpointSetScale.get((payload[msgOffset] & 0x18) >> 3));
        response.put("PRECISION", Integer.valueOf(payload[msgOffset] & 0xE0 >> 5));
        msgOffset += 1;

        // Process 'Value'
        ByteArrayOutputStream valValue = new ByteArrayOutputStream();
        for (int cntValue = 0; cntValue < varSize; cntValue++) {
            valValue.write(payload[msgOffset + cntValue]);
        }
        response.put("VALUE", valValue.toByteArray());
        msgOffset += varSize;

        // Return the map of processed response data;
        return response;
    }

    /**
     * Creates a new message with the HUMIDITY_CONTROL_SETPOINT_GET command.
     * <p>
     * Humidity Control Setpoint Get
     *
     * @param setpointType {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>HUMIDIFIER
     *            <li>DEHUMIDIFIER
     *            </ul>
     * @return the {@link byte[]} array with the command to send
     */
    static public byte[] getHumidityControlSetpointGet(String setpointType) {
        logger.debug("Creating command message HUMIDITY_CONTROL_SETPOINT_GET version 1");

        ByteArrayOutputStream outputData = new ByteArrayOutputStream();
        outputData.write(COMMAND_CLASS_KEY);
        outputData.write(HUMIDITY_CONTROL_SETPOINT_GET);

        // Process 'Properties1'
        int varSetpointType = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointGetSetpointType.keySet()) {
            if (constantHumidityControlSetpointGetSetpointType.get(entry).equals(setpointType)) {
                varSetpointType = entry;
                break;
            }
        }
        if (varSetpointType == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + setpointType + "' for setpointType");
        }
        outputData.write(varSetpointType & 0x0F);

        return outputData.toByteArray();
    }

    /**
     * Processes a received frame with the HUMIDITY_CONTROL_SETPOINT_GET command.
     * <p>
     * Humidity Control Setpoint Get
     * <p>
     * The output data {@link Map} has the following properties -:
     *
     * <ul>
     * <li>SETPOINT_TYPE {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>HUMIDIFIER
     * <li>DEHUMIDIFIER
     * </ul>
     * </ul>
     *
     * @param payload the {@link byte[]} payload data to process
     * @return a {@link Map} of processed response data
     */
    public static Map<String, Object> handleHumidityControlSetpointGet(byte[] payload) {
        // Create our response map
        Map<String, Object> response = new HashMap<String, Object>();

        // Process 'Properties1'
        response.put("SETPOINT_TYPE", constantHumidityControlSetpointGetSetpointType.get(payload[2] & 0x0F));

        // Return the map of processed response data;
        return response;
    }

    /**
     * Creates a new message with the HUMIDITY_CONTROL_SETPOINT_REPORT command.
     * <p>
     * Humidity Control Setpoint Report
     *
     * @param setpointType {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>HUMIDIFIER
     *            <li>DEHUMIDIFIER
     *            </ul>
     * @param scale {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>PERCENTAGE
     *            <li>ABSOLUTE
     *            </ul>
     * @param precision {@link Integer}
     * @param value {@link byte[]}
     * @return the {@link byte[]} array with the command to send
     */
    static public byte[] getHumidityControlSetpointReport(String setpointType, String scale, Integer precision,
            byte[] value) {
        logger.debug("Creating command message HUMIDITY_CONTROL_SETPOINT_REPORT version 1");

        ByteArrayOutputStream outputData = new ByteArrayOutputStream();
        outputData.write(COMMAND_CLASS_KEY);
        outputData.write(HUMIDITY_CONTROL_SETPOINT_REPORT);

        // Process 'Properties1'
        int varSetpointType = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointReportSetpointType.keySet()) {
            if (constantHumidityControlSetpointReportSetpointType.get(entry).equals(setpointType)) {
                varSetpointType = entry;
                break;
            }
        }
        if (varSetpointType == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + setpointType + "' for setpointType");
        }
        outputData.write(varSetpointType & 0x0F);

        // Process 'Properties2'
        // Size is used by 'Value'
        int size = value.length;
        int valProperties2 = 0;
        valProperties2 |= size & 0x07;
        int varScale = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointReportScale.keySet()) {
            if (constantHumidityControlSetpointReportScale.get(entry).equals(scale)) {
                varScale = entry;
                break;
            }
        }
        if (varScale == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + scale + "' for scale");
        }
        valProperties2 |= varScale << 3 & 0x18;
        valProperties2 |= ((precision << 5) & 0xE0);
        outputData.write(valProperties2);

        // Process 'Value'
        if (value != null) {
            try {
                outputData.write(value);
            } catch (IOException e) {
            }
        }

        return outputData.toByteArray();
    }

    /**
     * Processes a received frame with the HUMIDITY_CONTROL_SETPOINT_REPORT command.
     * <p>
     * Humidity Control Setpoint Report
     * <p>
     * The output data {@link Map} has the following properties -:
     *
     * <ul>
     * <li>SETPOINT_TYPE {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>HUMIDIFIER
     * <li>DEHUMIDIFIER
     * </ul>
     * <li>SCALE {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>PERCENTAGE
     * <li>ABSOLUTE
     * </ul>
     * <li>PRECISION {@link Integer}
     * <li>VALUE {@link byte[]}
     * </ul>
     *
     * @param payload the {@link byte[]} payload data to process
     * @return a {@link Map} of processed response data
     */
    public static Map<String, Object> handleHumidityControlSetpointReport(byte[] payload) {
        // Create our response map
        Map<String, Object> response = new HashMap<String, Object>();

        // We're using variable length fields, so track the offset
        int msgOffset = 2;

        // Process 'Properties1'
        response.put("SETPOINT_TYPE", constantHumidityControlSetpointReportSetpointType.get(payload[msgOffset] & 0x0F));
        msgOffset += 1;

        // Process 'Properties2'
        // Size is used by 'Value'
        int varSize = payload[msgOffset] & 0x07;
        response.put("SCALE", constantHumidityControlSetpointReportScale.get((payload[msgOffset] & 0x18) >> 3));
        response.put("PRECISION", Integer.valueOf(payload[msgOffset] & 0xE0 >> 5));
        msgOffset += 1;

        // Process 'Value'
        ByteArrayOutputStream valValue = new ByteArrayOutputStream();
        for (int cntValue = 0; cntValue < varSize; cntValue++) {
            valValue.write(payload[msgOffset + cntValue]);
        }
        response.put("VALUE", valValue.toByteArray());
        msgOffset += varSize;

        // Return the map of processed response data;
        return response;
    }

    /**
     * Creates a new message with the HUMIDITY_CONTROL_SETPOINT_SUPPORTED_GET command.
     * <p>
     * Humidity Control Setpoint Supported Get
     *
     * @return the {@link byte[]} array with the command to send
     */
    static public byte[] getHumidityControlSetpointSupportedGet() {
        logger.debug("Creating command message HUMIDITY_CONTROL_SETPOINT_SUPPORTED_GET version 1");

        ByteArrayOutputStream outputData = new ByteArrayOutputStream();
        outputData.write(COMMAND_CLASS_KEY);
        outputData.write(HUMIDITY_CONTROL_SETPOINT_SUPPORTED_GET);

        return outputData.toByteArray();
    }

    /**
     * Processes a received frame with the HUMIDITY_CONTROL_SETPOINT_SUPPORTED_GET command.
     * <p>
     * Humidity Control Setpoint Supported Get
     *
     * @param payload the {@link byte[]} payload data to process
     * @return a {@link Map} of processed response data
     */
    public static Map<String, Object> handleHumidityControlSetpointSupportedGet(byte[] payload) {
        // Create our response map
        Map<String, Object> response = new HashMap<String, Object>();

        // Return the map of processed response data;
        return response;
    }

    /**
     * Creates a new message with the HUMIDITY_CONTROL_SETPOINT_SUPPORTED_REPORT command.
     * <p>
     * Humidity Control Setpoint Supported Report
     *
     * @param bitMask {@link List<String>}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>HUMIDIFIER
     *            <li>DEHUMIDIFIER
     *            </ul>
     * @return the {@link byte[]} array with the command to send
     */
    static public byte[] getHumidityControlSetpointSupportedReport(List<String> bitMask) {
        logger.debug("Creating command message HUMIDITY_CONTROL_SETPOINT_SUPPORTED_REPORT version 1");

        ByteArrayOutputStream outputData = new ByteArrayOutputStream();
        outputData.write(COMMAND_CLASS_KEY);
        outputData.write(HUMIDITY_CONTROL_SETPOINT_SUPPORTED_REPORT);

        // Process 'Bit Mask'
        int valBitMask = 0;
        for (String value : bitMask) {
            boolean foundBitMask = false;
            for (Integer entry : constantHumidityControlSetpointSupportedReportBitMask.keySet()) {
                if (constantHumidityControlSetpointSupportedReportBitMask.get(entry).equals(value)) {
                    foundBitMask = true;
                    valBitMask += entry;
                    break;
                }
            }
            if (!foundBitMask) {
                throw new IllegalArgumentException("Unknown constant value '" + bitMask + "' for bitMask");
            }
        }
        outputData.write(valBitMask);

        return outputData.toByteArray();
    }

    /**
     * Processes a received frame with the HUMIDITY_CONTROL_SETPOINT_SUPPORTED_REPORT command.
     * <p>
     * Humidity Control Setpoint Supported Report
     * <p>
     * The output data {@link Map} has the following properties -:
     *
     * <ul>
     * <li>BIT_MASK {@link List}<{@link String}>
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>HUMIDIFIER
     * <li>DEHUMIDIFIER
     * </ul>
     * </ul>
     *
     * @param payload the {@link byte[]} payload data to process
     * @return a {@link Map} of processed response data
     */
    public static Map<String, Object> handleHumidityControlSetpointSupportedReport(byte[] payload) {
        // Create our response map
        Map<String, Object> response = new HashMap<String, Object>();

        // Process 'Bit Mask'
        List<String> responseBitMask = new ArrayList<String>();
        int lenBitMask = 1;
        for (int cntBitMask = 0; cntBitMask < lenBitMask; cntBitMask++) {
            if ((payload[2 + (cntBitMask / 8)] & (1 << cntBitMask % 8)) == 0) {
                continue;
            }
            responseBitMask.add(constantHumidityControlSetpointSupportedReportBitMask.get(cntBitMask));
        }
        response.put("BIT_MASK", responseBitMask);

        // Return the map of processed response data;
        return response;
    }

    /**
     * Creates a new message with the HUMIDITY_CONTROL_SETPOINT_SCALE_SUPPORTED_GET command.
     * <p>
     * Humidity Control Setpoint Scale Supported Get
     *
     * @param setpointType {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>HUMIDIFIER
     *            <li>DEHUMIDIFIER
     *            </ul>
     * @return the {@link byte[]} array with the command to send
     */
    static public byte[] getHumidityControlSetpointScaleSupportedGet(String setpointType) {
        logger.debug("Creating command message HUMIDITY_CONTROL_SETPOINT_SCALE_SUPPORTED_GET version 1");

        ByteArrayOutputStream outputData = new ByteArrayOutputStream();
        outputData.write(COMMAND_CLASS_KEY);
        outputData.write(HUMIDITY_CONTROL_SETPOINT_SCALE_SUPPORTED_GET);

        // Process 'Properties1'
        int varSetpointType = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointScaleSupportedGetSetpointType.keySet()) {
            if (constantHumidityControlSetpointScaleSupportedGetSetpointType.get(entry).equals(setpointType)) {
                varSetpointType = entry;
                break;
            }
        }
        if (varSetpointType == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + setpointType + "' for setpointType");
        }
        outputData.write(varSetpointType & 0x0F);

        return outputData.toByteArray();
    }

    /**
     * Processes a received frame with the HUMIDITY_CONTROL_SETPOINT_SCALE_SUPPORTED_GET command.
     * <p>
     * Humidity Control Setpoint Scale Supported Get
     * <p>
     * The output data {@link Map} has the following properties -:
     *
     * <ul>
     * <li>SETPOINT_TYPE {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>HUMIDIFIER
     * <li>DEHUMIDIFIER
     * </ul>
     * </ul>
     *
     * @param payload the {@link byte[]} payload data to process
     * @return a {@link Map} of processed response data
     */
    public static Map<String, Object> handleHumidityControlSetpointScaleSupportedGet(byte[] payload) {
        // Create our response map
        Map<String, Object> response = new HashMap<String, Object>();

        // Process 'Properties1'
        response.put("SETPOINT_TYPE", constantHumidityControlSetpointScaleSupportedGetSetpointType.get(payload[2] & 0x0F));

        // Return the map of processed response data;
        return response;
    }

    /**
     * Creates a new message with the HUMIDITY_CONTROL_SETPOINT_SCALE_SUPPORTED_REPORT command.
     * <p>
     * Humidity Control Setpoint Scale Supported Report
     *
     * @param scaleBitMask {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>PERCENTAGE
     *            <li>ABSOLUTE
     *            </ul>
     * @return the {@link byte[]} array with the command to send
     */
    static public byte[] getHumidityControlSetpointScaleSupportedReport(String scaleBitMask) {
        logger.debug("Creating command message HUMIDITY_CONTROL_SETPOINT_SCALE_SUPPORTED_REPORT version 1");

        ByteArrayOutputStream outputData = new ByteArrayOutputStream();
        outputData.write(COMMAND_CLASS_KEY);
        outputData.write(HUMIDITY_CONTROL_SETPOINT_SCALE_SUPPORTED_REPORT);

        // Process 'Properties1'
        int varScaleBitMask = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointScaleSupportedReportScaleBitMask.keySet()) {
            if (constantHumidityControlSetpointScaleSupportedReportScaleBitMask.get(entry).equals(scaleBitMask)) {
                varScaleBitMask = entry;
                break;
            }
        }
        if (varScaleBitMask == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + scaleBitMask + "' for scaleBitMask");
        }
        outputData.write(varScaleBitMask & 0x0F);

        return outputData.toByteArray();
    }

    /**
     * Processes a received frame with the HUMIDITY_CONTROL_SETPOINT_SCALE_SUPPORTED_REPORT command.
     * <p>
     * Humidity Control Setpoint Scale Supported Report
     * <p>
     * The output data {@link Map} has the following properties -:
     *
     * <ul>
     * <li>SCALE_BIT_MASK {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>PERCENTAGE
     * <li>ABSOLUTE
     * </ul>
     * </ul>
     *
     * @param payload the {@link byte[]} payload data to process
     * @return a {@link Map} of processed response data
     */
    public static Map<String, Object> handleHumidityControlSetpointScaleSupportedReport(byte[] payload) {
        // Create our response map
        Map<String, Object> response = new HashMap<String, Object>();

        // Process 'Properties1'
        response.put("SCALE_BIT_MASK", constantHumidityControlSetpointScaleSupportedReportScaleBitMask.get(payload[2] & 0x0F));

        // Return the map of processed response data;
        return response;
    }

    /**
     * Creates a new message with the HUMIDITY_CONTROL_SETPOINT_CAPABILITIES_GET command.
     * <p>
     * Humidity Control Setpoint Capabilities Get
     *
     * @param setpointType {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>HUMIDIFIER
     *            <li>DEHUMIDIFIER
     *            </ul>
     * @return the {@link byte[]} array with the command to send
     */
    static public byte[] getHumidityControlSetpointCapabilitiesGet(String setpointType) {
        logger.debug("Creating command message HUMIDITY_CONTROL_SETPOINT_CAPABILITIES_GET version 1");

        ByteArrayOutputStream outputData = new ByteArrayOutputStream();
        outputData.write(COMMAND_CLASS_KEY);
        outputData.write(HUMIDITY_CONTROL_SETPOINT_CAPABILITIES_GET);

        // Process 'Properties1'
        int varSetpointType = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointCapabilitiesGetSetpointType.keySet()) {
            if (constantHumidityControlSetpointCapabilitiesGetSetpointType.get(entry).equals(setpointType)) {
                varSetpointType = entry;
                break;
            }
        }
        if (varSetpointType == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + setpointType + "' for setpointType");
        }
        outputData.write(varSetpointType & 0x0F);

        return outputData.toByteArray();
    }

    /**
     * Processes a received frame with the HUMIDITY_CONTROL_SETPOINT_CAPABILITIES_GET command.
     * <p>
     * Humidity Control Setpoint Capabilities Get
     * <p>
     * The output data {@link Map} has the following properties -:
     *
     * <ul>
     * <li>SETPOINT_TYPE {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>HUMIDIFIER
     * <li>DEHUMIDIFIER
     * </ul>
     * </ul>
     *
     * @param payload the {@link byte[]} payload data to process
     * @return a {@link Map} of processed response data
     */
    public static Map<String, Object> handleHumidityControlSetpointCapabilitiesGet(byte[] payload) {
        // Create our response map
        Map<String, Object> response = new HashMap<String, Object>();

        // Process 'Properties1'
        response.put("SETPOINT_TYPE", constantHumidityControlSetpointCapabilitiesGetSetpointType.get(payload[2] & 0x0F));

        // Return the map of processed response data;
        return response;
    }

    /**
     * Creates a new message with the HUMIDITY_CONTROL_SETPOINT_CAPABILITIES_REPORT command.
     * <p>
     * Humidity Control Setpoint Capabilities Report
     *
     * @param setpointType {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>HUMIDIFIER
     *            <li>DEHUMIDIFIER
     *            </ul>
     * @param scale1 {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>PERCENTAGE
     *            <li>ABSOLUTE
     *            </ul>
     * @param precision1 {@link Integer}
     * @param minimumValue {@link byte[]}
     * @param scale2 {@link String}
     *            Can be one of the following -:
     *            <p>
     *            <ul>
     *            <li>PERCENTAGE
     *            <li>ABSOLUTE
     *            </ul>
     * @param precision2 {@link Integer}
     * @param maximumValue {@link byte[]}
     * @return the {@link byte[]} array with the command to send
     */
    static public byte[] getHumidityControlSetpointCapabilitiesReport(String setpointType, String scale1,
            Integer precision1, byte[] minimumValue, String scale2, Integer precision2, byte[] maximumValue) {
        logger.debug("Creating command message HUMIDITY_CONTROL_SETPOINT_CAPABILITIES_REPORT version 1");

        ByteArrayOutputStream outputData = new ByteArrayOutputStream();
        outputData.write(COMMAND_CLASS_KEY);
        outputData.write(HUMIDITY_CONTROL_SETPOINT_CAPABILITIES_REPORT);

        // Process 'Properties1'
        int varSetpointType = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointCapabilitiesReportSetpointType.keySet()) {
            if (constantHumidityControlSetpointCapabilitiesReportSetpointType.get(entry).equals(setpointType)) {
                varSetpointType = entry;
                break;
            }
        }
        if (varSetpointType == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + setpointType + "' for setpointType");
        }
        outputData.write(varSetpointType & 0x0F);

        // Process 'Properties2'
        // Size1 is used by 'Minimum Value'
        int size1 = minimumValue.length;
        int valProperties2 = 0;
        valProperties2 |= size1 & 0x07;
        int varScale1 = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointCapabilitiesReportScale1.keySet()) {
            if (constantHumidityControlSetpointCapabilitiesReportScale1.get(entry).equals(scale1)) {
                varScale1 = entry;
                break;
            }
        }
        if (varScale1 == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + scale1 + "' for scale1");
        }
        valProperties2 |= varScale1 << 3 & 0x18;
        valProperties2 |= ((precision1 << 5) & 0xE0);
        outputData.write(valProperties2);

        // Process 'Minimum Value'
        if (minimumValue != null) {
            try {
                outputData.write(minimumValue);
            } catch (IOException e) {
            }
        }

        // Process 'Properties3'
        // Size2 is used by 'Maximum Value'
        int size2 = maximumValue.length;
        int valProperties3 = 0;
        valProperties3 |= size2 & 0x07;
        int varScale2 = Integer.MAX_VALUE;
        for (Integer entry : constantHumidityControlSetpointCapabilitiesReportScale2.keySet()) {
            if (constantHumidityControlSetpointCapabilitiesReportScale2.get(entry).equals(scale2)) {
                varScale2 = entry;
                break;
            }
        }
        if (varScale2 == Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Unknown constant value '" + scale2 + "' for scale2");
        }
        valProperties3 |= varScale2 << 3 & 0x18;
        valProperties3 |= ((precision2 << 5) & 0xE0);
        outputData.write(valProperties3);

        // Process 'Maximum Value'
        if (maximumValue != null) {
            try {
                outputData.write(maximumValue);
            } catch (IOException e) {
            }
        }

        return outputData.toByteArray();
    }

    /**
     * Processes a received frame with the HUMIDITY_CONTROL_SETPOINT_CAPABILITIES_REPORT command.
     * <p>
     * Humidity Control Setpoint Capabilities Report
     * <p>
     * The output data {@link Map} has the following properties -:
     *
     * <ul>
     * <li>SETPOINT_TYPE {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>HUMIDIFIER
     * <li>DEHUMIDIFIER
     * </ul>
     * <li>SCALE1 {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>PERCENTAGE
     * <li>ABSOLUTE
     * </ul>
     * <li>PRECISION1 {@link Integer}
     * <li>MINIMUM_VALUE {@link byte[]}
     * <li>SCALE2 {@link String}
     * Can be one of the following -:
     * <p>
     * <ul>
     * <li>PERCENTAGE
     * <li>ABSOLUTE
     * </ul>
     * <li>PRECISION2 {@link Integer}
     * <li>MAXIMUM_VALUE {@link byte[]}
     * </ul>
     *
     * @param payload the {@link byte[]} payload data to process
     * @return a {@link Map} of processed response data
     */
    public static Map<String, Object> handleHumidityControlSetpointCapabilitiesReport(byte[] payload) {
        // Create our response map
        Map<String, Object> response = new HashMap<String, Object>();

        // We're using variable length fields, so track the offset
        int msgOffset = 2;

        // Process 'Properties1'
        response.put("SETPOINT_TYPE", constantHumidityControlSetpointCapabilitiesReportSetpointType.get(payload[msgOffset] & 0x0F));
        msgOffset += 1;

        // Process 'Properties2'
        // Size1 is used by 'Minimum Value'
        int varSize1 = payload[msgOffset] & 0x07;
        response.put("SCALE1", constantHumidityControlSetpointCapabilitiesReportScale1.get((payload[msgOffset] & 0x18) >> 3));
        response.put("PRECISION1", Integer.valueOf(payload[msgOffset] & 0xE0 >> 5));
        msgOffset += 1;

        // Process 'Minimum Value'
        ByteArrayOutputStream valMinimumValue = new ByteArrayOutputStream();
        for (int cntMinimumValue = 0; cntMinimumValue < varSize1; cntMinimumValue++) {
            valMinimumValue.write(payload[msgOffset + cntMinimumValue]);
        }
        response.put("MINIMUM_VALUE", valMinimumValue.toByteArray());
        msgOffset += varSize1;

        // Process 'Properties3'
        // Size2 is used by 'Maximum Value'
        int varSize2 = payload[msgOffset] & 0x07;
        response.put("SCALE2", constantHumidityControlSetpointCapabilitiesReportScale2.get((payload[msgOffset] & 0x18) >> 3));
        response.put("PRECISION2", Integer.valueOf(payload[msgOffset] & 0xE0 >> 5));
        msgOffset += 1;

        // Process 'Maximum Value'
        ByteArrayOutputStream valMaximumValue = new ByteArrayOutputStream();
        for (int cntMaximumValue = 0; cntMaximumValue < varSize2; cntMaximumValue++) {
            valMaximumValue.write(payload[msgOffset + cntMaximumValue]);
        }
        response.put("MAXIMUM_VALUE", valMaximumValue.toByteArray());
        msgOffset += varSize2;

        // Return the map of processed response data;
        return response;
    }
}
