"""
Support for Anthem Network Receivers and Processors.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.anthemav/
"""
import logging
import asyncio

import voluptuous as vol

from homeassistant.components.media_player import (
    PLATFORM_SCHEMA, SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_SELECT_SOURCE,
    SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, MediaPlayerDevice)
from homeassistant.const import (
    CONF_NAME, CONF_HOST, CONF_PORT, STATE_OFF, STATE_ON, STATE_UNKNOWN,
    EVENT_HOMEASSISTANT_STOP)
import homeassistant.helpers.config_validation as cv

REQUIREMENTS = ['anthemav==1.1.8']

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'anthemav'

DEFAULT_PORT = 14999

SUPPORT_ANTHEMAV = SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
    SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_SELECT_SOURCE

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


@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
    """Set up our socket to the AVR."""
    import anthemav

    host = config.get(CONF_HOST)
    port = config.get(CONF_PORT)
    name = config.get(CONF_NAME)
    device = None

    _LOGGER.info('Provisioning Anthem AVR device at %s:%d', host, port)

    def async_anthemav_update_callback(message):
        """Receive notification from transport that new data exists."""
        _LOGGER.info('Received update calback from AVR: %s', message)
        hass.async_add_job(device.async_update_ha_state())

    avr = yield from anthemav.Connection.create(
        host=host, port=port, loop=hass.loop,
        update_callback=async_anthemav_update_callback)

    device = AnthemAVR(avr, name)

    _LOGGER.debug('dump_devicedata: '+device.dump_avrdata)
    _LOGGER.debug('dump_conndata: '+avr.dump_conndata)
    _LOGGER.debug('dump_rawdata: '+avr.protocol.dump_rawdata)

    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, device.avr.close)
    yield from async_add_devices([device])


class AnthemAVR(MediaPlayerDevice):
    """Entity reading values from Anthem AVR protocol."""

    def __init__(self, avr, name):
        """"Initialize entity with transport."""
        super().__init__()
        self.avr = avr
        self._name = name

    def _lookup(self, propname, dval=None):
        return getattr(self.avr.protocol, propname, dval)

    @property
    def supported_media_commands(self):
        """Return flag of media commands that are supported."""
        return SUPPORT_ANTHEMAV

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def name(self):
        """Return name of device."""
        return self._name or self._lookup('model')

    @property
    def state(self):
        """Return state of power on/off."""
        pwrstate = self._lookup('power')

        if pwrstate is True:
            return STATE_ON
        elif pwrstate is False:
            return STATE_OFF
        else:
            return STATE_UNKNOWN

    @property
    def is_volume_muted(self):
        """Return boolean reflecting mute state on device."""
        return self._lookup('mute', False)

    @property
    def volume_level(self):
        """Return volume level from 0 to 1."""
        return self._lookup('volume_as_percentage', 0.0)

    @property
    def media_title(self):
        """Return current input name (closest we have to media title)."""
        return self._lookup('input_name', 'No Source')

    @property
    def app_name(self):
        """Return details about current video and audio stream."""
        return self._lookup('video_input_resolution_text', '') + ' ' \
            + self._lookup('audio_input_name', '')

    @property
    def source(self):
        """Return currently selected input."""
        return self._lookup('input_name', "Unknown")

    @property
    def source_list(self):
        """Return all active, configured inputs."""
        return self._lookup('input_list', ["Unknown"])

    @asyncio.coroutine
    def async_select_source(self, source):
        """Change AVR to the designated source (by name)."""
        self._update_avr('input_name', source)

    @asyncio.coroutine
    def async_turn_off(self):
        """Turn AVR power off."""
        self._update_avr('power', False)

    @asyncio.coroutine
    def async_turn_on(self):
        """Turn AVR power on."""
        self._update_avr('power', True)

    @asyncio.coroutine
    def async_set_volume_level(self, volume):
        """Set AVR volume (0 to 1)."""
        self._update_avr('volume_as_percentage', volume)

    @asyncio.coroutine
    def async_mute_volume(self, mute):
        """Engage AVR mute."""
        self._update_avr('mute', mute)

    def _update_avr(self, propname, value):
        """Update a property in the AVR."""
        _LOGGER.info('Sending command to AVR: set '+propname+' to '+str(value))
        setattr(self.avr.protocol, propname, value)

    @property
    def dump_avrdata(self):
        """Return state of avr object for debugging forensics."""
        attrs = vars(self)
        return(
            'dump_avrdata: '
            + ', '.join('%s: %s' % item for item in attrs.items()))
