# a (high-level) library for VJing etc.

# an abstraction that maps controls to actions and can be logged,
# also used to construct more complex serieses of events
# must work with Blender first, other (like Pygame) would be nice

import GameLogic
import Rasterizer

# a shorthand for blender
def act1(act):
    GameLogic.addActiveActuator(act,1)

def act0(act):
    GameLogic.addActiveActuator(act,0)

class Event:
    def __init__(self, scene, type):
        self.type=type #first: mover, global (could be camera etc.. & default?)
        self.scene=scene
        self.scene.pot_events.append(self)
        self.actions=[]

    def act(self, mover=None): #how about non mover default events?-o
        for action in self.actions:
            exec(action) # actions are engine specific command strings
            
    def start(self):
        self.scene.act_events.append(self)

    def stop(self):
        self.scene.act_events.remove(self)

class GlobalEvent(Event):
    def __init__(self, scene):
        Event.__init__(self, scene, "global")

class MoverEvent(Event):
    def __init__(self, scene):
        Event.__init__(self, scene, "mover")        
        
# used to log/record events (that lead to actions),
# playback may be used together with controls to add new events (to a new log)

class Recorder:
    def __init__(self):
        filename="k-log00.kel" # kel = kyperjokki event log

    def record(events):
        print "s.msms: "+events

    def play(self):
        pass

class Controller:
    def __init__(self):
        self.value=-1

class Slide(Controller):
    pass

class RhythmMaster:
    def __init__(self, scene):
        self.scene = scene
        #self.mode="beat"
        self.beatcount=0
        self.previousbeat=-1
        self.beat_begin=0
        self.tahti_length=0
        self.tahti_half=0
        self.tahti_end=0
        self.setBeat(135)
        self.setTahti(0)
        self.update()
        
    def update(self):
        #assumes even beat, 4/4 tahti
        if self.mode=="beat":
            if self.tahti_length:
                pass

            elif self.tahti_end:
                self.tahti_length = self.tahti_end - self.tahti_begin
            
            elif self.tahti_half:
                self.tahti_length = (self.tahti_half - self.tahti_begin) * 2

            else:
                print "could not (yet) calculate 'tahti' in beat mode"

            print self.getLength()

    def setBeat(self, bpm=None):
        self.mode="beat"
        if bpm:
            self.bpm=bpm
            self.beat_length = 60.00 / self.bpm
            self.tahti_half = self.beat_length * 2

        else:
            self.beatcount = self.beatcount + 1
            self.previousbeat = self.beat_begin
            self.beat_begin = self.scene.time.now
            self.beat_length = self.beat_begin - self.previousbeat

            if self.beatcount == 1:
                print "1st beat"
                self.tahti_begin=self.beat_begin
                self.tahti_half=0
                self.tahti_length=0

            if self.beatcount == 4:
                print "4th beat - tahti?"
                self.tahti_half=self.beat_begin-self.tahti_begin
                self.tahti_length=0

            if self.beatcount == 8:
                print "8th beat"
                self.tahti_end=self.beat_begin-self.tahti_begin
                self.tahti_length=0
                self.beatcount=0

            #self.bpm=?
            self.update()

    def setTahti(self, whatpart):
        if whatpart == 0:
            self.tahti_begin = self.scene.time.now

        elif whatpart == 1:
            self.tahti_half = self.scene.time.now

        else:
            print "invalid call to RhytmMaster.setTahti:", whatside

    def getLength(self, what="tahti"):
        if self.mode=="tahti":
            return self.tahti_length

        if self.mode=="beat":
            return self.beat_length

class TimeCode:
    def __init__(self, scene):
        self.scene = scene
        self.mode = "play"
        self.code=0 #the actual time code for whatever uses it, e.g. animations
        self.now=0
        self.was=-1

    def update(self, timer):
        #vrt. animmode = play|scrub
        self.was = self.now
        self.now = timer #actual time
        self.totalcyclelength = self.now - self.was
        #could also calculate how long scene.update() takes (vs. Blender)

        #setting the code, now 0..1 (i.e. suits short loops)
        # argh! -- what to do about animations that have rhytm anywhere within?
        if self.mode == "play":
            self.step = self.totalcyclelength / self.scene.rhythm.getLength()
            self.code = self.code + self.step
            if self.code > 1:
                self.code = self.code - 1
                            
        elif self.mode == "scrub":
            self.code = self.scene.horizontal.value
            #this could be done also similarily to KyperjokkiWorkPSX
            #if there were long loops

        elif self.mode == "pause":
            pass
            
        elif self.mode == "stop":
            self.code = 0

        #print "now:", self.now, "was:", self.was, "cycle:", self.totalcyclelength, "code:", self.code, "step:", self.step, " length:", self.scene.rhythm.getLength()

