def Debug( msg ):
        print msg

DIRECTION_UP = 0
DIRECTION_DOWN = 1
DIRECTION_LEFT = 2
DIRECTION_RIGHT = 3

class Event:
        """this is a superclass for any events that might be generated by an
        object and sent to the EventManager"""
        def __init__(self):
                self.name = "Generic Event"

class TickEvent(Event):
        def __init__(self):
                self.name = "CPU Tick Event"

class QuitEvent(Event):
        def __init__(self):
                self.name = "Program Quit Event"

class MapBuiltEvent(Event):
        def __init__(self, gameMap):
                self.name = "Map Finished Building Event"
                self.map = gameMap

class GameStartedEvent(Event):
        def __init__(self, game):
                self.name = "Game Started Event"
                self.game = game

class CharactorMoveRequest(Event):
        def __init__(self, direction):
                self.name = "Charactor Move Request"
                self.direction = direction

class CharactorPlaceEvent(Event):
        """this event occurs when a Charactor is *placed* in a sector,
        ie it doesn't move there from an adjacent sector."""
        def __init__(self, charactor):
                self.name = "Charactor Placement Event"
                self.charactor = charactor

class CharactorMoveEvent(Event):
        def __init__(self, charactor):
                self.name = "Charactor Move Event"
                self.charactor = charactor

#------------------------------------------------------------------------------
class EventManager:
        """this object is responsible for coordinating most communication
        between the Model, View, and Controller."""
        def __init__(self ):
                from weakref import WeakKeyDictionary
                self.listeners = WeakKeyDictionary()
                self.eventQueue= []

        #----------------------------------------------------------------------
        def RegisterListener( self, listener ):
                self.listeners[ listener ] = 1

        #----------------------------------------------------------------------
        def UnregisterListener( self, listener ):
                if listener in self.listeners:
                        del self.listeners[ listener ]
                
        #----------------------------------------------------------------------
        def Post( self, event ):
                if not isinstance(event, TickEvent):
                        Debug( "     Message: " + event.name )
                for listener in self.listeners:
                        #NOTE: If the weakref has died, it will be
                        #automatically removed, so we don't have
                        #to worry about it.
                        listener.Notify( event )

#------------------------------------------------------------------------------
class KeyboardController:
        """..."""
        def __init__(self, evManager):
                self.evManager = evManager
                self.evManager.RegisterListener( self )

        #----------------------------------------------------------------------
        def Notify(self, event):
                if isinstance( event, TickEvent ):
                        #Handle Input Events
                        for event in pygame.event.get():
                                ev = None
                                if event.type == QUIT:
                                        ev = QuitEvent()
                                elif event.type == KEYDOWN \
                                     and event.key == K_ESCAPE:
                                        ev = QuitEvent()
                                elif event.type == KEYDOWN \
                                     and event.key == K_UP:
                                        direction = DIRECTION_UP
                                        ev = CharactorMoveRequest(direction)
                                elif event.type == KEYDOWN \
                                     and event.key == K_DOWN:
                                        direction = DIRECTION_DOWN
                                        ev = CharactorMoveRequest(direction)
                                elif event.type == KEYDOWN \
                                     and event.key == K_LEFT:
                                        direction = DIRECTION_LEFT
                                        ev = CharactorMoveRequest(direction)
                                elif event.type == KEYDOWN \
                                     and event.key == K_RIGHT:
                                        direction = DIRECTION_RIGHT
                                        ev = CharactorMoveRequest(direction)

                                if ev:
                                        self.evManager.Post( ev )


#------------------------------------------------------------------------------
class CPUSpinnerController:
        """..."""
        def __init__(self, evManager):
                self.evManager = evManager
                self.evManager.RegisterListener( self )

                self.keepGoing = 1

        #----------------------------------------------------------------------
        def Run(self):
                while self.keepGoing:
                        event = TickEvent()
                        self.evManager.Post( event )

        #----------------------------------------------------------------------
        def Notify(self, event):
                if isinstance( event, QuitEvent ):
                        #this will stop the while loop from running
                        self.keepGoing = False


import pygame
from pygame.locals import *
#------------------------------------------------------------------------------
class SectorSprite(pygame.sprite.Sprite):
        def __init__(self, sector, group=None):
                pygame.sprite.Sprite.__init__(self, group)
                self.image = pygame.Surface( (128,128) )
                self.image.fill( (0,255,128) )

                self.sector = sector

