#!/usr/bin/env python
"""
Testing Monitor. 
This will be included in SimPyTest eventually.
__version__ = '$Revision: 1.1 $ $Date: 2004-05-19 20:22:05+02 $'
# 2004 05 03 corrected test for Monitored queues (gav)
"""
from __future__ import generators
from random import *
from SimPy.Simulation  import *
from SimPy.SimPlot import *
import unittest

## ------------------------------------------------------------
class Thing(Process):
   """ Thing process for testing Monitors in simulation"""
   def __init__(self,M=None,name="Thing"):
        Process.__init__(self)
        self.name=name
        self.y = 0.0
        self.M = M

   def execute(self):       
        DEBUG = 0
        self.y = 0.0
        if DEBUG: print self.name,now(),self.y
        self.M.observe(self.y)

        yield hold,self,10.0
        self.y = 10
        if DEBUG: print self.name,now(),self.y
        self.M.observe(self.y)

        yield hold,self,10.0
        self.y = 5
        if DEBUG: print self.name,now(),self.y
        self.M.observe(self.y)
       
## ------------------------------------------------------------

class makeMtestCase(unittest.TestCase):
    """ Test Monitor
    """
        
    def setUp(self):
        self.M = Monitor(name='First')
        for i in range(10):
            self.M.observe(2*i,i)
        self.T = Monitor(name='tallier')

    def testObserve(self):
        """Test Monitor - observe"""
        m = self.M
        #for i in m.series():
        #   print i
        assert m == [[i, 2*i] for i in range(10)],'series wrong'
        assert m.name == 'First','name wrong'
        assert m.tseries() == list(range(10)),'tseries wrong:%s'%(m.tseries(),)
        assert m.yseries() == [2*i for i in range(10)],'yseries wrong:%s'%(m.yseries(),)
        assert m.total() == 90, 'total wrong:%s'%m.total()
        assert m.mean() == 9.0,'mean wrong:%s'%m.mean()
        assert m.var() == (4*285.-(90*90/10.0))/10.0,'sample var wrong:%s'%(m.var(),)

    def testObserveNoTime(self):
        """Test Monitor - observe with time being picked up from now()"""
        m = Monitor(name='No time')
        initialize()
        t = Thing(m)
        activate(t,t.execute(),0.0)
        simulate(until=20.0)
        assert m.yseries() == [0,10,5],'yseries wrong:%s'%(m.yseries(),)
        assert m.tseries() == [0,10,20],'tseries wrong:%s'%(m.tseries(),)
        assert m.total() == 15, 'total wrong:%s'%m.total()
        assert m.timeAverage(10.0) == 5.0 ,'time average is wrong:%s'%m.timeAverage(10.0)
 
    def testObserveTally(self):
        """Test Monitor - observe without time values"""
        m = self.T
        for i in range(10):
           m.tally(2*i)
        assert m == [[0, 2*i] for i in range(10)],'series wrong'
        assert m.total() == 90, 'total wrong:%s'%m.total()
        assert m.mean() == 9.0,'mean wrong:%s'%m.mean()
        assert m.var() == (4*285.-(90*90/10.0))/10.0,'sample var wrong:%s'%(m.var(),)

    def testtimeAverage(self):
       """ test time averages """
       m = self.M
       assert m == [[i,2*i] for i in range(10)],'series wrong'
       assert m.timeAverage(10.0) == 9.0 ,'time average is wrong:%s'%m.timeAverage(10.0)
    

    def testreset(self):
       """ test time averages """
       m=self.M
       m.reset(t = 10.0)
       assert m.startTime == 10.0,'reset time  wrong'
       assert m == [],'reset series wrong:%s'%(m,)


    def testTally(self):
        """Test Monitor - tally"""
        m = Monitor(name='First')
        S = []
        for i in range(10):
            m.tally(i)
            S.append([0,i])
        assert m == S,'Stored series is wrong: %s'%(m,)
        assert m.name == 'First','Tally name wrong'
        assert m.total() == 45,'Tally total wrong'
        assert m.mean() == 4.5,'Tally mean wrong'
        assert m.var()  == (285-(45*45/10.0))/10.0,'Tally sample var wrong%s'%(m.var(),)
        

    def testAccumulate(self):
        """Test Monitor - accumulate"""
        #print 'Monitor version '+__version__
        m2 = Monitor(name='Second')
        assert m2.startTime == 0,'accum startTime wrong'
        for i in range(5):
            m2.accum(10,i)  # this is (y,t)
        # print 'debug', m2.data
        assert m2.total() == 50,'accum total wrong:%s'%(m2.total(),)
        assert m2.startTime == 0,'accum startTime wrong'
        assert m2.timeAverage(5.0) == 10.0,'accum timeAverage wrong:%s'%(m2.timeAverage(10.0),)
        ## test reset
        m2.reset(10)
        assert m2 == [],'accum reset list wrong:%s'%(m2,)
        assert m2.total() == 0.0,'accum reset total wrong'
        assert m2.startTime == 10,'accum startTime wrong'

    def testAccumulateInTime(self):
        """Test Monitor - accumulate over simulation time"""
        #print 'Monitor version '+__version__
        initialize()
        m3 = Monitor(name='third')
        T3 = Thing(name="Job",M=m3)
        assert m3.startTime == 0,'Accumulate startTime wrong'
        activate(T3,T3.execute(),0.0)
        simulate(until=30.0)
        assert m3.startTime == 0,'Accumulate startTime wrong'

    def testListStuff(self):
       """Test some Monitor list operations"""
       shouldBe=[[i,2*i] for i in range(10)]
       assert shouldBe == self.M, 'M list is wrong'
       assert [2,4] == self.M[2], 'indexing wrong:%s'%(self.M[2],)
       self.M[0] = [10,10]
       assert [10,10] == self.M[0], 'item replacement wrong:%s'%(self.M[0],)
       self.M.reverse()
       assert [10,10] == self.M[-1], 'list reverse wrong:%s'%(self.M[-1],)
       self.M.sort()
       assert [1,2] == self.M[0], 'list sort wrong:%s'%(self.M[0],)
       assert 10 == len(self.M), 'list length wrong'
       assert [2,4] in self.M, 'item in list wrong'
       
       
    def testhistogram(self):
       """Test some Monitor list operations"""
       m = Monitor(name='First')      
       for y in [-5, 0, 5, 15,99,105,120]:m.observe(y)
       h = m.histogram(low=0.0,high=100.0,nbins=10)
       shouldBe = list(zip(*h)[1])
       assert shouldBe == [1,2,1,0,0,0,0,0,0,0,1,2], 'm histogram is wrong: %s'%(shouldBe,)