class BeatTap(GlobalEvent):
    def act(self):
        self.scene.rhythm.setBeat()

class TahtiTap(GlobalEvent):
    def act(self):
        self.scene.rhythm.setTahti(0) #only for beginning now

#encapsulates (in mover5) what used to be globals (in mover4)
class Scene:
    def __init__(self, controller):
        #for keyboard control, used in controls.py
        self.keymod=None
        
        #to see if something was cloned last cycle, to set it's bobject
        self.wascloned=None

        #to adjust the phase of controlled clone actions
        self.clonephasing=0.3 #default delay between clones

        #matrix stuff
        self.matrix_todo=None #the type of cloning for matrixmode
        self.matrix_clones_todo=[] #list of clones to make (in .update())
        self.matrixmode=0 #set by MatrixMode event that adds to todo
        self.matrixfilling=None #the thing&direction where is filled now
        self.matrixfillcount=0 #the amount of fills to do

        #for direct movement manipulation test
        self.jugglemode=0
        
        #all potential events in this scene (setup / preset?)
        self.pot_events = []

        #events that are currently activated (by some control)
        self.act_events = []

        #movers in this setup (from blender side to get their GameObjects?)
        self.pot_movers=[] #all potential
        self.act_movers=[] #all to which actions should apply now

        #where movers wait till their blender objects&controllers come..
        self.mover_placeholder={}
       
        # mouse axes go to these now
        self.horizontal = Slide()
        self.vertical = Slide()

        #is used together with controls.py to implement ONCLICK control type
        self.wasclicked=[]

        self.leftmousepressed = 0
        self.leftmousewaspressed = 0

        #the screen (to be able to normalize mouse axis) -- assumes fullscreen!
        self.screenx = Rasterizer.getWindowWidth();
        self.screeny=Rasterizer.getWindowHeight();

        #sensors = GameLogic.controller.getSensors()
        self.controller=controller
        self.controllerobject=self.controller.getOwner()
        #print sensors
        print self.controllerobject
        self.keyboard = self.controller.getSensor("keyboard")
        self.mousemove = self.controller.getSensor("mousemove")

        #used in AnimateCharacter, perhaps other's too (if was video :o)
        # -- now switching to use a TimeCode class! and a timer property
        #self.animmode = "play"
        self.time = TimeCode(self)
        self.rhythm = RhythmMaster(self)

        #can't do buttons in the same, 'cause mousemove activates them!-/
        #leftmouse = GameLogic.controller.getSensor("leftmouse")

        #perhaps not needed as are gotten with names below..
        #actuators = controller.getActuators()

        #now here only those NOT about the objects (movers)
        self.setscene = self.controller.getActuator("setscene")
        self.addobject = self.controller.getActuator("addobject")

        #of camera
        self.cammove = self.controller.getActuator("cammove")
        self.camzoom = self.controller.getActuator("camzoom")
        self.camtrack = self.controller.getActuator("camtrack")

        #.. also the camera itself, how else to get it .. from scene?
        self.camera = self.cammove.getOwner()
        self.camera.zoom=35
        act1(self.camzoom)

        #this is the Empty object now?
        #controller = None

    def update(self):
        self.time.update(self.controllerobject.timer)
        #self.rhythm.update() #is called from events that affect
        
        if self.wascloned:
            #matrix kludge
            #self.wascloned.clone()
            print "wascloned"
            
            #self.wascloned=None
            #pass

        try:
            GameLogic.remotecommands

            try:
                self.remotecommand.stop()
                self.remotecommand=None
            except:
                pass #there was no command the last time
            
            while GameLogic.remotecommands:
                self.remotestr=GameLogic.remotecommands.pop()
                try:
                    self.remotecommand=self.pot_events[int(self.remotestr)]
                    print "activating remote command:", self.remotecommand
                    self.remotecommand.start()
                    print self.act_events
                except ValueError:
                    print "not a number:", self.remotestr

        except:
            pass #print "the list of remote commands not there yet"

        if self.act_events:
            #print self.act_events
            for event in self.act_events:
                if event.type=="global":
                    event.act()

                if event.type=="mover":
                    event.act()
                    #for mover in self.scene.act_movers:
                        #mover.move.act("forward")
                        #eval(mover.repr(event).act(params))
                    #change this to -> mover.act(act_mover_events) !?!
               
                if event in self.wasclicked:
                    self.wasclicked.remove(event)
                    event.stop()
                    #10:55 < sjj> map(lambda x: event.act(self, x), self.act_movers) but the for loop or a list comprehension would be more efficient in this case

        #do these HOG?
        if self.camera.zoom > 100:
            self.camera.zoom = 100

        elif self.camera.zoom < 1:
            self.camera.zoom = 1

        act1(self.camzoom)
        act1(self.cammove)

        if self.leftmousepressed:
            if not self.leftmousepressed:
                scrubMode.start(self)
                self.leftmousewaspressed=1

        else:
            if self.leftmousewaspressed:
                scrubMode.stop()
                self.leftmousewaspressed=0

        if (not self.wascloned) and self.matrix_clones_todo:
            print "there was no cloning in this cycle, filling in 'matrix'"
            self.matrixfilling, self.matrixfillcount=self.matrix_clones_todo.pop()
            #if self.matrixfilling[1]=="horizontal":
            #-- is actually handled by initmover.
            self.addobject.setObject(self.matrixfilling[0].name)
            act1(self.addobject)

    def addMover(self, number):
        self.addobject.setObject(self.movernames[number-1])
        act1(self.addobject)
        self.addedmovernumber=number #to be able to put to right spot
        #does this need wascreated? initmover.py does take care.

    #What else?

