import time

from checks import AgentCheck

import xmlrpclib

DEFAULT_HOST = 'localhost'
DEFAULT_PORT = '9001'
DEFAULT_SERVER = 'server'

OK = AgentCheck.OK
CRITICAL = AgentCheck.CRITICAL
UNKNOWN = AgentCheck.UNKNOWN

STATUS_MAP = {
    'STOPPED': CRITICAL,
    'STARTING': OK,
    'RUNNING': OK,
    'BACKOFF': UNKNOWN,
    'STOPPING': CRITICAL,
    'EXITED': CRITICAL,
    'FATAL': CRITICAL,
    'UNKNOWN': UNKNOWN
}

TIME_FORMAT = '%Y-%m-%d %H:%M:%S'


def time_formatter(s):
    return time.strftime(TIME_FORMAT, time.localtime(s))


class SupervisordCheck(AgentCheck):

    def check(self, instance):
        server_name = instance.get('name', DEFAULT_SERVER)
        server = self._connect(instance)
        count = {
            AgentCheck.OK: 0,
            AgentCheck.CRITICAL: 0,
            AgentCheck.UNKNOWN: 0
        }

        # Report service checks and uptime for each process
        proc_names = instance.get('proc_names')
        if proc_names and len(proc_names):
            processes = [server.supervisor.getProcessInfo(p) for p in proc_names]
        else:
            processes = server.supervisor.getAllProcessInfo()

        for proc in processes:
            proc_name = proc['name']
            tags = ['supervisord',
                    'server:%s' % server_name,
                    'process:%s' % proc_name]

            # Report Service Check
            status = STATUS_MAP[proc['statename']]
            msg = self._build_message(proc)
            count[status] += 1
            self.service_check('supervisord.process.check',
                               status, tags=tags, message=msg)
            # Report Uptime
            uptime = self._extract_uptime(proc)
            self.gauge('supervisord.process.uptime', uptime, tags=tags)

        # Report counts by status
        tags = ['supervisord', 'server:%s' % server_name]
        self.gauge('supervisord.process.total', len(processes), tags=tags)
        self.gauge('supervisord.process.up', count[OK], tags=tags)
        self.gauge('supervisord.process.down', count[CRITICAL], tags=tags)
        self.gauge('supervisord.process.unknown', count[UNKNOWN], tags=tags)

    def _connect(self, instance):
        host = instance.get('host', DEFAULT_HOST)
        port = instance.get('port', DEFAULT_PORT)
        user = instance.get('user', None)
        password = instance.get('pass', None)
        auth = '%s:%s@' % (user, password) if user and password else ''
        return xmlrpclib.Server('http://%s%s:%s/RPC2' % (auth, host, port))

    def _extract_uptime(self, proc):
        desc = proc['description']
        if proc['statename'] == 'RUNNING' and 'uptime' in desc:
            h, m, s = desc.split('uptime ')[1].split(':')
            return int(s) + 60 * (int(m) + 60 * int(h))
        else:
            start, stop, now = int(proc['start']), int(proc['stop']), int(proc['now'])
            return 0 if stop >= start else now - start

    def _build_message(self, proc):
        start, stop, now = int(proc['start']), int(proc['stop']), int(proc['now'])
        proc['now_str'] = time_formatter(now)
        proc['start_str'] = time_formatter(start)
        proc['stop_str'] = '' if stop == 0 else time_formatter(stop)

        return """Current time: %(now_str)s
Process name: %(name)s
Process group: %(group)s
Description: %(description)s
Error log file: %(stderr_logfile)s
Stdout log file: %(stdout_logfile)s
Log file: %(logfile)s
State: %(statename)s
Start time: %(start_str)s
Stop time: %(stop_str)s
Exit Status: %(exitstatus)s""" % proc

@@ -211,26 +211,25 @@
 NKNOWN%0A%0A
+DD_
 STATUS
-_MAP
  = %7B%0A   
@@ -412,16 +412,97 @@
 NOWN%0A%7D%0A%0A
+PROCESS_STATUS = %7B%0A    CRITICAL: 'down',%0A    OK: 'up',%0A    UNKNOWN: 'unknown'%0A%7D%0A%0A
 TIME_FOR
@@ -1475,18 +1475,17 @@
 s = 
+DD_
 STATUS
-_MAP
 %5Bpro
@@ -1951,75 +1951,47 @@
     
-self.gauge('supervisord.process.total', len(processes), tags=tags)%0A
+for proc_status in PROCESS_STATUS:%0A    
     
@@ -2026,18 +2026,21 @@
 process.
-up
+count
 ', count
@@ -2044,174 +2044,100 @@
 unt%5B
-OK%5D, tags=tags)%0A        self.gauge('supervisord.process.down', count%5BCRITICAL%5D, tags=tags)%0A        self.gauge('supervisord.process.unknown', count%5BUNKNOWN%5D, tags=tags
+proc_status%5D,%0A                       tags=tags + %5B'status:%25s' %25 PROCESS_STATUS%5Bproc_status%5D%5D
 )%0A%0A 

Consolidate count metrics into one metric and make status a tag