def makeMSuite():
    suite = unittest.TestSuite()
    testObserve = makeMtestCase("testObserve")
    testObserveNoTime = makeMtestCase("testObserveNoTime")
    testObserveTally = makeMtestCase("testObserveTally")
    testtimeAverage = makeMtestCase("testtimeAverage")
    testreset = makeMtestCase("testreset")
    testTally = makeMtestCase("testTally")
    testAccumulate = makeMtestCase("testAccumulate")
    testAccumulateInTime = makeMtestCase("testAccumulateInTime")
    testListStuff = makeMtestCase("testListStuff")
    testhistogram = makeMtestCase("testhistogram")
    suite.addTests([testObserve,testObserveNoTime,
                    testObserveTally,
                    testtimeAverage,testreset,
                    testTally,testAccumulate,
                    testAccumulateInTime,
                    testListStuff,
                    testhistogram,
                    ]) 
    return suite

## -----------------------------------------------------------------------
class makeHtestCase(unittest.TestCase):
    """ Test Histogram"""
        
    def setUp(self):
        self.H = Histogram(name='First Test',low=0.0,high=100.0,nbins=10)
        #print 'setup ',self.H
       
    def testHistogram(self):
        """Test Histogram"""
        h = self.H
        #print 'h = :',h
        assert h.name == 'First Test', 'wrong histogram name: %s'%h.name
        #print h.nbins,h.binsize, h
        assert h[0]  == [h.low-h.binsize,0], 'wrong init of under bin: %s'%h
        i=h.nbins+1
        assert h[-1] == [h.low+(i-1)*h.binsize,0], 'wrong init of over bin: %s'%h
 
    def testaddIn(self):
        """Test addIn"""
        h=self.H
        for y in [-5, 0, 5, 15,99,105,120]:
            h.addIn(y)
        assert h[0][1]  == 1, 'wrong value for under: %s'%h[0]
        assert h[1][1]  == 2, 'wrong value for 1 (low): %s'%h[1]
        assert h[2][1]  == 1, 'wrong value for 2 (low + 1)%s'%h[1]
        assert h[10][1] == 1, 'wrong value for 10 (high): %s'%h[10]
        assert h[11][1] == 2, 'wrong value for 11 (over): %s'%h[11]

    def testPlot(self):
        """Test plot histogram"""
        h=self.H
        for y in [-5, 0, 5, 15,15,15,15,15,15,15,15,15,15,99,105,120]:
            h.addIn(y)
        h2=Histogram(name='long test',low=0, high=100,nbins=100)
        seed =1133557799
        g = Random(seed)
        for i in range(1000):
            h2.addIn(g.expovariate(1.0/33))
   

        plt=SimPlot()
        plt.plotStep(h,
             title='Basic step plot',
                     color='green',width=3,
                     xaxis='minimal',
                     yaxis='minimal')
        plt.plotStep(h2,
                     color='blue',
                     #xaxis='minimal',
                     yaxis='minimal')
        plt.mainloop()


def makeHSuite():
    suite = unittest.TestSuite()
    testHistogram = makeHtestCase("testHistogram")
    testaddIn = makeHtestCase("testaddIn")
    testPlot = makeHtestCase("testPlot")
    suite.addTests([testHistogram,
                    testPlot,
                    testaddIn,
                    ]) 
    return suite

if __name__ == '__main__':
    alltests = unittest.TestSuite((makeMSuite(),
                                   makeHSuite(),
                                   #makeIntegraterSuite(),
                                   ))
    runner = unittest.TextTestRunner()
    runner.run(alltests)