#argh!
#hum, is this used?
moverscene = Scene(GameLogic.getCurrentController())

#to encapsulate things needed for mover in Blender
class Mover:
    def __init__(self, name, motions, bone, scene):
        self.scene=scene
        self.name = name
        self.motions = motions #names of actions for animating
        self.animations = [] #will be added based on motions when brining in
        self.bone = bone #the default bone for transforming directly
        self.scene.mover_placeholder[name]=self

    def invoke(self):
        #blender stuff associated
        self.bobject, self.controller = GameLogic.Object[self.name]
        
        #should go to the own place, see ksetup.py/scene.movernames
        #but an init order problem? solving with a helper variable..
        self.placenumber=self.scene.addedmovernumber
        self.scene.pot_movers[self.placenumber-1]=self

        #for turning (not a vector for the sake of simplicity..)
        #must be floats for slowing down to work!
        self.turn_x=0.00
        self.turn_y=0.00
        self.turn_z=0.00

        #for movements
        self.move_x=0.00
        self.move_y=0.00
        self.move_z=0.00

        #experimental.. the clones are not movers but blender objects. ok?
        # .. or perhaps they should be put back as Movers? *sigh* / gee! ?-o
        self.allclones=[[],[],[], []] #horizontal, vertical, (z/y), matrixfill 
        #self.matrixclones =[[],[]]
        self.ver_cloning=0 #a counter / trigger from Mover to initmover
        self.hor_cloning=0 #same for the other direction
        #how about z?

        self.actuators = self.controller.getActuators()
        self.move_act = self.controller.getActuator("move")
        self.animates=[0,0,0,0,0] #,0,0,0,0,0,0,0,0,0,0,0] #stupid hack :o
        #changemesh = controller.getActuator("changemesh")
        self.ipo_act = self.controller.getActuator("ipo")
        self.endobject_act = self.controller.getActuator("endobject")

        #animations (as one actuator may do only one thing per cycle)
        for act in range(self.bobject.maxacts):
            #exec("self.animate"+repr(act+1)+" = self.controller.getActuator(\"animate"+repr(act+1)+"\")")
            print "self.animate_act"+repr(act+1)+" = self.controller.getActuator(\"animate"+repr(act+1)+"\")"
            exec("self.animate_act"+repr(act+1)+" = self.controller.getActuator(\"animate"+repr(act+1)+"\")")
            self.animates[act]=0 #all actuators are initially free

        #trying to have used-to-be methods as MoverEvent instances
        #move=MoveMover(self)
        #turn=TurnMover(self)

        #general attributes
        self.active=1
        self.scene.act_movers.append(self) #same info twice, keep in sync!
        self.selected=1
        self.visible=1
        
        for motion in self.motions:
            self.animations.append(CharacterAnimation(self, motion))

    def clone(self, direction):
        if 1: #normal version
            #print "cloning"
            self.scene.addobject.setObject(self.name)
            act1(self.scene.addobject)
            if direction=="horizontal":
                self.hor_cloning=self.hor_cloning+1
                print self, "hor_cloning incremented to", self.hor_cloning
                self.scene.wascloned=(self, "horizontal")

            elif direction=="vertical":
                self.ver_cloning=self.ver_cloning+1
                print self, "ver_cloning incremented to", self.ver_cloning
                self.scene.wascloned=(self, "vertical")

        if 1: #adding matrix stuff, i.e. to fill the area
            #uh, as only one can be added every time, needs serious kludging
            #.. perhaps a list of objects to be created with some params?
            #, to be read in scene.update (like wascloned)
            #self.scene.vertical_clones_todo.append(self)
            #twice to make both sides
            #self.scene.vertical_clones_todo.append(self)
            
            #counts how many .. rows?
            #self.vertical_clones=1 #self.vertical_clones+1
            pass

    def declone(self, direction):
        #what an earth to do here, as clones are not movers, no endobject?
        #now they have controller and actuators although are not movers!
        
        if direction=="every": #every single clone, now hor&ver only!
            while self.allclones[0] or self.allclones[1]:
                self.declone("all")
        
        if direction=="all": #in all directions, bind to some key perhaps?
            self.declone("horizontal")
            self.declone("vertical")
        
        if direction=="horizontal":
            if self.allclones[0]:
                self.latest_hor_clone=self.allclones[0].pop()
                act1(self.latest_hor_clone[1].getActuator("endobject"))
                print self, "hor_cloning decremented to", self.hor_cloning
                self.hor_cloning=self.hor_cloning-1
            else:
                print "no hor_clones to delete."
                 
        elif direction=="vertical":
             if self.allclones[1]:
                 self.latest_ver_clone=self.allclones[1].pop()
                 act1(self.latest_ver_clone[1].getActuator("endobject"))

                 print self, "ver_cloning decremented to", self.ver_cloning
                 self.ver_cloning=self.ver_cloning-1
                 
             else:
                 print "no ver_clones to delete."

    #selections and removals
    def select(self):
        if not self.selected:
            self.selected=1
            self.scene.act_movers.append(self)

        else:
            pass #could deselect if wanted toggle

    def deselect(self):
        if self.selected:
            self.selected=0
            self.scene.act_movers.remove(self)

        else:
            pass #could select if toggling..

    #add now in Scene, could be here?
    def remove(self):
        self.bobject=None
        self.controller=None
        self.scene.pot_movers[self.placenumber-1]=None
        self.placenumber=None
        self.deselect()
        self.visible=0
        self.declone("all")

        #must clean animations in a way that is safe if they are on!
        #.. there is now a simple quick check in animating
       ##  for event in self.scene.act_events:
