import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import *
from direct.task import Task

class Flat(DirectObject):
    def __init__(self,paths,cam=None):
        cm = CardMaker("for flat")
        cm.setFrame(-.5,.5,-.5,.5)
        card = cm.generate()
        self.flat = NodePath(card)
        self.flat.setTransparency(TransparencyAttrib.MAlpha)
        self.frames = []
        for p in paths:
            self.frames.append(loader.loadTexture(p))
        self.flat.setTexture(self.frames[0])
        self.flat.setLightOff()
        self.currentFrame = 0
        self.frameCountdown = 1
        
        self.cam = cam
        self.billboarded = (self.cam is not None)
        if self.billboarded:
            self.ID = 0
            while taskMgr.hasTaskNamed("billboard task "+str(self.ID)):
                self.ID+=1
            taskMgr.add(self.billboardTask,"billboard task "+str(self.ID))
        self.animID = -1
        
    # on the one hand, % in python is signed and can return negative
    # on the other, lists index by negatives...
    def advanceFrame(self):
        self.currentFrame = (self.currentFrame+1)%len(self.frames)
        self.flat.setTexture(self.frames[self.currentFrame])
        
    def reverseFrame(self):
        self.currentFrame = (self.currentFrame-1)%len(self.frames)
        if self.currentFrame<0:
            self.currentFrame+=len(self.frames)
        self.flat.setTexture(self.frames[self.currentFrame])
        
    def setFrame(self,frame):
        self.currentFrame = frame%len(self.frames)
        self.flat.setTexture(self.frames[self.currentFrame])
        
    def billboardTask(self,task):
        self.flat.setHpr(self.cam.getHpr(render))
        return Task.cont
    
    # play an animation of frames
    def playForwards(self,framerate,numframes):
        self.frameCountdown = numframes
        
        if self.animID!=-1:
            self.stopAnims()
        self.animID=0
        while taskMgr.hasTaskNamed("animate forwards "+str(self.animID)):
            self.animID+=1
        taskMgr.doMethodLater(1.0/framerate,self.playForwardsTask,"animate forwards "+str(self.animID))
        
    def playForwardsTask(self,task):
        self.advanceFrame()
        self.frameCountdown -= 1
        if self.frameCountdown!=0:
            return Task.again
        
    def playBackwards(self,framerate,numframes):
        self.frameCountdown = numframes
        if self.animID!=-1:
            self.stopAnims()
        self.animID=0
        while taskMgr.hasTaskNamed("animate backwards "+str(self.animID)):
            self.animID+=1
        taskMgr.doMethodLater(1.0/framerate,self.playBackwardsTask,"animate backwards "+str(self.animID))
        
    def playBackwardsTask(self,task):
        self.reverseFrame()
        self.frameCountdown -= 1
        if self.frameCountdown!=0:
            return Task.again
        
    def loopForwards(self,framerate):
        if self.animID!=-1:
            self.stopAnims()
        self.animID=0
        while taskMgr.hasTaskNamed("loop forwards "+str(self.animID)):
            self.animID+=1
        taskMgr.doMethodLater(1.0/framerate,self.loopForwardsTask,"loop forwards "+str(self.animID))
    
    def loopForwardsTask(self,task):
        self.advanceFrame()
        return Task.again
        
    def loopBackwards(self,framerate):
        if self.animID!=-1:
            self.stopAnims()
        self.animID=0
        while taskMgr.hasTaskNamed("loop backwards "+str(self.animID)):
            self.animID+=1
        taskMgr.doMethodLater(1.0/framerate,self.loopBackwardsTask,"loop backwards "+str(self.animID))
        
    def loopBackwardsTask(self,task):
        self.reverseFrame()
        return Task.again
        
    def stopAnims(self):
        taskMgr.remove("animate forwards "+str(self.animID))
        taskMgr.remove("animate backwards "+str(self.animID))
        taskMgr.remove("loop forwards "+str(self.animID))
        taskMgr.remove("loop backwards "+str(self.animID))
        self.animID=-1
        
    def destroy(self):
        if self.billboarded:
            taskMgr.remove("billboard task "+str(self.ID))
        self.flat.removeNode()
        #DirectObject.destroy(self)
        