#------------------------------------------------------------------------------
class CharactorSprite(pygame.sprite.Sprite):
        def __init__(self, group=None):
                pygame.sprite.Sprite.__init__(self, group)

                charactorSurf = pygame.Surface( (64,64) )
                pygame.draw.circle( charactorSurf, (255,0,0), (32,32), 32 )
                self.image = charactorSurf
                self.rect  = charactorSurf.get_rect()

                self.moveTo = None

        #----------------------------------------------------------------------
        def update(self):
                if self.moveTo:
                        self.rect.center = self.moveTo
                        self.moveTo = None

#------------------------------------------------------------------------------
class PygameView:
        """..."""
        def __init__(self, evManager):
                self.evManager = evManager
                self.evManager.RegisterListener( self )

                pygame.init()
                self.window = pygame.display.set_mode( (424,440) )
                pygame.display.set_caption( 'Example Game' )
                self.background = pygame.Surface( self.window.get_size() )
                self.background.fill( (0,0,0) )

                self.backSprites = pygame.sprite.RenderUpdates()
                self.frontSprites = pygame.sprite.RenderUpdates()


        #----------------------------------------------------------------------
        def ShowMap(self, gameMap):
                squareRect = pygame.Rect( (-128,10, 128,128 ) )

                i = 0
                for sector in gameMap.sectors:
                        if i < 3:
                                squareRect = squareRect.move( 138,0 )
                        else:
                                i = 0
                                squareRect = squareRect.move( -(138*2), 138 )
                        i += 1
                        newSprite = SectorSprite( sector, self.backSprites )
                        newSprite.rect = squareRect
                        newSprite = None

        #----------------------------------------------------------------------
        def ShowCharactor(self, charactor):
                charactorSprite = CharactorSprite( self.frontSprites )

                sector = charactor.sector
                sectorSprite = self.GetSectorSprite( sector )
                charactorSprite.rect.center = sectorSprite.rect.center

        #----------------------------------------------------------------------
        def MoveCharactor(self, charactor):
                charactorSprite = self.GetCharactorSprite( charactor )

                sector = charactor.sector
                sectorSprite = self.GetSectorSprite( sector )

                charactorSprite.moveTo = sectorSprite.rect.center

        #----------------------------------------------------------------------
        def GetCharactorSprite(self, charactor):
                #there will be only one
                for s in self.frontSprites:
                        return s

        #----------------------------------------------------------------------
        def GetSectorSprite(self, sector):
                for s in self.backSprites:
                        if hasattr(s, "sector") and s.sector == sector:
                                return s


        #----------------------------------------------------------------------
        def Notify(self, event):
                if isinstance( event, TickEvent ):
                        #Draw Everything
                        self.backSprites.clear( self.window, self.background )
                        self.frontSprites.clear( self.window, self.background )

                        self.backSprites.update()
                        self.frontSprites.update()

                        dirtyRects1 = self.backSprites.draw( self.window )
                        dirtyRects2 = self.frontSprites.draw( self.window )
                        
                        dirtyRects = dirtyRects1 + dirtyRects2
                        pygame.display.update( dirtyRects )


                elif isinstance( event, MapBuiltEvent ):
                        gameMap = event.map
                        self.ShowMap( gameMap )

                elif isinstance( event, CharactorPlaceEvent ):
                        self.ShowCharactor( event.charactor )

                elif isinstance( event, CharactorMoveEvent ):
                        self.MoveCharactor( event.charactor )


#------------------------------------------------------------------------------
class Game:
        """..."""

        STATE_PREPARING = 0
        STATE_RUNNING = 1
        STATE_PAUSED = 2

        #----------------------------------------------------------------------
        def __init__(self, evManager):
                self.evManager = evManager
                self.evManager.RegisterListener( self )

                self.state = Game.STATE_PREPARING
                
                self.players = [ Player(evManager) ]
                self.map = Map( evManager )

        #----------------------------------------------------------------------
        def Start(self):
                self.map.Build()
                self.state = Game.STATE_RUNNING
                ev = GameStartedEvent( self )
                self.evManager.Post( ev )

        #----------------------------------------------------------------------
        def Notify(self, event):
                if isinstance( event, TickEvent ):
                        if self.state == Game.STATE_PREPARING:
                                self.Start()

#------------------------------------------------------------------------------
class Player:
        """..."""
        def __init__(self, evManager):
                self.evManager = evManager
                #self.evManager.RegisterListener( self )

                self.charactors = [ Charactor(evManager) ]