##             if isinstance(event, AnimateMover):
##                 print "removing from:", event
##                 event.remove(self)

        del GameLogic.Object[self.name]

        #otherwise, invoking should take care that the table is clear
        #when returning, so this should be safe to do now:
        act1(self.endobject_act)

    #finally actual actions/methods/functions .. things that can do!
    def turn(self, direction):
        #could be in __init__ but here for the sake of clarity. ok?
        try:
            self.turnings
            "the table was there"
            #saving cpu anyhow..
        except:
            print "initialising turnings table"
            self.turnings = {"left": "self.turn_y = self.turn_y + self.step",
                             "right":"self.turn_y = self.turn_y - self.step",
                             "up": "self.turn_x = self.turn_x + self.step",
                             "down": "self.turn_x = self.turn_x - self.step",
                             }
        self.step=1*self.scene.time.totalcyclelength

        if not direction=="slow":
            exec(self.turnings[direction])

        else:
            if self.turn_x != 0: #goes on for very long.. no harm? how stop?
                self.turn_x = self.turn_x / 2
                #print self.turn_x
                
            if self.turn_y != 0:
                self.turn_y = self.turn_y / 2

            #slows movement now too
            if self.move_z != 0:
                self.move_z = self.move_z / 2
                
        self.move_act.setDRot(self.turn_x, self.turn_y, self.turn_z, 1)
        act1(self.move_act)

        for clones in self.allclones:
            for clone in clones:
                self.clonemoveact=clone[1].getActuator("move")
                self.clonemoveact.setDRot(self.turn_x, self.turn_y, self.turn_z, 1)
                act1(self.clonemoveact)

    def move(self, direction):
        #how to bind animations to these? other than subclassing..
        if direction=="stop":
            self.move_z=0
        
        if direction=="forward":
           self.move_z = self.move_z - 0.01

        if direction=="backward":
            self.move_z = self.move_z + 0.01

        self.move_act.setDLoc(0, 0, self.move_z, 1)
        act1(self.move_act)
       
        #can not change turning & movement at the same time,
        #a second movement actuator may be added if that's needed!
        #before that could check the active actuators to note overlap..

        for clones in self.allclones:
           for clone in clones:
               self.clonemoveact=clone[1].getActuator("move")
               self.clonemoveact.setDLoc(0, 0, self.move_z, 1)
               act1(self.clonemoveact)

    def animate(self, motionnumber, todo):
        #motions and animations are different but indexed similarly
        self.hasthismotion=0
            
        try:
            self.animations[motionnumber-1] #does filter out correctly?
            self.hasthismotion=1
        except:
            pass #print "tried to animate a mover with no such animation"
            
        if self.hasthismotion:
            eval("self.animations[motionnumber-1]."+todo+"()")
            #uh clones handled within CharacterAnimation

