/**
 * Copyright (c) 2010-2020 Contributors to the openHAB project
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0
 *
 * SPDX-License-Identifier: EPL-2.0
 */

 /* ***********************************************************
 * This file was automatically generated on 2022-01-03.      *
 *                                                           *
 * openHAB Bindings Version 2.0.0                            *
 *                                                           *
 * If you have a bugfix for this file and want to commit it, *
 * please fix the bug in the generator. You can find a link  *
 * to the generators git repository on tinkerforge.com       *
 *************************************************************/

package org.openhab.binding.tinkerforge.internal.device;

import java.net.URI;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.config.core.ConfigDescription;
import org.eclipse.smarthome.config.core.ConfigDescriptionBuilder;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameter.Type;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameterBuilder;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameterGroup;
import org.eclipse.smarthome.config.core.ParameterOption;
import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.StateOption;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.CommandDescriptionBuilder;
import org.eclipse.smarthome.core.types.CommandOption;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
import org.eclipse.smarthome.core.thing.type.ChannelDefinitionBuilder;
import org.eclipse.smarthome.core.thing.type.ChannelType;
import org.eclipse.smarthome.core.thing.type.ChannelTypeBuilder;
import org.eclipse.smarthome.core.thing.type.ChannelTypeUID;
import org.eclipse.smarthome.core.types.RefreshType;
import org.eclipse.smarthome.core.thing.type.ThingType;
import org.eclipse.smarthome.core.thing.type.ThingTypeBuilder;
import org.eclipse.smarthome.core.types.StateDescriptionFragmentBuilder;
import org.openhab.binding.tinkerforge.internal.TinkerforgeBindingConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.QuantityType;
import org.eclipse.smarthome.core.library.unit.MetricPrefix;
import org.eclipse.smarthome.core.library.unit.SIUnits;
import org.eclipse.smarthome.core.library.unit.SmartHomeUnits;
import org.eclipse.smarthome.core.library.types.RawType;
import org.eclipse.smarthome.core.library.types.OpenClosedType;

import com.tinkerforge.BrickletThermalImaging;
import com.tinkerforge.IPConnection;
import com.tinkerforge.TinkerforgeException;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

/**
 * Wraps the Java Bindings of the Thermal Imaging Bricklet.
 * @author Erik Fleckstein - Initial contribution
 */
@NonNullByDefault
public class BrickletThermalImagingWrapper extends BrickletThermalImaging implements CoMCUFlashable, DeviceWrapper {
    public static final DeviceInfo DEVICE_INFO = new DeviceInfo(BrickletThermalImaging.DEVICE_DISPLAY_NAME, "brickletthermalimaging", BrickletThermalImaging.DEVICE_IDENTIFIER, BrickletThermalImagingWrapper.class, BrickletThermalImagingActions.class, "2.0.5", true);

    public BrickletThermalImagingWrapper(String uid, IPConnection ipcon) {
        super(uid, ipcon);
    }

    private List<ScheduledFuture<?>> manualChannelUpdates = new ArrayList<>();
    private List<ListenerReg<?>> listenerRegs = new ArrayList<>();

    public void cancelManualUpdates() {
        manualChannelUpdates.forEach(f -> f.cancel(true));
    }

    public <T> T reg(T listener, Consumer<T> toRemove) {
        listenerRegs.add(new ListenerReg<T>(listener, toRemove));
        return listener;
    }

    
    private final Logger logger = LoggerFactory.getLogger(BrickletThermalImagingWrapper.class);

