/*
 * Copyright 2016 The Winston Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.s13g.winston.master.channel.instance;

import com.google.common.collect.ImmutableList;
import com.s13g.winston.lib.nest.Thermostat;
import com.s13g.winston.lib.temperature.Temperature;
import com.s13g.winston.master.channel.Channel;
import com.s13g.winston.master.channel.ChannelException;
import com.s13g.winston.master.channel.ChannelValue;
import com.s13g.winston.master.channel.ReadOnlyChannelValue;

import java.util.List;
import java.util.Optional;

/**
 * A channel for a Nest thermostat.
 */
public class NestThermostatChannel implements Channel {
  private final String mChannelId;
  private final Thermostat mThermostat;

  public NestThermostatChannel(String channelId, Thermostat thermostat) {
    mChannelId = channelId;
    mThermostat = thermostat;
  }

  @Override
  public String getChannelId() {
    return mChannelId;
  }

  @Override
  public List<ChannelValue> getValues() {
    ChannelValue<Float> ambientTempCelcius = new ReadOnlyChannelValue<>(
        "ambientTempCelsius", this::readTemperature,
        "Cannot set ambientTemp. Set targetTemp instead.");
    ChannelValue<Float> humidity = new ReadOnlyChannelValue<>(
        "humidity", this::readHumidity, "Cannot set humidity.");

    return ImmutableList.of(
        ambientTempCelcius,
        humidity,
        new NestTargetTemperatureCelsiusChannel());
  }

  /** Reads the temperature from the thermostat. */
  private float readTemperature() throws ChannelException {
    Optional<Temperature> ambientTemperature = mThermostat.refresh().getAmbientTemperature();
    if (!ambientTemperature.isPresent()) {
      throw new ChannelException("Cannot read ambient temperature for '" + mChannelId + "'.");
    }
    return ambientTemperature.get().get(Temperature.Unit.CELSIUS);
  }

  /** Read the humidity from the thermostat. */
  private float readHumidity() throws ChannelException {
    Optional<Float> ambientTemperature = mThermostat.refresh().getHumidity();
    if (!ambientTemperature.isPresent()) {
      throw new ChannelException("Cannot read humidity for '" + mChannelId + "'.");
    }
    return ambientTemperature.get();
  }

  /** Read/Write channel for the thermostat's target temperature. */
  private class NestTargetTemperatureCelsiusChannel implements ChannelValue<Float> {
    @Override
    public Mode getType() {
      return Mode.READ_WRITE;
    }

    @Override
    public String getName() {
      return "targetTempCelsius";
    }

    @Override
    public void writeRaw(String valueRaw) throws ChannelException {
      try {
        write(Float.parseFloat(valueRaw));
      } catch (NumberFormatException ex) {
        throw new ChannelException("Cannot parse temperature", ex);
      }
    }

    @Override
    public void write(Float value) throws ChannelException {
      mThermostat.setTargetTemperature(new Temperature(value, Temperature.Unit.CELSIUS));
    }

    @Override
    public Float read() throws ChannelException {
      Optional<Temperature> ambientTemperature = mThermostat.refresh().getTargetTemperature();
      if (!ambientTemperature.isPresent()) {
        throw new ChannelException("Cannot read target temperature for '" + mChannelId + "'.");
      }
      return ambientTemperature.get().get(Temperature.Unit.CELSIUS);
    }
  }
}

@@ -1509,24 +1509,148 @@
 tValues() %7B%0A
+    ChannelValue%3CString%3E deviceName = new ReadOnlyChannelValue%3C%3E(%0A        %22deviceName%22, this::readName, %22Cannot set name%22);%0A
     ChannelV
@@ -1702,32 +1702,32 @@
 ChannelValue%3C%3E(%0A
-
         %22ambient
@@ -1981,16 +1981,36 @@
 ist.of(%0A
+        deviceName,%0A
         
@@ -2096,32 +2096,319 @@
 hannel());%0A  %7D%0A%0A
+  private String readName() throws ChannelException %7B%0A    Optional%3CString%3E deviceName = mThermostat.refresh().getName();%0A    if (!deviceName.isPresent()) %7B%0A      throw new ChannelException(%22Cannot read thermostat name for '%22 + mChannelId + %22'.%22);%0A    %7D%0A    return deviceName.get();%0A  %7D%0A%0A
   /** Reads the 
@@ -2938,34 +2938,24 @@
 %3CFloat%3E 
-ambientTemperature
+humidity
  = mTher
@@ -2995,34 +2995,24 @@
    if (!
-ambientTemperature
+humidity
 .isPrese
@@ -3120,34 +3120,24 @@
  return 
-ambientTemperature
+humidity
 .get();%0A

Add channel for reading thermostat name.