#class BodyMover(Mover):
#    def animate

#class WalkingMover(BodyMover):
#something that has a walking animation

class CommandMover(MoverEvent):
    def __init__(self, scene, command, params):
        MoverEvent.__init__(self, scene)
        self.command = command
        self.params = params

    def act(self):
        for mover in self.scene.act_movers:
            eval("mover."+self.command+"("+'self.params'+")")

class MoveMover(MoverEvent):
    def __init__(self, scene, direction):
        MoverEvent.__init__(self, scene)
        self.direction=direction

    def act(self):
        for mover in self.scene.act_movers:
            mover.move(self.direction)

    def stop(self):
        for mover in self.scene.act_movers:
            mover.move("stop")
        MoverEvent.stop(self)
        
class TurnMover(MoveMover):
    def act(self):
        for mover in self.scene.act_movers:
            mover.turn(self.direction)

class AnimateMover(MoverEvent):
    def __init__(self, scene, animnum):
        MoverEvent.__init__(self, scene)
        self.animnum=animnum
        self.activemovers=[] #so that movers added during animation wont crash!

    def start(self):
        MoverEvent.start(self)
        self.activemovers=self.scene.act_movers[:]
        print "starting animations for", self.activemovers
        
        for mover in self.activemovers:
            mover.animate(self.animnum, "begin")
        
    def act(self):
        for mover in self.activemovers:
            mover.animate(self.animnum, "play")

    def remove(self, mover):
        self.activemovers.delete(mover)

    def stop(self):
        for mover in self.activemovers:
            mover.animate(self.animnum, "end")
        MoverEvent.stop(self)
    