#------------------------------------------------------------------------------
class Charactor:
        """..."""
        def __init__(self, evManager):
                self.evManager = evManager
                self.evManager.RegisterListener( self )
                self.sector = None

        #----------------------------------------------------------------------
        def Move(self, direction):
                if self.sector.MovePossible( direction ):
                        newSector = self.sector.neighbors[direction]
                        self.sector = newSector
                        ev = CharactorMoveEvent( self )
                        self.evManager.Post( ev )

        #----------------------------------------------------------------------
        def Place(self, sector):
                self.sector = sector
                ev = CharactorPlaceEvent( self )
                self.evManager.Post( ev )

        #----------------------------------------------------------------------
        def Notify(self, event):
                if isinstance( event, GameStartedEvent ):
                        gameMap = event.game.map
                        self.Place( gameMap.sectors[gameMap.startSectorIndex] )

                elif isinstance( event, CharactorMoveRequest ):
                        self.Move( event.direction )

#------------------------------------------------------------------------------
class Map:
        """..."""
        def __init__(self, evManager):
                self.evManager = evManager
                #self.evManager.RegisterListener( self )

                self.sectors = range(9)
                self.startSectorIndex = 0

        #----------------------------------------------------------------------
        def Build(self):
                for i in range(9):
                        self.sectors[i] = Sector( self.evManager )

                self.sectors[3].neighbors[DIRECTION_UP] = self.sectors[0]
                self.sectors[4].neighbors[DIRECTION_UP] = self.sectors[1]
                self.sectors[5].neighbors[DIRECTION_UP] = self.sectors[2]
                self.sectors[6].neighbors[DIRECTION_UP] = self.sectors[3]
                self.sectors[7].neighbors[DIRECTION_UP] = self.sectors[4]
                self.sectors[8].neighbors[DIRECTION_UP] = self.sectors[5]

                self.sectors[0].neighbors[DIRECTION_DOWN] = self.sectors[3]
                self.sectors[1].neighbors[DIRECTION_DOWN] = self.sectors[4]
                self.sectors[2].neighbors[DIRECTION_DOWN] = self.sectors[5]
                self.sectors[3].neighbors[DIRECTION_DOWN] = self.sectors[6]
                self.sectors[4].neighbors[DIRECTION_DOWN] = self.sectors[7]
                self.sectors[5].neighbors[DIRECTION_DOWN] = self.sectors[8]

                self.sectors[1].neighbors[DIRECTION_LEFT] = self.sectors[0]
                self.sectors[2].neighbors[DIRECTION_LEFT] = self.sectors[1]
                self.sectors[4].neighbors[DIRECTION_LEFT] = self.sectors[3]
                self.sectors[5].neighbors[DIRECTION_LEFT] = self.sectors[4]
                self.sectors[7].neighbors[DIRECTION_LEFT] = self.sectors[6]
                self.sectors[8].neighbors[DIRECTION_LEFT] = self.sectors[7]

                self.sectors[0].neighbors[DIRECTION_RIGHT] = self.sectors[1]
                self.sectors[1].neighbors[DIRECTION_RIGHT] = self.sectors[2]
                self.sectors[3].neighbors[DIRECTION_RIGHT] = self.sectors[4]
                self.sectors[4].neighbors[DIRECTION_RIGHT] = self.sectors[5]
                self.sectors[6].neighbors[DIRECTION_RIGHT] = self.sectors[7]
                self.sectors[7].neighbors[DIRECTION_RIGHT] = self.sectors[8]

                ev = MapBuiltEvent( self )
                self.evManager.Post( ev )

#------------------------------------------------------------------------------
class Sector:
        """..."""
        def __init__(self, evManager):
                self.evManager = evManager
                #self.evManager.RegisterListener( self )

                self.neighbors = range(4)

                self.neighbors[DIRECTION_UP] = None
                self.neighbors[DIRECTION_DOWN] = None
                self.neighbors[DIRECTION_LEFT] = None
                self.neighbors[DIRECTION_RIGHT] = None

        #----------------------------------------------------------------------
        def MovePossible(self, direction):
                if self.neighbors[direction]:
                        return 1


#------------------------------------------------------------------------------
def main():
        """..."""
        evManager = EventManager()

        keybd = KeyboardController( evManager )
        spinner = CPUSpinnerController( evManager )
        pygameView = PygameView( evManager )
        game = Game( evManager )
        
        spinner.Run()

if __name__ == "__main__":
        main()