    @Override
    public void initialize(org.eclipse.smarthome.config.core.Configuration config, Function<String, org.eclipse.smarthome.config.core.Configuration> getChannelConfigFn, BiConsumer<String, org.eclipse.smarthome.core.types.State> updateStateFn, BiConsumer<String, String> triggerChannelFn, ScheduledExecutorService scheduler, BaseThingHandler handler) throws TinkerforgeException {
        this.setResponseExpectedAll(true);
        BrickletThermalImagingConfig cfg = (BrickletThermalImagingConfig) config.as(BrickletThermalImagingConfig.class);
        
        this.setImageTransferConfig(cfg.imageType);
		    this.setResolution(cfg.resolution);
		    this.setSpotmeterConfig(new int[]{cfg.spotmeterColumnStart, cfg.spotmeterRowStart, cfg.spotmeterColumnEnd, cfg.spotmeterRowEnd});
		    this.setFluxLinearParameters(cfg.sceneEmissivity, cfg.temperatureBackground, cfg.tauWindow, cfg.temperatureWindow, cfg.tauAtmosphere, cfg.temperatureAtmosphere, cfg.reflectionWindow, cfg.temperatureReflection);
		this.setStatusLEDConfig(cfg.statusLEDConfig);
		if (cfg.imageType == 0) {
		BrickletThermalImagingHighContrastImageConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingHighContrastImage").as(BrickletThermalImagingHighContrastImageConfig.class);
		this.setHighContrastConfig(new int[]{channelCfg.highContrastColumnStart, channelCfg.highContrastRowStart, channelCfg.highContrastColumnEnd, channelCfg.highContrastRowEnd}, channelCfg.dampeningFactor, new int[]{channelCfg.clipLimitHigh, channelCfg.clipLimitLow}, channelCfg.emptyCounts);
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingHighContrastImage"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		if (cfg.imageType == 1) {
		BrickletThermalImagingTemperatureImageConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingTemperatureImage").as(BrickletThermalImagingTemperatureImageConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingTemperatureImage"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingTemperatureConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingSpotmeterMeanTemperature").as(BrickletThermalImagingTemperatureConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingSpotmeterMeanTemperature"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingTemperatureConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingSpotmeterMaximumTemperature").as(BrickletThermalImagingTemperatureConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingSpotmeterMaximumTemperature"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingTemperatureConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingSpotmeterMinimumTemperature").as(BrickletThermalImagingTemperatureConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingSpotmeterMinimumTemperature"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingSpotmeterROIPixelCountConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingSpotmeterROIPixelCount").as(BrickletThermalImagingSpotmeterROIPixelCountConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingSpotmeterROIPixelCount"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingTemperatureConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingFocalPlainArrayTemperature").as(BrickletThermalImagingTemperatureConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingFocalPlainArrayTemperature"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingTemperatureConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingFocalPlainArrayTemperatureFFC").as(BrickletThermalImagingTemperatureConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingFocalPlainArrayTemperatureFFC"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingTemperatureConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingHousingTemperature").as(BrickletThermalImagingTemperatureConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingHousingTemperature"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingTemperatureConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingHousingTemperatureFFC").as(BrickletThermalImagingTemperatureConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingHousingTemperatureFFC"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingFFCStatusConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingFFCStatus").as(BrickletThermalImagingFFCStatusConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingFFCStatus"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingShutterLockoutConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingShutterLockout").as(BrickletThermalImagingShutterLockoutConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingShutterLockout"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
		{
		BrickletThermalImagingOvertemperatureShutdownImminentConfig channelCfg = getChannelConfigFn.apply("BrickletThermalImagingOvertemperatureShutdownImminent").as(BrickletThermalImagingOvertemperatureShutdownImminentConfig.class);
		
		if(channelCfg.updateInterval > 0) {
    this.manualChannelUpdates.add(scheduler.scheduleWithFixedDelay(() -> {if(handler.getThing().getStatus() == ThingStatus.ONLINE) {handler.handleCommand(new ChannelUID(handler.getThing().getUID(), "BrickletThermalImagingOvertemperatureShutdownImminent"), RefreshType.REFRESH);}}, channelCfg.updateInterval, channelCfg.updateInterval, TimeUnit.MILLISECONDS));
}
		}
    }

    @Override
    public void dispose(org.eclipse.smarthome.config.core.Configuration config) throws TinkerforgeException {
        listenerRegs.forEach(ListenerReg::deregister);

        
        
    }

    @Override
    public List<String> getEnabledChannels(org.eclipse.smarthome.config.core.Configuration config) throws TinkerforgeException{
        BrickletThermalImagingConfig cfg = (BrickletThermalImagingConfig) config.as(BrickletThermalImagingConfig.class);
List<String> result = new ArrayList<String>();
        if (cfg.imageType == 0) {
                result.add("BrickletThermalImagingHighContrastImage");
            }
		if (cfg.imageType == 1) {
                result.add("BrickletThermalImagingTemperatureImage");
            }
		result.add("BrickletThermalImagingSpotmeterMeanTemperature");
		result.add("BrickletThermalImagingSpotmeterMaximumTemperature");
		result.add("BrickletThermalImagingSpotmeterMinimumTemperature");
		result.add("BrickletThermalImagingSpotmeterROIPixelCount");
		result.add("BrickletThermalImagingFocalPlainArrayTemperature");
		result.add("BrickletThermalImagingFocalPlainArrayTemperatureFFC");
		result.add("BrickletThermalImagingHousingTemperature");
		result.add("BrickletThermalImagingHousingTemperatureFFC");
		result.add("BrickletThermalImagingFFCStatus");
		result.add("BrickletThermalImagingShutterLockout");
		result.add("BrickletThermalImagingOvertemperatureShutdownImminent");
        return result;
    }

    public static @Nullable ChannelType getChannelType(ChannelTypeUID channelTypeUID) {
        switch(channelTypeUID.getId()) {
            case "BrickletThermalImagingHighContrastImage":
                return ChannelTypeBuilder.state(new ChannelTypeUID("tinkerforge", "BrickletThermalImagingHighContrastImage"), "High Contrast Image", "Image").withConfigDescriptionURI(URI.create("channel-type:tinkerforge:BrickletThermalImagingHighContrastImage")).withDescription("The current high contrast image. See here: https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Thermal_Imaging.html#high-contrast-image-vs-temperature-image for the difference between High Contrast and Temperature Image. If you don't know what to use the High Contrast Image is probably right for you.").build();
            case "BrickletThermalImagingTemperatureImage":
                return ChannelTypeBuilder.state(new ChannelTypeUID("tinkerforge", "BrickletThermalImagingTemperatureImage"), "Temperature Image", "Image").withConfigDescriptionURI(URI.create("channel-type:tinkerforge:BrickletThermalImagingTemperatureImage")).withDescription("The current temperature image. See here: https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Thermal_Imaging.html#high-contrast-image-vs-temperature-image for the difference between High Contrast and Temperature Image. If you don't know what to use the High Contrast Image is probably right for you.").build();
            case "BrickletThermalImagingTemperature":
                return ChannelTypeBuilder.state(new ChannelTypeUID("tinkerforge", "BrickletThermalImagingTemperature"), "NOT USED", "Number:Temperature").withConfigDescriptionURI(URI.create("channel-type:tinkerforge:BrickletThermalImagingTemperature")).withStateDescription(StateDescriptionFragmentBuilder.create().withPattern("%.3f %unit%").withReadOnly(true).build().toStateDescription()).build();
            case "BrickletThermalImagingSpotmeterROIPixelCount":
                return ChannelTypeBuilder.state(new ChannelTypeUID("tinkerforge", "BrickletThermalImagingSpotmeterROIPixelCount"), "Spotmeter ROI Pixel Count", "Number").withConfigDescriptionURI(URI.create("channel-type:tinkerforge:BrickletThermalImagingSpotmeterROIPixelCount")).withStateDescription(StateDescriptionFragmentBuilder.create().withPattern("%d %unit%").withReadOnly(true).build().toStateDescription()).build();
            case "BrickletThermalImagingFFCStatus":
                return ChannelTypeBuilder.state(new ChannelTypeUID("tinkerforge", "BrickletThermalImagingFFCStatus"), "FFC Status", "Number:Dimensionless").withConfigDescriptionURI(URI.create("channel-type:tinkerforge:BrickletThermalImagingFFCStatus")).withDescription("Flat Field Correction Status")
.withStateDescription(StateDescriptionFragmentBuilder.create().withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(3)).withPattern("%d").withReadOnly(true).withOptions(Arrays.asList(new StateOption("0", "Never Commanded"), new StateOption("1", "Imminent"), new StateOption("2", "In Progress"), new StateOption("3", "Complete"))).build().toStateDescription()).build();
            case "BrickletThermalImagingShutterLockout":
                return ChannelTypeBuilder.state(new ChannelTypeUID("tinkerforge", "BrickletThermalImagingShutterLockout"), "Shutter Lockout", "Contact").withConfigDescriptionURI(URI.create("channel-type:tinkerforge:BrickletThermalImagingShutterLockout")).withDescription("If enabled, shutter is locked out because temperature is outside -10°C to +65°C").build();
            case "BrickletThermalImagingOvertemperatureShutdownImminent":
                return ChannelTypeBuilder.state(new ChannelTypeUID("tinkerforge", "BrickletThermalImagingOvertemperatureShutdownImminent"), "Overtemperature Shutdown Imminent", "Contact").withConfigDescriptionURI(URI.create("channel-type:tinkerforge:BrickletThermalImagingOvertemperatureShutdownImminent")).withDescription("Gets enabled 10 seconds before shutdown.").build();
default:
                break;
        }

        return null;
    }