# trying to fix -- these will be associated from Mover
class CharacterAnimation:
    def __init__(self, mover, motion):
        self.mover=mover
        self.mode="play" #will be refactored to use this? now does not.        
        self.length=motion[1]
        self.position=0
        self.actionname=motion[0]

    def begin(self):
        for a in range(self.mover.bobject.maxacts):
            if self.mover.animates[a]==0:
                self.mover.animates[a]=1
                self.actuatornumber=a+1
                print self.actuatornumber
                break

            elif a==self.mover.bobject.maxacts:
                print "out of action actuators!"
                
            else:
                pass

        self.cloneactname="animate"+repr(self.actuatornumber)

        self.mover.bobject.acts = self.mover.bobject.acts + 1
        #is this thread safe? i guess so.. the print below will show
        #self.actuatornumber = self.mover.bobject.acts #this was a stupid bug?
        self.actuator=eval("self.mover.animate_act"+repr(self.actuatornumber))
        print "ADDED "+repr(self.actuator)+", now there are "+repr(self.mover.bobject.acts)+" of "+repr(self.mover.bobject.maxacts)+" like this:"+repr(self.mover.animates)+repr(self.mover)

    def play(self):
        #HOW TO HANDLE THE EXCEPTION?
      self.cando=0  
      try:
          self.actuator
          self.cando=1

      except:
          print "no actuator in play!"
          self.cando=0
          self.end()
          
      if self.mover.bobject and self.cando:
        self.position = self.length * self.mover.scene.time.code
        #can this drop frames? of course if very fast tempo & long anim.

        if self.mover.scene.jugglemode:
            self.actuator.setChannel(self.mover.bone, self.mover.scene.jugglematrix)

        else: #normal mode
            self.actuator.setAction(self.actionname,0)
            exec("self.mover.bobject.position"+repr(self.actuatornumber)+" = self.position")

        act1(self.actuator)

        for clones in self.mover.allclones:
            self.clonedistance=0
            for clone in clones:
                self.clonedistance=self.clonedistance+1
                self.mover.scene.clonephasing=self.mover.scene.vertical.value
                self.cloneposition=self.position+(self.mover.scene.clonephasing*self.clonedistance)
                if self.cloneposition > self.length:
                    self.cloneposition = self.cloneposition % self.length
                
                self.cloneact = clone[1].getActuator(self.cloneactname)
                self.cloneact.setAction(self.actionname,0)
                exec("clone[0].position"+repr(self.actuatornumber)+" = self.cloneposition")
                act1(self.cloneact)
      else:
          pass

    def end(self):
      if self.mover.bobject:
        #self.position=0
        self.mover.bobject.acts = self.mover.bobject.acts - 1
        self.mover.animates[self.actuatornumber-1]=0
        print "REMOVE "+repr(self.actuator)+", now there are "+repr(self.mover.bobject.acts)+" of "+repr(self.mover.bobject.maxacts)+"like this:"+repr(self.mover.animates)+repr(self.mover)
        act0(self.actuator) #this should free the actuator
        for clones in self.mover.allclones:
            for clone in clones:
                print self.mover.allclones
                self.cloneact = clone[1].getActuator(self.cloneactname)
                act0(self.cloneact)
                    
# a (simple) class for character animations
# needs to add time control (e.g. to bpm/'tahti', scrubbing etc.)
# .. trying scrubbing now, adding modes (a mode for what, actually?) for that

#stupidity follows..
#could these be MoverEvents now?
# -- did that so not used anymore!
## class ObjectManager(Event):
##         def __init__(self, direction, creation):
##             self.type="mover"
##             self.direction=direction
##             self.creation=creation
##             #self.mode=whichmode

##         def act(self, mover):
##             if self.creation
##             mover.clone(self.direction)

class ObjectRemover(MoverEvent):
        def act(self, mover):
            mover.declone()

class JuggleMode(GlobalEvent):
    def __init__(self, scene):
        GlobalEvent.__init__(self, scene)
        self.xyz=[0.0, 0.0, 0.60]

    def start(self):
        Event.start(self)
        if self.scene.jugglemode==0:
            self.scene.jugglemode=1
        self.scene.jugglematrix=[[1,0,0,0],
                                 [0,1,0,0],
                                 [0,0,1,0],
                                 [0,0,0,1]]


    def act(self):
        #for i in range(len(self.xyz)):
        #    self.xyz[i]=self.xyz[i]+0.1
        #    if self.xyz[i]>1: self.xyz[i]=0
        self.xyz[0]=self.scene.horizontal.value-0.5
        self.xyz[1]=-(self.scene.vertical.value-0.5)
        self.scale=self.scene.horizontal.value+0.5
                       
        self.scene.jugglematrix=[[self.scale,0,0,0],
                                 [0,self.scale,0,0],
                                 [0,0,self.scale,0],
                                 [self.xyz[0],self.xyz[1],self.xyz[2],1]]
        print self.scene.jugglematrix
        
    def stop(self):
        self.scene.jugglemode=0
        Event.stop(self)
        
