"""
Tools to interact with XRootD's `report` functionality
"""
from __future__ import division, absolute_import
import time
import logging
import subprocess
import atexit

from ..utilities import singleton, safe_eval

import chainlet


class XRootDReports(singleton.Singleton, chainlet.ChainLink):
    """
    Collects information generated by the `all.report` directive

    :param port: port receiving reports
    :type port: int

    Provides xrootd reports as individual dictionaries to a chain.
    Keys are preserved, while values are evaluated as literals.
    """
    def __init__(self, port):
        super(XRootDReports, self).__init__()
        self.port = port
        self._reportstreamer = None
        self._logger = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__))

    @classmethod
    def __singleton_signature__(cls, port):
        return XRootDReports, port

    def open(self):
        """Start collecting reports"""
        if self._reportstreamer is None:
            self._logger.info('opening report stream on port %d', self.port)
            self._reportstreamer = subprocess.Popen(
                ['mpxstats', '-p', str(self.port), '-f', 'cgi'],
                stdout=subprocess.PIPE,
                universal_newlines=True,
            )
            self._logger.info('buffering report stream')
            atexit.register(self._reportstreamer.terminate)

    def close(self):
        """Stop collecting reports"""
        if self._reportstreamer is not None:
            if self._reportstreamer.poll() is None:
                self._reportstreamer.terminate()
                time.sleep(0.1)
            self._logger.info('closed report stream on port %d (exit code: %s)', self.port, self._reportstreamer.poll())
            self._reportstreamer = None

    def chainlet_send(self, value=None):
        """Fetch a report"""
        self.open()
        line = self._reportstreamer.stdout.readline()
        self._logger.debug('received datagram: %r', line)
        datagram = dict(item.split('=') for item in line.split('&'))
        for key in datagram:
            datagram[key] = safe_eval(datagram[key])
        return datagram

    def __enter__(self):
        # start collection on entering the context, do not delay until consumption
        self.open()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()
        return False

    def __del__(self):
        self.close()


xrdreports = XRootDReports
