#!/usr/bin/env python2.3

import gzip
import math
import sys
import time

if sys.version_info[:2] < (2,2):
    print "I need Python 2.2 or later.  (Python 2.3 is much faster)"
    sys.exit(1)

def gzopen(fn):
    if fn.endswith(".gz"):
        return gzip.open(fn, 'r')
    else:
        return open(fn, 'r')

def getNext(f):
    if hasattr(f, 'xreadlines'):
        return iter(f.xreadlines()).next
    else:
        return f.readline

class Params:
    def __hash__(self):
        return hash(self.p)
    def __cmp__(self,o):
        return cmp(self.p,o.p)
class SDParams(Params):
    def __init__(self,**test):
        self.p = (test['b'],test['N'],test['m'])
    def disp(self):
        b,N,m=self.p
        return "b:%4d  N:%7d  m:%4d" %(b,N,m)
    def getM(self):
        return self.p[2]
    def getPMsg(self):
        return 1.0

class UnkBGParams(Params):
    STRATEGIES = {"uniform-geometric":"UU",
                  "smallworld-geometric":"BU",
                  "smallworld-geometric-weighted":"BB"}
    def __init__(self,**test):
        self.p = (test['b'],test['N'],test['m'],int(test['pMessage']*100),
                  self.STRATEGIES[test['aliceStrategy']])
    def disp(self):
        b,N,m,pM,strat=self.p
        return "b:%4d N:%7d m:%4d pM:%2s%% S:%3s"%(b,N,m,pM,strat)
    def getM(self):
        return self.p[2]
    def getPMsg(self):
        return self.p[3]/100.0

class MixTrialParams(Params):
    def __init__(self,**test):
        self.p = (test['N'],
                  test['m'],
                  test['l'],
                  int(test['pMessage']*100),
                  int(test['pDummy']*100),
                  int(test['pDelay']*100),
                  test['bgVolume'],
                  test.get('padding'),
                  int(test['pOnline']*100),
                  int(test['pObserve']*100),
                  test.get('smoothPadding',0))
    def disp(self):
        N,m,l,pA,pJ,pD,bgV,pad,pOn,pO,smooth=self.p
        return ("N:%5d m:%3d l:%1d pA:%2s%% pJ:%2s%% pD:%2s%% bg:%5d pl:%d sm:%d pOn:%d%% pOb:%2d%%"
                %(N,m,l,pA,pJ,pD,bgV,pad,smooth,pOn,pO))
    def getM(self):
        return self.p[1]
    def getPMsg(self):
        return self.p[3]/100.0

class NymTrialParams(Params):
    def __init__(self,**test):
        self.p = (test['N'],
                  test['l'],
                  int(test['pA']*100),
                  int(test['pD']*100),
                  test['bgVol'],
                  int(test['pObs']*100))
    def disp(self):
        N,l,pA,pD,bgV,pO=self.p
        return ("N:%5d l:%1d pA:%2s%% pD:%2s%% bg:%5d pOb:%2d%%"
                %(N,l,pA,pD,bgV,pO))
    def getM(self):
        return 1
    def getPMsg(self):
        return self.p[2]/100.0

def kwdict(**kw): return kw
def pct(x):
    return int(x*100)

