"""
homeassistant.components.climate.heatmiserneo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Heatmiser NeoStat control via Heatmiser Neo-hub
Code largely ripped off and glued together from:
demo.py, nest.py and light/hyperion.py for the json elements
"""

from homeassistant.components.climate import ClimateEntity, PLATFORM_SCHEMA
import logging
import voluptuous as vol
from homeassistant.components.climate.const import (
    ATTR_TARGET_TEMP_HIGH,
    ATTR_TARGET_TEMP_LOW,
    CURRENT_HVAC_COOL,
    CURRENT_HVAC_HEAT,
    CURRENT_HVAC_IDLE,
    CURRENT_HVAC_OFF,
    HVAC_MODE_COOL,
    HVAC_MODE_HEAT,
    HVAC_MODE_HEAT_COOL,
    HVAC_MODE_OFF,
    HVAC_MODES,
    SUPPORT_AUX_HEAT,
    SUPPORT_FAN_MODE,
    SUPPORT_PRESET_MODE,
    SUPPORT_SWING_MODE,
    SUPPORT_TARGET_HUMIDITY,
    SUPPORT_TARGET_TEMPERATURE,
    SUPPORT_TARGET_TEMPERATURE_RANGE,
    HVAC_MODE_AUTO,
)
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
from homeassistant.const import (CONF_HOST,CONF_PORT,CONF_NAME)
import homeassistant.helpers.config_validation as cv
import socket
import json

_LOGGER = logging.getLogger(__name__)

VERSION = '2.0.2'

SUPPORT_FLAGS = 0

# Heatmiser does support all lots more stuff, but only heat for now.
#hvac_modes=[HVAC_MODE_HEAT_COOL, HVAC_MODE_COOL, HVAC_MODE_HEAT, HVAC_MODE_OFF]
# Heatmiser doesn't really have an off mode - standby is a preset - implement later
hvac_modes = [HVAC_MODE_OFF, HVAC_MODE_HEAT]

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
    {
        vol.Required(CONF_HOST): cv.string,
        vol.Required(CONF_PORT): cv.port,
    }
)

# Fix this when I figure out why my config won't read in. Voluptuous schema thing.
# Excludes time clocks from being included if set to True
ExcludeTimeClock = False

def setup_platform(hass, config, add_devices, discovery_info=None):
    """ Sets up a Heatmiser Neo-Hub And Returns Neostats"""
    host = config.get(CONF_HOST, None)
    port = config.get(CONF_PORT, 4242)

    thermostats = []

    NeoHubJson = HeatmiserNeostat(TEMP_CELSIUS, False, host, port).json_request({"INFO": 0})

    _LOGGER.debug(NeoHubJson)

    for device in NeoHubJson['devices']:
        if device['DEVICE_TYPE'] != 6:
            name = device['device']
            tmptempfmt = device['TEMPERATURE_FORMAT']
            if (tmptempfmt == False) or (tmptempfmt.upper() == "C"):
                temperature_unit = TEMP_CELSIUS
            else:
                temperature_unit = TEMP_FAHRENHEIT
            away = device['AWAY']
            current_temperature = device['CURRENT_TEMPERATURE']
            set_temperature = device['CURRENT_SET_TEMPERATURE']

            _LOGGER.info("Thermostat Name: %s " % name)
            _LOGGER.info("Thermostat Away Mode: %s " % away)
            _LOGGER.info("Thermostat Current Temp: %s " % current_temperature)
            _LOGGER.info("Thermostat Set Temp: %s " % set_temperature)
            _LOGGER.info("Thermostat Unit Of Measurement: %s " % temperature_unit)

            if (('TIMECLOCK' in device['STAT_MODE']) and (ExcludeTimeClock == True)):
              _LOGGER.debug("Found a Neostat configured in timer mode named: %s skipping" % device['device'])
            else:
              thermostats.append(HeatmiserNeostat(temperature_unit, away, host, port, name))

        elif device['DEVICE_TYPE'] == 6:
            _LOGGER.debug("Found a Neoplug named: %s skipping" % device['device'])

    _LOGGER.info("Adding Thermostats: %s " % thermostats)
    add_devices(thermostats)


