###########################################################################
#
# This program is part of Zenoss Core, an open source monitoring platform.
# Copyright (C) 2008, Zenoss Inc.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published by
# the Free Software Foundation.
#
# For complete information please visit: http://www.zenoss.com/oss/
#
###########################################################################

# mappings of collector names (from the command line) to classes
COLLECTOR_NAMES = {'cpu' : 'CPUCollector',
                   'mem' : 'MemoryCollector',
                   'disk' : 'DiskCollector',
                   'intf' : 'InterfaceCollector'}

from zenoss.plugins.common import ApplicationError
from zenoss.plugins.common import Collector


class CPUCollector(Collector):
    '''Uses vmstat to report CPU information'''

    def __init__(self, *args, **kwargs):
        Collector.__init__(self, *args, **kwargs)

    def collect(self):
        '''reads the various states of the cpu and returns them'''
    
        import popen2
        stdout, stdin = popen2.popen4('vmstat')
        stdout.readline()
        stdout.readline()
        line = stdout.readline()
        vals = line.split()[-6:]
        
        self.map['deviceInterruptsPerSec'] = vals[0]
        self.map['systemCallsPerSec'] = vals[1]
        self.map['contextSwitchesPerSec'] = vals[2]
        self.map['user'] = vals[3]
        self.map['system'] = vals[4]
        self.map['idle'] = vals[5]


class MemoryCollector(Collector):
    '''Uses vmstat and pstat to read memory and swap information.'''

    def __init__(self, *args, **kwargs):
        Collector.__init__(self, *args, **kwargs)

    def collect(self):
        '''reads the memory information from both vmstat -a and /proc/meminfo
        and returns the values in a map'''
    

        # set the page size
        import resource
        self.map['pageSize'] = resource.getpagesize()
        
        # read the memory values
        import popen2
        stdout, stdin = popen2.popen4('vmstat')
        stdout.readline()
        stdout.readline()
        line = stdout.readline()
        vals = line.split()[3:]
        # these page values are reported in 1024 byte units
        # see man vmstat
        multiplier = 1024
        self.map['activeVirtual'] = int(vals[0]) * multiplier
        self.map['freeList'] = int(vals[1]) * multiplier
        
        self.map['pageFaultTotalCount'] = vals[2]
        self.map['pageFaultReclaimCount'] = vals[3]
        self.map['pageFaultAttachCount'] = vals[3]
        self.map['pageFaultInCount'] = vals[4]
        self.map['pageFaultOutCount'] = vals[5]
        self.map['pageFaultFreeCount'] = vals[6]
        self.map['pageFaultScanCount'] = vals[7]
        
        stdout, stdin = popen2.popen4('sysctl -n hw.physmem')
        self.map['memTotalReal'] = int(stdout.readline().strip())
        
        # and the swap values
        stdout, stdin = popen2.popen4('pstat -s')
        # jump the header
        stdout.readline()
        # and zip through all the swap partitions left
        swapsize = 0
        swapused = 0
        for line in stdout.readlines():
            values = line.split()
            swapsize = swapsize + int(values[1]) * 512
            swapused = swapused + int(values[2]) * 512
        self.map['memTotalSwap'] = swapsize
        self.map['memAvailSwap'] = swapsize - swapused


class DiskCollector(Collector):
    '''Uses df -k to read disk information.'''

    def __init__(self, *args, **kwargs):
        Collector.__init__(self, *args, **kwargs)

    def collect(self):
        '''reads the disk information for the mount provided'''
        if len(self.args) == 0:
            raise ApplicationError('No mount point defined')
        
        mount = self.args[0]

        import popen2
        stdout, stdin = popen2.popen4("df -i %s" % mount)
        lines = stdout.readlines()
        
        # mount was not located
        if len(lines) == 1:
            raise ApplicationError("Disk %s not found" % mount)

        # extract the used and available blocks
        line = lines[-1]
        vals = line.split()
        total, used, avail = vals[1:4]
        self.map['usedBlocks'] = used
        self.map['availBlocks'] = avail
        self.map['totalBlocks'] = total

        # extract the used and available inodes
        used, avail = vals[5:7]
        total = int(used) + int(avail)
        self.map['usedInodes'] = used
        self.map['availInodes'] = avail
        self.map['totalInodes'] = total



class InterfaceCollector(Collector):
    '''
    Collector that reads traffic information for a given interface
    '''

    def __init__(self, *args, **kwargs):
        Collector.__init__(self, *args, **kwargs)

    def collect(self):
        '''reads the network information using netstat -b'''
        if len(self.args) == 0:
            raise ApplicationError('No interface defined')

        iface = self.args[0].strip()

        import popen2
        # have to execute two netstat commands to get all the stuff we want
        # so we do it as close together as we can, then parse all the data later
        stdout, stdin = popen2.popen4("netstat -bn -I %s" % iface)
        bytes = stdout.readlines()
        stdout, stdin = popen2.popen4("netstat -n -I %s" % iface)
        packets = stdout.readlines()

        # parse up the bytes
        for line in bytes:
            values = line.split()
            if values[0] == iface:
                self.map['ifInOctets'] = values[4]
                self.map['ifOutOctets'] = values[5]
                break

        # parse up the packets and errors
        for line in packets:
            values = line.split()
            if values[0] == iface:
                self.map['ifInPackets'] = values[4]
                self.map['ifInErrors'] = values[5]
                self.map['ifOutPackets'] = values[6]
                self.map['ifOutErrors'] = values[7]
                break