class MatrixMode(GlobalEvent):
    def act(self):
        if self.scene.matrix_todo:
            if self.scene.matrix_todo[1]=="horizontal":
                for ver in range(self.scene.matrix_todo[0].ver_cloning):
                    self.scene.matrix_clones_todo.append((self.scene.matrix_todo, ver))

            elif self.scene.matrix_todo[1]=="vertical":
                for hor in range(self.scene.matrix_todo[0].hor_cloning):
                    self.scene.matrix_clones_todo.append((self.scene.matrix_todo, hor))
            else:
                print "invalid or unsupported cloning direction for matrix fill!"
            self.scene.matrix_todo=None

    def start(self):
        Event.start(self)
        if self.scene.matrixmode==0:
            self.scene.matrixmode=1

    def stop(self):
        if self.scene.matrixmode==1:
            #now erases all matrixfill here, for the latest such mover
            while self.scene.matrixfilling[0].allclones[3]:
                self.filler=self.scene.matrixfilling[0].allclones[3].pop()
                act1(self.filler[1].getActuator("endobject"))
                
            self.scene.matrixmode=0
        Event.stop(self)

class SetCamera(Event):
    def __init__(self, where="front"):
        self.type="global"
        self.where=where

#    def start(self, scene):
#        Event.start(self, scene)
#        self.camera

    def act(self):
        self.target=self.scene.act_movers[-1].bobject.getPosition()
        print "setting camera to:", self.where, ", in relation to:", self.target
        if self.where=="front":
            self.target[0]=self.target[0]-1

        elif self.where=="back":
            self.target[0]=self.target[0]+1

        elif self.where=="left":
            self.target[0]=self.target[1]-1

        elif self.where=="right":
            self.target[0]=self.target[1]+1

        self.scene.camera.setPosition(self.target)

# a simple command receiver, now from server.py!
# derived from http://mail.python.org/pipermail/tutor/2002-August/016299.html ("A small example of using the SocketServer module.")
## import SocketServer

## class RemoteEventHandler(SocketServer.StreamRequestHandler):
##     def handle(self):
##         line = self.rfile.readline()
##         self.wfile.write(line) 

## def startserver():
##     tcpserver = SocketServer.ThreadingTCPServer(('localhost', 16117), RemoteEventHandler)
##     tcpserver.serve_forever()
##     return tcpserver

# a Blender scene
#obsolete so here only as a note..
def blend():
    #import Blender
    import GameLogic
    #import time
    print "starting.."

    kyperscene = GameLogic.SceneActuator()
    print kyperscene.getScene()
    
    #scene = Blender.Scene.New('kyperscene')
    #GameLogic.setScene('kyperscene')
    #scene.makeCurrent()
    #scene.update()
    #Blender.Redraw()
    #print scene.getChildren()

    #camera = Blender.Camera.New('persp')
    #camera.lens = 35.0
    #cameraobj = Blender.Object.New('Camera')
    #cameraobj.link(camera)
    #scene.link(cameraobj)
    #scene.setCurrentCamera(cameraobj)

    #lamp = Blender.Lamp.New('Spot')
    #lamp.energy = 1.8
    #lamp.spotSize = 30.0
    #lampobj = Blender.Object.New('Lamp')
    #lampobj.link(lamp)
    #scene.link(lampobj)

    #Blender.loadFile("meshes.blend")
    #print dir(Blender.Mesh)

    #mesh = Blender.Mesh.get("Guy") # now are: Guy, Monster(?), Suzanne
    #meshobj = Blender.Object.New('Mesh')
    #meshobj.link(mesh)
    #print meshobj
    #meshobj.update()
    #scene.link(meshobj)

    #ob = Blender.Object.New('Lamp2')
    #ob.setLocation(10.0, 0.0, 0.0)
    #ob.link(lamp)
    #scene.link(ob)

    #print scene.getChildren()
    #scene.update()
    #Blender.Redraw()
    print "something made in Blender"
    #while 1: pass
    #time.sleep(10)

    #for z in range(0,10000):
    #    meshobj.setLocation((0, 0, z/100))

    #print "a bit more made"

    return 1

#print "Kyperjokki lib. imported"