class HeatmiserNeostat(ClimateEntity):
    """ Represents a Heatmiser Neostat thermostat. """
    def __init__(self, unit_of_measurement, away, host, port, name="Null"):
        self._name = name
        self._unit_of_measurement = unit_of_measurement
        self._away = away
        self._host = host
        self._port = port
        #self._type = type Neostat vs Neostat-e
        self._hvac_action = None
        self._hvac_mode = None
        self._hvac_modes = hvac_modes
        self._support_flags = SUPPORT_FLAGS
        self._support_flags = self._support_flags | SUPPORT_TARGET_TEMPERATURE
        self.update()

    @property
    def supported_features(self):
        """Return the list of supported features."""
        return self._support_flags

    @property
    def should_poll(self):
        """ No polling needed for a demo thermostat. """
        return True

    @property
    def name(self):
        """ Returns the name. """
        return self._name

    @property
    def temperature_unit(self):
        """Return the unit of measurement."""
        return self._unit_of_measurement

    @property
    def current_temperature(self):
        """ Returns the current temperature. """
        return self._current_temperature

    @property
    def target_temperature(self):
        """Return the temperature we try to reach."""
        return self._target_temperature

    @property
    def current_humidity(self):
        """Return the current humidity."""
        return self._current_humidity

    @property
    def target_humidity(self):
        """Return the humidity we try to reach."""
        return self._target_humidity

    #@property
    #def target_temperature(self):
    #    """ Returns the temperature we try to reach. """
    #    return self._target_temperature

    @property
    def hvac_action(self):
        """Return current activity ie. currently heating, cooling, idle."""
        return self._hvac_action

    @property
    def hvac_mode(self):
        """Return current operation mode ie. heat, cool, off."""
        return self._hvac_mode

    @property
    def hvac_modes(self):
        """Return the list of available operation modes."""
        return self._hvac_modes

    # @property
    # def preset_mode(self):
    #     """Return preset mode."""
    #     return self._preset

    # @property
    # def preset_modes(self):
    #     """Return preset modes."""
    #     return self._preset_modes

    def set_temperature(self, **kwargs):
        """ Set new target temperature. """
        response = self.json_request({"SET_TEMP": [int(kwargs.get(ATTR_TEMPERATURE)), self._name]})
        if response:
            _LOGGER.info("set_temperature response: %s " % response)
            # Need check for success here
            # {'result': 'temperature was set'}

    def set_hvac_mode(self, hvac_mode):
        """Set hvac mode."""
        if hvac_mode == HVAC_MODE_HEAT:
            self._hvac_mode = HVAC_MODE_HEAT
            mode = "FROST_OFF"
        elif hvac_mode == HVAC_MODE_OFF:
            self._hvac_mode = HVAC_MODE_OFF
            mode = "FROST_ON"
        else:
            _LOGGER.error("Unrecognized hvac mode: %s", hvac_mode)
            return

        response = self.json_request({mode: [self._name]})
        if response:
            _LOGGER.info("set_hvac_mode response: %s " % response)

    def update(self):
        """ Get Updated Info. """
        _LOGGER.debug("Entered update(self)")
        response = self.json_request({"INFO": 0})
        if response:
            # Add handling for mulitple thermostats here
            _LOGGER.debug("update() json response: %s " % response)
            # self._name = device['device']
            for device in response['devices']:
              if self._name == device['device']:
                tmptempfmt = device["TEMPERATURE_FORMAT"]
                if (tmptempfmt == False) or (tmptempfmt.upper() == "C"):
                  self._temperature_unit = TEMP_CELSIUS
                else:
                  self._temperature_unit = TEMP_FAHRENHEIT
                self._away = device['AWAY']
                self._target_temperature =  round(float(device["CURRENT_SET_TEMPERATURE"]), 2)
                self._current_temperature = round(float(device["CURRENT_TEMPERATURE"]), 2)
                self._current_humidity = round(float(device["HUMIDITY"]), 2)

                if device['STANDBY']:
                    self._hvac_mode = HVAC_MODE_OFF
                elif device["COOLING_ENABLED"] == True:
                    self._hvac_mode = HVAC_MODE_COOL
                else:
                    self._hvac_mode = HVAC_MODE_HEAT

                # Figure out current action based on Heating / Cooling flags
                if device["HEATING"] == True:
                    self._hvac_action = CURRENT_HVAC_HEAT
                    _LOGGER.debug("Heating")
                elif device["COOLING"] == True:
                    self._hvac_action = CURRENT_HVAC_COOL
                    _LOGGER.debug("Cooling")
                else:
                    self._hvac_action = CURRENT_HVAC_IDLE
                    _LOGGER.debug("Idle")
        return False

    def json_request(self, request=None, wait_for_response=False):
        """ Communicate with the json server. """
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(5)

        try:
            sock.connect((self._host, self._port))
        except OSError:
            sock.close()
            return False

        if not request:
            # no communication needed, simple presence detection returns True
            sock.close()
            return True

        _LOGGER.debug("json_request: %s " % request)

        sock.send(bytearray(json.dumps(request) + "\0\r", "utf-8"))
        try:
            buf = sock.recv(4096)
        except socket.timeout:
            # something is wrong, assume it's offline
            sock.close()
            return False

        # read until a newline or timeout
        buffering = True
        while buffering:
            if "\n" in str(buf, "utf-8"):
                response = str(buf, "utf-8").split("\n")[0]
                buffering = False
            else:
                try:
                    more = sock.recv(4096)
                except socket.timeout:
                    more = None
                if not more:
                    buffering = False
                    response = str(buf, "utf-8")
                else:
                    buf += more

        sock.close()

        response = response.rstrip('\0')

        _LOGGER.debug("json_response: %s " % response)

        return json.loads(response, strict=False)