class Transformers {

   static void addThermostatAttrs(Model m, ImmutableMap.Builder<String, Object> attrs, Map<String, Object> params) {
      if(params == null) {
         params = ImmutableMap.of();
      }

      assertCapability(m, ThermostatCapability.NAMESPACE);

      String newMode = (String) params.get(Commands.SetMode.arg_mode);
      String targetMode = newMode == null ? ThermostatModel.getHvacmode(m) : Constants.TemperatureSettingMode.valueOf(newMode.toLowerCase()).toIris();

      if(!Objects.equals(targetMode, ThermostatModel.getHvacmode(m))) {
         attrs.put(ThermostatCapability.ATTR_HVACMODE, targetMode);
      }

      Number tempNumber = (Number) params.get(Commands.TemperatureSetPoint.arg_temperature);
      Double temp = tempNumber == null ? null : tempNumber.doubleValue();

      switch(targetMode) {
         case ThermostatCapability.HVACMODE_OFF:
            return;
         case ThermostatCapability.HVACMODE_COOL:
            if(modeChangeOnlyTemp(temp)) { return; }
            assertSetPoint(temp);
            attrs.put(ThermostatCapability.ATTR_COOLSETPOINT, temp);
            break;
         case ThermostatCapability.HVACMODE_HEAT:
            if(modeChangeOnlyTemp(temp)) { return; }
            assertSetPoint(temp);
            attrs.put(ThermostatCapability.ATTR_HEATSETPOINT, temp);
            break;
         case ThermostatCapability.HVACMODE_AUTO:
            Number tempHighNumber = (Number) params.get(Commands.TemperatureSetRange.arg_temperature_high);
            Double tempHigh = tempHighNumber == null ? null : tempHighNumber.doubleValue();
            Number tempLowNumber = (Number) params.get(Commands.TemperatureSetRange.arg_temperature_low);
            Double tempLow = tempLowNumber == null ? null : tempLowNumber.doubleValue();

            // mode only change
            if(modeChangeOnlyTemp(temp) && modeChangeOnlyTemp(tempHigh) && modeChangeOnlyTemp(tempLow)) {
               return;
            }

            if((tempHigh != null && tempLow == null) || (tempHigh == null && tempLow != null)) {
               throw new ErrorEventException(
                  Constants.Error.VALUE_OUT_OF_RANGE,
                  Commands.TemperatureSetRange.name + " must have both " + Commands.TemperatureSetRange.arg_temperature_low + " and " + Commands.TemperatureSetRange.arg_temperature_high
               );
            }

            if(tempHigh == null && tempLow == null) {
               Pair<Double, Double> idealRange = calculateIdealRange(m, temp);
               tempLow = idealRange.getLeft();
               tempHigh = idealRange.getRight();
            } else {
               assertGap(tempLow, tempHigh);
            }
            attrs.put(ThermostatCapability.ATTR_HEATSETPOINT, tempLow);
            attrs.put(ThermostatCapability.ATTR_COOLSETPOINT, tempHigh);
            break;
         default:
            /* no op */
      }
   }

   private  Transformers();

}