# pylint: disable=C0111,R0903

"""Displays battery status, remaining percentage and charging information.

Parameters:
    * battery.device              : Comma-separated list of battery devices to read information from (defaults to auto for auto-detection)
    * battery.warning             : Warning threshold in % of remaining charge (defaults to 20)
    * battery.critical            : Critical threshold in % of remaining charge (defaults to 10)
    * battery.showdevice          : If set to 'true', add the device name to the widget (defaults to False)
    * battery.decorate            : If set to 'false', hides additional icons (charging, etc.) (defaults to True)
    * battery.showpowerconsumption: If set to 'true', show current power consumption (defaults to False)
    * battery.compact-devices     : If set to 'true', compacts multiple batteries into a single entry (default to False)
"""

import os
import glob
import logging
log = logging.getLogger(__name__)

try:
    import power
except ImportError:
    log.warning('unable to import module "power": Time estimates will not be available')

import core.module
import core.widget
import core.input

import util.format

class BatteryManager(object):
    def remaining(self):
        try:
            estimate = power.PowerManagement().get_time_remaining_estimate()
            # do not show remaining if on AC
            if estimate == power.common.TIME_REMAINING_UNLIMITED:
                return None
            return estimate*60 # return value in seconds
        except Exception as e:
            return -1
        return -1

    def read(self, battery, component, default=None):
        path = '/sys/class/power_supply/{}'.format(battery)
        if not os.path.exists(path):
            return default
        try:
            with open('{}/{}'.format(path, component)) as f:
                return f.read().strip()
        except IOError:
            return 'n/a'
        return default


    def capacity(self, battery):
        capacity = self.read(battery, 'capacity', 100)
        if capacity != 'n/a':
            capacity = int(capacity)

        return capacity if capacity < 100 else 100

    def capacity_all(self, batteries):
        now = 0
        full = 0
        for battery in batteries:
            try:
                with open('/sys/class/power_supply/{}/energy_full'.format(battery)) as f:
                    full += int(f.read())
                with open('/sys/class/power_supply/{}/energy_now'.format(battery)) as f:
                    now += int(f.read())
            except IOError:
                return 'n/a'
        return int(float(now)/float(full)*100.0)

    def isac(self, battery):
        path = '/sys/class/power_supply/{}'.format(battery)
        return not os.path.exists(path)

    def isac_any(self, batteries):
        for battery in batteries:
            if self.isac(battery): return True
        return False

    def consumption(self, battery):
        consumption = self.read(battery, 'power_now', 'n/a')
        if consumption == 'n/a':
            return 'n/a'
        return '{}W'.format(int(consumption)/1000000)

    def charge(self, battery):
        return self.read(battery, 'status', 'n/a')

    def charge_any(self, batteries):
        for battery in batteries:
            if self.charge(battery) == 'Discharging':
                return 'Discharging'
        return 'Charged'

class Module(core.module.Module):
    def __init__(self, config, theme):
        widgets = []
        super().__init__(config, theme, widgets)

        self.__manager = BatteryManager()

        self._batteries = util.format.aslist(self.parameter('device', 'auto'))
        if self._batteries[0] == 'auto':
            self._batteries = [ os.path.basename(battery) for battery in glob.glob('/sys/class/power_supply/BAT*') ]
        if len(self._batteries) == 0:
            raise Exceptions('no batteries configured/found')
        core.input.register(self, button=core.input.LEFT_MOUSE,
            cmd='gnome-power-statistics')

        if util.format.asbool(self.parameter('compact-devices', False)):
            widget = core.widget.Widget(full_text=self.capacity, name='all-batteries', module=self)
            widgets.append(widget)
        else:
            for battery in self._batteries:
                log.debug('adding new widget for {}'.format(battery))
                widget = core.widget.Widget(full_text=self.capacity, name=battery, module=self)
                widgets.append(widget)
        for w in self.widgets():
            if util.format.asbool(self.parameter('decorate', True)) == False:
                widget.set('theme.exclude', 'suffix')

    def capacity(self, widget):
        if widget.name == 'all-batteries':
            capacity = self.__manager.capacity_all(self._batteries)
        else:
            capacity = self.__manager.capacity(widget.name)
        widget.set('capacity', capacity)
        widget.set('ac', self.__manager.isac_any(self._batteries))
        widget.set('theme.minwidth', '100%')

        # Read power conumption
        if util.format.asbool(self.parameter('showpowerconsumption', False)):
            output = '{}% ({})'.format(capacity, self.__manager.consumption(widget.name))
        else:
             output =  '{}%'.format(capacity)

        if util.format.asbool(self.parameter('showremaining', True))\
                and self.__manager.charge(widget.name) == 'Discharging':
            remaining = self.__manager.remaining()
            if remaining >= 0:
                output = '{} {}'.format(output, util.format.duration(remaining, compact=True, unit=True))

        if util.format.asbool(self.parameter('showdevice', False)):
            output = '{} ({})'.format(output, widget.name)

        return output
       
    def state(self, widget):
        state = []
        capacity = widget.get('capacity')

        if capacity < 0:
            log.debug('battery state: {}'.format(state))
            return ['critical', 'unknown']

        if capacity < int(self.parameter('critical', 10)):
            state.append('critical')
        elif capacity < int(self.parameter('warning', 20)):
            state.append('warning')

        if widget.get('ac'):
            state.append('AC')
        else:
            if widget.name == 'all-batteries':
                charge = self.__manager.charge_any(self._batteries)
            else:
                charge = self.__manager.charge(widget.name)
            if charge == 'Discharging':
                state.append('discharging-{}'.format(min([10, 25, 50, 80, 100], key=lambda i: abs(i-capacity))))
            elif charge == 'Unknown':
                state.append('unknown-{}'.format(min([10, 25, 50, 80, 100], key=lambda i: abs(i-capacity))))
            else:
                if capacity > 95:
                    state.append('charged')
                else:
                    state.append('charging')
        return state

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4