#! /usr/bin/env python
###############################################################################
#                                                                             #
#   Copyright 2005 University of Cambridge Computer Laboratory.               #
#                                                                             #
#   This file is part of Nprobe.                                              #
#                                                                             #
#   Nprobe is free software; you can redistribute it and/or modify            #
#   it under the terms of the GNU General Public License as published by      #
#   the Free Software Foundation; either version 2 of the License, or         #
#   (at your option) any later version.                                       #
#                                                                             #
#   Nprobe is distributed in the hope that it will be useful,                 #
#   but WITHOUT ANY WARRANTY; without even the implied warranty of            #
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             #
#   GNU General Public License for more details.                              #
#                                                                             #
#   You should have received a copy of the GNU General Public License         #
#   along with Nprobe; if not, write to the Free Software                     #
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA #
#                                                                             #
###############################################################################


import re
import types
import commands
from nprobe import _inet_aton


##############################################################################
## 
## Generic stats collector for np analysis
## - subtype specific stats collectors for particular log analysis tasks
## 
##############################################################################

class NoIPAddrError:

    #
    # Exception raised by get_IPaddr method if no addr found
    #


    def __init__(self, val):
        self.val = val

    def __str__(self):
        return self.val

#######################################################################
#######################################################################


class StatsCollector:

    def __init__(self, args, quiet=0, trace=0, logpath=None):

        self.trace = trace
        self.quiet=quiet
        self.obdict = {}
        self.logpath = logpath
        self.log = []
        self.loglen = 0
        self.logtot = 0
        if not logpath:
            self.open_log = self.close_log = self.write_log = self.save_log \
                            = self.nullf
        else:
            if quiet:
                self.open_log()
            else:
                self.write_log = self.log.append
        self.basepath = None
        self.basedir = None

        self.init_log(args)
    
#######################################################################

    def init_log(self, args):
        
        cmd = 'whoami'
	status, me = commands.getstatusoutput(cmd)
        cmd = 'hostname'
	status, host = commands.getstatusoutput(cmd)
        cmd = 'date'
	status, date = commands.getstatusoutput(cmd)

        str = 'Run by %s on %s %s     ' % (me, host, date)
        self.write_log(str)
        str = 'Invoked %s     ' % (args)
        self.write_log(str)
    
#######################################################################

    def open_log(self):

        try:
            self.logf = open(self.logpath, 'w')
        except:
            print 'Can\'t open logfile', self.logpath
            raise

        self.write_log('Log saved to %s' % (self.logpath))
        
    
#######################################################################

    def close_log(self):
        
        ss = 'Log size %.2fM' % (self.logtot/1000000.0)
        print ss
        self.logf.write(ss + '\n')

        try:
            self.logf.close()
        except:
            print 'Can\'t close logfile', self.logpath
            raise

        
        
    
#######################################################################

    def write_log(self, s):

        self.log.append(s)
        self.loglen += len(s)
        if self.loglen > 524288:
            self.dump_log()
        
    
#######################################################################

    def dump_log(self):
        
        lw = self.logf.write
        log = self.log

        for s in log:
            lw(s+'\n')

        self.logtot += self.loglen
        self.log = []
        self.loglen = 0
        self.logf.flush()
    
#######################################################################
        
    def save_log(self):

        self.open_log()
        
        lw = self.logf.write
        log = self.log

        for s in log:
            lw(s+'\n')
            self.logtot += len(s) + 1

        self.close_log()
        
#######################################################################

    def get_per(self, s):

        #
        # get value of string embedded integer
        #

        digs = ''
        for c in s:
            if c.isdigit():
                digs += c

        return int(digs)
        
    
#######################################################################

    def nullf(self, *args):

        #
        # sink something
        #


        return
        
    
#######################################################################


    #
    # Return rank siffix for i (ie 1st, 2nd, etc)
    #

    def rank_str(self, i):
        
##         if i == 0:
##             return ' 1st'
##         elif i == 1:
##             return ' 2nd'
##         elif i == 2:
##             return ' 3rd'
##         elif i == 9:
##             return '10th'
##         else:
##             return ' %dth' % (i+1)
        if 10 <= i <= 19:
            return ' %dth' % (i+1)
        elif i % 10  == 0:
            return ' %dst' % (i+1)
        elif i % 10 == 1:
            return ' %dnd' % (i+1)
        elif i % 10 == 2:
            return ' %drd' % (i+1)
        else:
            return ' %dth' % (i+1)

#######################################################################
#######################################################################

#
# Utility functions
#



#
# Return list of NBO IP addrs for any embedded dd addresses
#

def get_IPaddrs(s):

    l = []
    RE = re.compile('(\d+\.){3}\d+')
    it = RE.finditer(s)
    while 1:
        try:
            r = it.next()
        except StopIteration:
            break
        if r:
            l.append(r.group())

    if not l:
        raise NoIPAddrError, s

    addrs = []
    for dd in l:
        a = _inet_aton(dd)
        if not a:
            raise NoIPAddrError, s
        addrs.append(a)

    return addrs

#
# Return conn_ids for server/client pair
#

def sc_connids(cid, sid, obdict):

    sconns = obdict['sdict'][sid]
    cconns = obdict['cdict'][cid]

    cl = []
    add = cl.append
    i = 0
    for c in sconns:
        try:
            while cconns[i] < c:
                i += 1
        except IndexError:
            break
        if cconns[i] == c:
            add(c)



        