    public static ThingType getThingType(ThingTypeUID thingTypeUID) {
             Map<String, String> thingTypeProperties = ThingTypeBuilder.instance(thingTypeUID, "unused").build().getProperties();
             Map<String, String> props = new HashMap<String, String>(thingTypeProperties);
             props.putIfAbsent(TinkerforgeBindingConstants.PROPERTY_MINIMUM_FIRMWARE_VERSION, DEVICE_INFO.minimumFWVersion);
        return ThingTypeBuilder.instance(thingTypeUID, "Tinkerforge Thermal Imaging Bricklet").isListed(false).withSupportedBridgeTypeUIDs(Arrays.asList(TinkerforgeBindingConstants.THING_TYPE_BRICK_DAEMON.toString())).withConfigDescriptionURI(URI.create("thing-type:tinkerforge:" + thingTypeUID.getId())).withDescription("80x60 pixel thermal imaging camera").withChannelDefinitions(Arrays.asList(new ChannelDefinitionBuilder("BrickletThermalImagingHighContrastImage", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingHighContrastImage")).withLabel("High Contrast Image").build(), new ChannelDefinitionBuilder("BrickletThermalImagingTemperatureImage", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingTemperatureImage")).withLabel("Temperature Image").build(), new ChannelDefinitionBuilder("BrickletThermalImagingSpotmeterMeanTemperature", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingTemperature")).withLabel("Spotmeter Mean Temperature").withDescription("Mean temperature in the spotmeter region of interest.").build(), new ChannelDefinitionBuilder("BrickletThermalImagingSpotmeterMaximumTemperature", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingTemperature")).withLabel("Spotmeter Maximum Temperature").withDescription("Maximum temperature in the spotmeter region of interest.").build(), new ChannelDefinitionBuilder("BrickletThermalImagingSpotmeterMinimumTemperature", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingTemperature")).withLabel("Spotmeter Minimum Temperature").withDescription("Minimum temperature in the spotmeter region of interest.").build(), new ChannelDefinitionBuilder("BrickletThermalImagingSpotmeterROIPixelCount", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingSpotmeterROIPixelCount")).withLabel("Spotmeter ROI Pixel Count").withDescription("Number of pixels in the spotmeter region of interest.").build(), new ChannelDefinitionBuilder("BrickletThermalImagingFocalPlainArrayTemperature", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingTemperature")).withLabel("Focal Plain Array Temperature").withDescription("Current Focal Plain Array temperature").build(), new ChannelDefinitionBuilder("BrickletThermalImagingFocalPlainArrayTemperatureFFC", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingTemperature")).withLabel("Focal Plain Array Temperature (last FFC)").withDescription("Focal Plain Array temperature at last FFC (Flat Field Correction).").build(), new ChannelDefinitionBuilder("BrickletThermalImagingHousingTemperature", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingTemperature")).withLabel("Housing Temperature").withDescription("Current Housing temperature.").build(), new ChannelDefinitionBuilder("BrickletThermalImagingHousingTemperatureFFC", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingTemperature")).withLabel("Housing Temperature (last FFC)").withDescription("Housing temperature at last FFC (Flat Field Correction).").build(), new ChannelDefinitionBuilder("BrickletThermalImagingFFCStatus", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingFFCStatus")).withLabel("Flat Field Correction Status").build(), new ChannelDefinitionBuilder("BrickletThermalImagingShutterLockout", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingShutterLockout")).withLabel("Shutter Lockout").build(), new ChannelDefinitionBuilder("BrickletThermalImagingOvertemperatureShutdownImminent", new ChannelTypeUID("tinkerforge", "BrickletThermalImagingOvertemperatureShutdownImminent")).withLabel("Overtemperature Shutdown Imminent").build())).withProperties(props).build();
    }

    public static @Nullable ConfigDescription getConfigDescription(URI uri) {
        switch(uri.toASCIIString()) {
            case "thing-type:tinkerforge:brickletthermalimaging":
                return ConfigDescriptionBuilder.create(uri).withParameters(Arrays.asList(ConfigDescriptionParameterBuilder.create("imageType", Type.INTEGER).withDefault("0").withDescription("The necessary bandwidth of this Bricklet is too high to use the high contrast and temperature image at the same time. You have to configure the one you want to use, the Bricklet will optimize the internal configuration accordingly.").withLabel("Image Type").withLimitToOptions(true).withOptions(Arrays.asList(new ParameterOption("0", "High Contrast Image"), new ParameterOption("1", "Linear Temperature Image"))).build(), ConfigDescriptionParameterBuilder.create("scaleFactor", Type.INTEGER).withDefault("1").withDescription("Multiplicator for the image width and height. The image has a resolution of 80x60, so for a image of size 160x120 use a scale factor of 4.").withLabel("Scale Factor").withMinimum(BigDecimal.valueOf(1)).build(), ConfigDescriptionParameterBuilder.create("resolution", Type.INTEGER).withDefault("1").withDescription("The Thermal Imaging Bricklet can either measure<ul><li>from 0 to 6553 Kelvin (-273.15°C to +6279.85°C) with 0.1°C resolution or</li><li>from 0 to 655 Kelvin (-273.15°C to +381.85°C) with 0.01°C resolution.</li></ul><br/>The accuracy is specified for -10°C to 450°C in the first range and -10°C and 140°C in the second range.").withLabel("Resolution").withLimitToOptions(true).withOptions(Arrays.asList(new ParameterOption("0", "0 To 6553 Kelvin"), new ParameterOption("1", "0 To 655 Kelvin"))).build(), ConfigDescriptionParameterBuilder.create("colorPalette", Type.INTEGER).withDefault("0").withDescription("The thermal image color palette.").withLabel("Color Palette").withLimitToOptions(true).withOptions(Arrays.asList(new ParameterOption("0", "Standard"), new ParameterOption("1", "Greyscale"), new ParameterOption("2", "Hot Cold"))).build(), ConfigDescriptionParameterBuilder.create("spotmeterColumnStart", Type.INTEGER).withDefault("39").withDescription("First column of the spotmeter region of interest.").withLabel("Spotmeter Column Start").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(79)).build(), ConfigDescriptionParameterBuilder.create("spotmeterRowStart", Type.INTEGER).withDefault("29").withDescription("First row of the spotmeter region of interest.").withLabel("Spotmeter Row Start").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(59)).build(), ConfigDescriptionParameterBuilder.create("spotmeterColumnEnd", Type.INTEGER).withDefault("40").withDescription("Last column of the spotmeter region of interest.").withLabel("Spotmeter Column End").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(79)).build(), ConfigDescriptionParameterBuilder.create("spotmeterRowEnd", Type.INTEGER).withDefault("30").withDescription("Last row of the spotmeter region of interest.").withLabel("Spotmeter Row End").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(59)).build(), ConfigDescriptionParameterBuilder.create("sceneEmissivity", Type.INTEGER).withDefault("8192").withDescription("").withGroupName("Flux Linear Parameters").withLabel("Scene Emissivity").withAdvanced(true).withMinimum(BigDecimal.valueOf(82)).withMaximum(BigDecimal.valueOf(8192)).build(), ConfigDescriptionParameterBuilder.create("temperatureBackground", Type.INTEGER).withDefault("29515").withDescription("").withGroupName("Flux Linear Parameters").withLabel("Temperatrure Background").withAdvanced(true).withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(65535)).build(), ConfigDescriptionParameterBuilder.create("tauWindow", Type.INTEGER).withDefault("8192").withDescription("").withGroupName("Flux Linear Parameters").withLabel("Tau Window").withAdvanced(true).withMinimum(BigDecimal.valueOf(82)).withMaximum(BigDecimal.valueOf(8192)).build(), ConfigDescriptionParameterBuilder.create("temperatureWindow", Type.INTEGER).withDefault("29515").withDescription("").withGroupName("Flux Linear Parameters").withLabel("Temperature Window").withAdvanced(true).withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(65535)).build(), ConfigDescriptionParameterBuilder.create("tauAtmosphere", Type.INTEGER).withDefault("8192").withDescription("").withGroupName("Flux Linear Parameters").withLabel("Tau Atmosphere").withAdvanced(true).withMinimum(BigDecimal.valueOf(82)).withMaximum(BigDecimal.valueOf(8192)).build(), ConfigDescriptionParameterBuilder.create("temperatureAtmosphere", Type.INTEGER).withDefault("29515").withDescription("").withGroupName("Flux Linear Parameters").withLabel("Temperature Atmosphere").withAdvanced(true).withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(65535)).build(), ConfigDescriptionParameterBuilder.create("reflectionWindow", Type.INTEGER).withDefault("0").withDescription("").withGroupName("Flux Linear Parameters").withLabel("Reflection Window").withAdvanced(true).withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(8192)).build(), ConfigDescriptionParameterBuilder.create("temperatureReflection", Type.INTEGER).withDefault("29515").withDescription("").withGroupName("Flux Linear Parameters").withLabel("Temperature Reflection").withAdvanced(true).withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(65535)).build(), ConfigDescriptionParameterBuilder.create("statusLEDConfig", Type.INTEGER).withDefault("3").withDescription("The status LED configuration. By default the LED shows communication traffic between Brick and Bricklet, it flickers once for every 10 received data packets.<br/><br/>You can also turn the LED permanently on/off or show a heartbeat.<br/><br/>If the Bricklet is in bootloader mode, the LED is will show heartbeat by default.").withLabel("Status LED Configuration").withAdvanced(true).withLimitToOptions(true).withOptions(Arrays.asList(new ParameterOption("0", "Off"), new ParameterOption("1", "On"), new ParameterOption("2", "Show Heartbeat"), new ParameterOption("3", "Show Status"))).build())).withParameterGroups(Arrays.asList(new ConfigDescriptionParameterGroup("update_intervals", "null", true, "Update Intervals", "Update Intervals"), new ConfigDescriptionParameterGroup("Flux Linear Parameters", "null", true, "Flux Linear Parameters", "The flux linear parameters that can be used for radiometry calibration.<br/><br/>See FLIR document 102-PS245-100-01 for more details."))).build();
            case "channel-type:tinkerforge:BrickletThermalImagingHighContrastImage":
                return ConfigDescriptionBuilder.create(uri).withParameters(Arrays.asList(ConfigDescriptionParameterBuilder.create("highContrastColumnStart", Type.INTEGER).withDefault("0").withDescription("First column of the high contrast region of interest.").withLabel("High Contrast Column Start").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(79)).build(), ConfigDescriptionParameterBuilder.create("highContrastRowStart", Type.INTEGER).withDefault("0").withDescription("First row of the high contrast region of interest.").withLabel("High Contrast Row Start").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(59)).build(), ConfigDescriptionParameterBuilder.create("highContrastColumnEnd", Type.INTEGER).withDefault("79").withDescription("Last column of the high contrast region of interest.").withLabel("High Contrast Column End").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(79)).build(), ConfigDescriptionParameterBuilder.create("highContrastRowEnd", Type.INTEGER).withDefault("59").withDescription("Last row of the high contrast region of interest.").withLabel("High Contrast Row End").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(59)).build(), ConfigDescriptionParameterBuilder.create("dampeningFactor", Type.INTEGER).withDefault("64").withDescription("This parameter is the amount of temporal dampening applied to the HEQ (history equalization) transformation function. An IIR filter of the form:<pre>(N / 256) * previous + ((256 - N) / 256) * current</pre>is applied, and the HEQ dampening factor represents the value N in the equation, i.e., a value that applies to the amount of influence the previous HEQ transformation function has on the current function. The lower the value of N the higher the influence of the current video frame whereas the higher the value of N the more influence the previous damped transfer function has.").withLabel("Dampening Factor").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(256)).build(), ConfigDescriptionParameterBuilder.create("clipLimitLow", Type.INTEGER).withDefault("512").withDescription("This parameter defines an artificial population that is added to every non-empty histogram bin. In other words, if the Clip Limit Low is set to L, a bin with an actual population of X will have an effective population of L + X. Any empty bin that is nearby a populated bin will be given an artificial population of L. The effect of higher values is to provide a more linear transfer function; lower values provide a more non-linear (equalized) transfer function.").withLabel("AGC HEQ Clip Limit Low").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(1024)).build(), ConfigDescriptionParameterBuilder.create("clipLimitHigh", Type.INTEGER).withDefault("4800").withDescription("This parameter defines the maximum number of pixels allowed to accumulate in any given histogram bin. Any additional pixels in a given bin are clipped. The effect of this parameter is to limit the influence of highly-populated bins on the resulting HEQ transformation function.").withLabel("AGC HEQ Clip Limit High").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(4800)).build(), ConfigDescriptionParameterBuilder.create("emptyCounts", Type.INTEGER).withDefault("2").withDescription(" This parameter specifies the maximum number of pixels in a bin that will be interpreted as an empty bin. Histogram bins with this number of pixels or less will be processed as an empty bin.").withLabel("Empty Counts").withMinimum(BigDecimal.valueOf(0)).withMaximum(BigDecimal.valueOf(16383)).build(), ConfigDescriptionParameterBuilder.create("updateInterval", Type.INTEGER).withDefault("1000").withDescription("Specifies the update interval in milliseconds. A value of 0 disables automatic updates.").withLabel("Update Interval").withUnit("ms").build())).withParameterGroups(Arrays.asList()).build();
            case "channel-type:tinkerforge:BrickletThermalImagingTemperatureImage":
                return ConfigDescriptionBuilder.create(uri).withParameters(Arrays.asList(ConfigDescriptionParameterBuilder.create("updateInterval", Type.INTEGER).withDefault("1000").withDescription("Specifies the update interval in milliseconds. A value of 0 disables automatic updates.").withLabel("Update Interval").withUnit("ms").build())).withParameterGroups(Arrays.asList()).build();
            case "channel-type:tinkerforge:BrickletThermalImagingTemperature":
                return ConfigDescriptionBuilder.create(uri).withParameters(Arrays.asList(ConfigDescriptionParameterBuilder.create("updateInterval", Type.INTEGER).withDefault("1000").withDescription("Specifies the update interval in milliseconds. A value of 0 disables automatic updates.").withLabel("Update Interval").withUnit("ms").build())).withParameterGroups(Arrays.asList()).build();
            case "channel-type:tinkerforge:BrickletThermalImagingSpotmeterROIPixelCount":
                return ConfigDescriptionBuilder.create(uri).withParameters(Arrays.asList(ConfigDescriptionParameterBuilder.create("updateInterval", Type.INTEGER).withDefault("1000").withDescription("Specifies the update interval in milliseconds. A value of 0 disables automatic updates.").withLabel("Update Interval").withUnit("ms").build())).withParameterGroups(Arrays.asList()).build();
            case "channel-type:tinkerforge:BrickletThermalImagingFFCStatus":
                return ConfigDescriptionBuilder.create(uri).withParameters(Arrays.asList(ConfigDescriptionParameterBuilder.create("updateInterval", Type.INTEGER).withDefault("1000").withDescription("Specifies the update interval in milliseconds. A value of 0 disables automatic updates.").withLabel("Update Interval").withUnit("ms").build())).withParameterGroups(Arrays.asList()).build();
            case "channel-type:tinkerforge:BrickletThermalImagingShutterLockout":
                return ConfigDescriptionBuilder.create(uri).withParameters(Arrays.asList(ConfigDescriptionParameterBuilder.create("updateInterval", Type.INTEGER).withDefault("1000").withDescription("Specifies the update interval in milliseconds. A value of 0 disables automatic updates.").withLabel("Update Interval").withUnit("ms").build())).withParameterGroups(Arrays.asList()).build();
            case "channel-type:tinkerforge:BrickletThermalImagingOvertemperatureShutdownImminent":
                return ConfigDescriptionBuilder.create(uri).withParameters(Arrays.asList(ConfigDescriptionParameterBuilder.create("updateInterval", Type.INTEGER).withDefault("1000").withDescription("Specifies the update interval in milliseconds. A value of 0 disables automatic updates.").withLabel("Update Interval").withUnit("ms").build())).withParameterGroups(Arrays.asList()).build();
            default:
                break;
        }
        return null;
    }

        @Override
    public void refreshValue(String channel, org.eclipse.smarthome.config.core.Configuration config, org.eclipse.smarthome.config.core.Configuration channelConfig, BiConsumer<String, org.eclipse.smarthome.core.types.State> updateStateFn, BiConsumer<String, String> triggerChannelFn) throws TinkerforgeException {
        BrickletThermalImagingConfig cfg = (BrickletThermalImagingConfig) config.as(BrickletThermalImagingConfig.class);
switch(channel) {
            case "BrickletThermalImagingHighContrastImage":
                   {
            int[] value = this.getHighContrastImage();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingHighContrastImageGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingTemperatureImage":
                   {
            int[] value = this.getTemperatureImage();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingTemperatureImageGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingSpotmeterMeanTemperature":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingSpotmeterMeanTemperatureGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingSpotmeterMaximumTemperature":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingSpotmeterMaximumTemperatureGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingSpotmeterMinimumTemperature":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingSpotmeterMinimumTemperatureGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingSpotmeterROIPixelCount":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingSpotmeterROIPixelCountGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingFocalPlainArrayTemperature":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingFocalPlainArrayTemperatureGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingFocalPlainArrayTemperatureFFC":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingFocalPlainArrayTemperatureFFCGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingHousingTemperature":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingHousingTemperatureGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingHousingTemperatureFFC":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingHousingTemperatureFFCGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingFFCStatus":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingFFCStatusGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingShutterLockout":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingShutterLockoutGetter0(value, cfg));
        }
                   return;
            case "BrickletThermalImagingOvertemperatureShutdownImminent":
                   {
            BrickletThermalImaging.Statistics value = this.getStatistics();
            if(true)
                updateStateFn.accept(channel, transformBrickletThermalImagingOvertemperatureShutdownImminentGetter0(value, cfg));
        }
                   return;
default:
                logger.warn("Refresh for unknown channel {}", channel);
                break;
        }
    }
    

        @Override
    public List<SetterRefresh> handleCommand(org.eclipse.smarthome.config.core.Configuration config, org.eclipse.smarthome.config.core.Configuration channelConfig, String channel, Command command) throws TinkerforgeException {
        List<SetterRefresh> result = Collections.emptyList();
        
        switch(channel) {
            default:
                logger.warn("Command for unknown channel {}", channel);
        }
        return result;
    }

        private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingHighContrastImageGetter0(int[] value, BrickletThermalImagingConfig cfg) {
        return new RawType(Helper.convertThermalHighContrastImage(value, cfg.colorPalette, logger, cfg.scaleFactor), "image/png");
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingTemperatureImageGetter0(int[] value, BrickletThermalImagingConfig cfg) {
        return new RawType(Helper.convertThermalTemperatureImage(value, cfg.colorPalette, logger, cfg.scaleFactor), "image/png");
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingSpotmeterMeanTemperatureGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return new QuantityType<>(value.spotmeterStatistics[0] / (cfg.resolution == 0 ? 10.0 : 100.0), SmartHomeUnits.KELVIN);
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingSpotmeterMaximumTemperatureGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return new QuantityType<>(value.spotmeterStatistics[1] / (cfg.resolution == 0 ? 10.0 : 100.0), SmartHomeUnits.KELVIN);
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingSpotmeterMinimumTemperatureGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return new QuantityType<>(value.spotmeterStatistics[2] / (cfg.resolution == 0 ? 10.0 : 100.0), SmartHomeUnits.KELVIN);
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingSpotmeterROIPixelCountGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return new DecimalType(value.spotmeterStatistics[3]);
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingFocalPlainArrayTemperatureGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return new QuantityType<>(value.temperatures[0] / (cfg.resolution == 0 ? 10.0 : 100.0), SmartHomeUnits.KELVIN);
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingFocalPlainArrayTemperatureFFCGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return new QuantityType<>(value.temperatures[1] / (cfg.resolution == 0 ? 10.0 : 100.0), SmartHomeUnits.KELVIN);
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingHousingTemperatureGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return new QuantityType<>(value.temperatures[2] / (cfg.resolution == 0 ? 10.0 : 100.0), SmartHomeUnits.KELVIN);
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingHousingTemperatureFFCGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return new QuantityType<>(value.temperatures[3] / (cfg.resolution == 0 ? 10.0 : 100.0), SmartHomeUnits.KELVIN);
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingFFCStatusGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return new DecimalType(value.ffcStatus);
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingShutterLockoutGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return value.temperatureWarning[0] ? OpenClosedType.CLOSED : OpenClosedType.OPEN;
    }
	    private org.eclipse.smarthome.core.types.State transformBrickletThermalImagingOvertemperatureShutdownImminentGetter0(BrickletThermalImaging.Statistics value, BrickletThermalImagingConfig cfg) {
        return value.temperatureWarning[1] ? OpenClosedType.CLOSED : OpenClosedType.OPEN;
    }

}