# General simulation classes defined here, should be usable by any arcology simulation
#

import string
from SimPy.Simulation import *
from random import *
from elementtree.ElementTree import Element, SubElement


global cuid     # Cell unique identifier, to correspond to the node number used by graphviz
cuid = 0
global h2ts     # multiplier to convert simulation time units to hours
h2ts = 60       # currently using minutes as sim time unit

class Cell:
    "Core entity with a unique id 'uid', a list of subcells 'sc', and a ref to parent cell 'p' "
    def __init__(self,parent):
        "Generate a global id and remember who our parent is"
        global cuid
        self.uid = cuid
        cuid = cuid+1   # increment the global unique ID every time a Cell is created
        self.sc = []        # container for subcells
        self.p = parent # remember our parent
    def className(self):
        "Return text indicating name of inherited class"
        # trim out CLASSNAME from expected '<Instance of CLASSNAME at ... >' text
        # also append the UID number
        return string.rstrip(string.split(str(self))[2],',') +str(self.uid)
    def xmlify(self):
        """Return an ElementTree.Element containing itself and all of its children.
        element text will be its Class name"""
        tree = Element(self)
        tree.text = str(self)
        for n in self.sc:
            tree.append(n.xmlify())
        return tree
    def printtree(self, level=0):
        "Print our class name and the names of children"
        text = str(self) + '\n'
        padding = ''
        for s in range(level):
            padding += '_'
        for n in self.sc:
            text += padding + n.printtree(level+1)
        return text
    def relocate(self, newcell):
        "Relocate from one cell to newcell, updating all records for parent cell, newcell, and self.parent"
        self.p.sc.remove(self)   # remove self from parent's subcell list.  We're now in limbo!
        newcell.sc.append(self) # add self to new cell
        self.p = newcell   # record new parent cell

class ResidenceCell(Cell):
    "Represents a residential house"
    def __init__(self,parent):
        Cell.__init__(self,parent)
        # Set up some resources for consumption / waste processing
        self.resource = {
            'water' : 0,
            'wastewater' : 0,
            'electricity' : 0
            }          
            

class Individual(Process,Cell):
    "Person"
    def __init__(self,parent):
        Process.__init__(self)
        Cell.__init__(self,parent)
        self.name=self.className()
        ##l self.sc # Individuals are leaf cells because, well, they can't be divided into anything smaller
        self.residence = []
    def getAHome(self,cell):     # create a home in specified Cell cell
        """Create a home"""
        newres = ResidenceCell(cell)
        cell.sc.append(newres)  # add the residence to the cell
        newres.sc.append(self)  # add ourselves to the residence
        self.p = newres     # make the residence our parent node
        self.residence.append(newres)   # remember where we live on a stack (so we can have temporary homes-away-from-home)
    def sleep(self):
        """sleep, perchance to dream"""
        bedtime = now()
        print "%7.4f %s : Going to sleep"%(now(),self.name)
        global h2ts
        yield hold,self,normalvariate(8*h2ts,1*h2ts)  # sleep for about 8 hours on average
        print "%7.4f %s : woke up"%(now(),self.name)
        t = now() - bedtime
        Mon.observe(t)
    
Mon = Monitor('sleeping time')


class ReactionEngine(Process):
    "Handles transaction events of resources & waste"
    def __init__(self,cell):
        Process.__init__(self)
        

class TransactionEngine(Process):
    "Handle interachange of resources / waste between cells"
    def __init__(self,src,dest):
        Process.__init__(self)