#!/usr/bin/env python
"""
Check the status of some component.
"""
__rcsid__ = "$Id$"
__author__ = "Dan Gunter <dkgunter@lbl.gov>"

## Imports

import re
import sys
from netlogger import nlstatus
from netlogger.nllog import OptionParser, get_logger

## Constants

## Classes

class OP(OptionParser):
    """Override print_help in order to print commands """
    def print_help(self, file=None):
        if file is None: file = sys.stderr
        OptionParser.print_help(self, file)
        self._print_commands(file)

    def _print_commands(self, f):
        indent = "    "
        f.write("\nCommands\n--------\n")
        commands = Commands()
        names = sorted(commands.getNames())
        for name in names:
            info = commands.getInfo(name)
            argstr = ' '.join(['{%s}' % x[0] for x in info.args])
            f.write("* %s %s\n" % (info.name, argstr))
            for name, desc in info.args:
                f.write("%s%s - %s\n" % (indent, name, desc))

class CommandInfo:
    def __init__(self, name):
        self.name = name
        self.func, self.desc, self.args = None, None, [ ]

class Commands:
    """Every function in this class that starts with PREFIX
    implements a status check of a given component,
    and returns an nlstatus.Status result.

    The documentation string of these functions is parsed for the
    help message, so should follow the same format (note the '.'):
      Description (may span multiple lines).
      -- arg1 : arg1 description.
       >> etc. <<
      -- argN : argN description.
    """
    PREFIX = "cmd_"

    def getInfo(self, name):
        """Get information about command 'name'.

        Returns a CommandInfo object, or None if not found
        """
        if not hasattr(self, self.PREFIX + name):
            return None
        info = CommandInfo(name)
        info.func = getattr(self, self.PREFIX + name)
        doclines = info.func.__doc__.split()
        doc = ' '.join([x.strip() for x in doclines])
        # parse out initial docstring.
        info.desc = re.match("(.*?)\.", doc).groups()[0]
        # parse out arguments
        for arg in re.findall("(--.*?\.)", doc):
            name, desc = re.match("-- (\w+)\s*:\s*(.*?)\.", arg).groups()
            info.args.append((name, desc))
        return info

    def getNames(self):
        """Get list of all command names (without the prefix).
        """
        result = [ ]
        for key in dir(self):
            if key.startswith(self.PREFIX):
                result.append(key[len(self.PREFIX):])
        return result

    def cmd_syslogng(self, filename, date):
        """Check that the last event in a syslog-ng log file
        is on or after the given date.
        -- filename : Log file to examine.
        -- date : Cutoff date.
        """
        checker = nlstatus.Syslogng(log_file=filename, since=date)
        return checker.check()

    def cmd_rawlogs(self, directory, pattern, date):
        """Check that the modification time of all log files
        is on or after the given date.
        -- directory : File directory.
        -- pattern : Glob pattern that tells which files to check.
        -- date : Cutoff date.
        """
        checker = nlstatus.Rawlogs(log_dir=directory, log_pat=pattern,
                                   since=date)
        return checker.check()

## Functions

def main():
    # Parse arguments
    usage = "%prog command [args..]"
    desc = ' '.join(__doc__.split())
    p = OP(usage=usage, description=desc)
    options, args = p.parse_args()
    log = get_logger(__file__)  # Should be first done, just after parsing args
    # Check arguments
    if len(args) < 1:
        p.error("No command given")
    cmd_name = args[0]
    commands = Commands()
    info = commands.getInfo(cmd_name)
    if info is None:
        p.error("Unknown command, '%s'" % cmd_name)
    cmd_args = args[1:]
    if len(cmd_args) != len(info.args):
        p.error("Not enough arguments for command '%s'" % cmd_name)
    # Run command
    try:
        status = info.func(*cmd_args)
    except Exception, E:
        status = nlstatus.Abort(E)
    print status.nagiosString()

if __name__ == '__main__':
    sys.exit(main())