class RecipientDistribution:
    MAXIMUM = 1e10 #off the scale
    def __init__(self, M):
        self.M=M
        self.items = 0
        self.lst = [[], #1st
                    [], #1/2,
                    [], #3/4
                    [], #7/8
                    [], #15/16
                    [], #all-but-1
                    [], #all.
                    ]
        self.positions = [ (0, 1),
                           (1, M//2),
                           (2, (M*3)//4),
                           (3, (M*7)//8),
                           (4, (M*15)//16),
                           (5, M-1),
                           (6, M) ]
        self.nGuessedAtRoundN = {}
    def addResult(self,res):
        got=len(res)-1
        self.items += 1
        lastidx=0
        for idx, pos in self.positions:
            if got>=pos:
                self.lst[idx].append(res[pos])
                lastidx = idx
        for idx in xrange(lastidx+1, len(self.positions)):
            self.lst[idx].append(self.MAXIMUM)
        for r in res[1:]:
            try:
                self.nGuessedAtRoundN[r] += 1
            except KeyError:
                self.nGuessedAtRoundN[r] = 1
    def getPercentile(self,pctile):
        r = []
        p = int(math.ceil(self.items * (pctile/100.0)))
        for l in self.lst:
            l.sort()
            if p < len(l):
                r.append(l[p])
            else:
                r.append(self.MAXIMUM)
        return r

class ResultSet:
    SCOPE = { 'MixTrial' : MixTrialParams,
              'UnkBGBatchTrial' : UnkBGParams,
              'SDTrial' : SDParams,
              'NymTrial' : NymTrialParams,
              'Result' : kwdict }
    def __init__(self):
        self.nTrials = {}
        self.nSuccess = {}
        self.nSent = {}
        self.nRounds = {}
        self.nRoundsAlice = {}
        self.nGuessed = {}
        self.nRoundsToGuessN = {}

    def readFile(self,fn):
        f = gzopen(fn)
        next = getNext(f)

        scope = self.SCOPE

        nTrials = self.nTrials
        nSuccess = self.nSuccess
        nSent = self.nSent
        nRounds = self.nRounds
        nRoundsAlice = self.nRoundsAlice
        nGuessed = self.nGuessed
        nRoundsToGuessN = self.nRoundsToGuessN
        xth = 0
        try:
            while 1:
                xth += 1
                testline = next() #UnkBGBatchTrial(...)
                next() # "x/100"
                resultline = next() # Result(...)
                if resultline.startswith("bgAlice"):
                    resultline = next()
                if resultline.startswith("Got only"):
                    resultline = next()
                next() # empty
                if not (testline and resultline): break
                if not resultline.startswith("Result"):
                    print xth,"Bad result line:",resultline
                testline = testline.replace("smoothPadding0",
                                            "smoothPadding=0")
                testline = testline.replace("smoothPadding1",
                                            "smoothPadding=1")
                testline = testline.replace("pading", "padding")
                params = eval(testline, scope)
                result = eval(resultline, scope)
                try:
                    nTrials[params]+=1
                except KeyError:
                    nTrials[params]=1
                    nSuccess[params]=0
                    nSent[params]=0
                    nRounds[params]=0
                    nRoundsAlice[params]=0
                    nGuessed[params]=0
                    nRoundsToGuessN[params] = \
                        RecipientDistribution(params.getM())
                if result['succeeded']:
                    nSuccess[params] += 1
                    nRounds[params] += result['rounds']
                    nRoundsAlice[params] += result['roundsWithAlice']
                    nSent[params] += result['msgsFromAlice']
                nGuessed[params] += len(result['nRoundsToGuessNth'])-1
                nRoundsToGuessN[params].addResult(result['nRoundsToGuessNth'])
                #i += 1
                #if not (i % 100):
                #    print i, (time.time()-start)/i
        except StopIteration:
            pass
        except SyntaxError:
            print xth

    def display(self):
        params = self.nTrials.keys()
        params.sort()
        for p in params:
            nT = self.nTrials[p]
            fT = float(nT)
            pS = self.nSuccess[p]/fT
            if self.nSuccess[p]:
                avgR = self.nRounds[p]/float(self.nSuccess[p])
                avgRA = self.nRoundsAlice[p]/float(self.nSuccess[p])
                avgSent = self.nSent[p]/float(self.nSuccess[p])
            else:
                avgR = 5000000
                avgRA = (5000000*p.getPMsg())//100
                avgSent = 5000000

            pG = self.nGuessed[p]/(fT*p.getM())
            dp = p.disp()

            nrtgn = self.nRoundsToGuessN[p]

            print ("%s | N:%3d succ:%3s%% guess:%3s%% rnds:%7d rndsA:%7s sentA:%5d"
                   %(dp, nT, int(pS*100), int(pG*100), avgR, avgRA,avgSent)),

            N_NAMES=7
            names = ["1st","1_2","3_4", "7_8", None, "but1", "all"]
            for percentile in 50,80,90,95:
                pct = nrtgn.getPercentile(percentile)
                for idx in xrange(N_NAMES):
                    name=names[idx]
                    val=pct[idx]
                    if not name: continue
                    print ("p%s_%s:%s" % (percentile, name, val)),
            print

if __name__ == '__main__':
    rs = ResultSet()
    for fn in sys.argv[1:]:
        rs.readFile(fn)
    rs.display()

