"""
Support for real-time departure information for public transport in Munich.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.mvglive/
"""
import logging
from datetime import timedelta

import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
    CONF_NAME, ATTR_ATTRIBUTION, STATE_UNKNOWN
    )

REQUIREMENTS = ['PyMVGLive==1.1.3']

_LOGGER = logging.getLogger(__name__)

CONF_NEXT_DEPARTURE = 'nextdeparture'

CONF_STATION = 'station'
CONF_DESTINATIONS = 'destinations'
CONF_DIRECTIONS = 'directions'
CONF_LINES = 'lines'
CONF_PRODUCTS = 'products'
CONF_TIMEOFFSET = 'timeoffset'

DEFAULT_PRODUCT = ['U-Bahn', 'Tram', 'Bus', 'S-Bahn']

ICONS = {
    'U-Bahn': 'mdi:subway',
    'Tram': 'mdi:tram',
    'Bus': 'mdi:bus',
    'S-Bahn': 'mdi:train',
    'SEV': 'mdi:checkbox-blank-circle-outline',
    '-': 'mdi:clock'
}
ATTRIBUTION = "Data provided by MVG-live.de"

SCAN_INTERVAL = timedelta(seconds=30)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_NEXT_DEPARTURE): [{
        vol.Required(CONF_STATION): cv.string,
        vol.Optional(CONF_DESTINATIONS, default=['']): cv.ensure_list_csv,
        vol.Optional(CONF_DIRECTIONS, default=['']): cv.ensure_list_csv,
        vol.Optional(CONF_LINES, default=['']): cv.ensure_list_csv,
        vol.Optional(CONF_PRODUCTS, default=DEFAULT_PRODUCT):
            cv.ensure_list_csv,
        vol.Optional(CONF_TIMEOFFSET, default=0): cv.positive_int,
        vol.Optional(CONF_NAME): cv.string}]
})


def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the MVGLive sensor."""
    sensors = []
    for nextdeparture in config.get(CONF_NEXT_DEPARTURE):
        sensors.append(
            MVGLiveSensor(
                nextdeparture.get(CONF_STATION),
                nextdeparture.get(CONF_DESTINATIONS),
                nextdeparture.get(CONF_DIRECTIONS),
                nextdeparture.get(CONF_LINES),
                nextdeparture.get(CONF_PRODUCTS),
                nextdeparture.get(CONF_TIMEOFFSET),
                nextdeparture.get(CONF_NAME)))
    add_devices(sensors, True)


# pylint: disable=too-few-public-methods
class MVGLiveSensor(Entity):
    """Implementation of an MVG Live sensor."""

    def __init__(self, station, destinations, directions,
                 lines, products, timeoffset, name):
        """Initialize the sensor."""
        self._station = station
        self._name = name
        self.data = MVGLiveData(station, destinations, directions,
                                lines, products, timeoffset)
        self._state = STATE_UNKNOWN
        self._icon = ICONS['-']

    @property
    def name(self):
        """Return the name of the sensor."""
        if self._name:
            return self._name
        else:
            return self._station

    @property
    def state(self):
        """Return the next departure time."""
        return self._state

    @property
    def state_attributes(self):
        """Return the state attributes."""
        return self.data.departures

    @property
    def icon(self):
        """Icon to use in the frontend, if any."""
        return self._icon

    @property
    def unit_of_measurement(self):
        """Return the unit this state is expressed in."""
        return "min"

    def update(self):
        """Get the latest data and update the state."""
        self.data.update()
        if not self.data.departures:
            self._state = '-'
            self._icon = ICONS['-']
        else:
            self._state = self.data.departures.get('time', '-')
            self._icon = ICONS[self.data.departures.get('product', '-')]


class MVGLiveData(object):
    """Pull data from the mvg-live.de web page."""

    def __init__(self, station, destinations, directions,
                 lines, products, timeoffset):
        """Initialize the sensor."""
        import MVGLive
        self._station = station
        self._destinations = destinations
        self._directions = directions
        self._lines = lines
        self._products = products
        self._timeoffset = timeoffset
        self._include_ubahn = True if 'U-Bahn' in self._products else False
        self._include_tram = True if 'Tram' in self._products else False
        self._include_bus = True if 'Bus' in self._products else False
        self._include_sbahn = True if 'S-Bahn' in self._products else False
        self.mvg = MVGLive.MVGLive()
        self.departures = {}

    def update(self):
        """Update the connection data."""
        try:
            _departures = self.mvg.getlivedata(
                station=self._station, ubahn=self._include_ubahn,
                tram=self._include_tram, bus=self._include_bus,
                sbahn=self._include_sbahn)
        except ValueError:
            self.departures = {}
            _LOGGER.warning("Returned data not understood")
            return
        for _departure in _departures:
            # find the first departure meeting the criteria
            if ('' not in self._destinations[:1] and
                    _departure['destination'] not in self._destinations):
                continue
            elif ('' not in self._directions[:1] and
                  _departure['direction'] not in self._directions):
                continue
            elif ('' not in self._lines[:1] and
                  _departure['linename'] not in self._lines):
                continue
            elif _departure['time'] < self._timeoffset:
                continue
            # now select the relevant data
            _nextdep = {ATTR_ATTRIBUTION: ATTRIBUTION}
            for k in ['destination', 'linename', 'time', 'direction',
                      'product']:
                _nextdep[k] = _departure.get(k, '')
            _nextdep['time'] = int(_nextdep['time'])
            self.departures = _nextdep
            break
