# MayaCurveCache.py
# Implements a specialized version of the cache
# that can generate Maya curves based on the
# data it has been given
  
#--> = my added notes
  
import BasicCache as BC
import maya.cmds as mc
import ProjectUtilities as PU
import random
  
#============================================
# Note this super class is derived from BasicCache.    
class MayaParticleCache(BC.BasicCache):
    # This queries the particle system and used the base
    # class method "add()" to accumulate xyz data
    #--> tnode is an argument passed over by the MEL script at call
    def updateCache(self, tnode):
        pnum = mc.particle(tnode, q = True, count = True)
        for n in range(pnum):
            pname = tnode + ".pt[%s]" % n
            pos = mc.getParticleAttr(pname,at = 'position')
            # getParticleAttr returns a list of 6 values of which
            # only the first three are a particles xyz position!
            #--> the trim function cuts this down to the first three
            #--> i.e. the first position (0) up to but not including
            #--> the fourth (3)
            self.add(pos[0:3])
  
    # Construct the string that will become the Mel command to 
    # create a curve
    def writeCurve(self):
        melcmd = 'curve -d 3 '
        #--> counter for line-breaks for readability
        count = 1
        for xyz in self.data:
            #--> remember, the point coords are stored in a LIST of TUPLES
            #--> therefore xyz denotes the LIST index and the bracketed
            #--> numbers indicate the TUPLE index of that LIST index
            melcmd = melcmd + '-p %1.3f %1.3f %1.3f ' % (xyz[0],xyz[1],xyz[2])
            count += 1
            if count > 5:
                #--> adds a return and tab carriage for human-readability
                melcmd += '\n\t'
                count = 1
        melcmd = melcmd + ';'
        #--> stores the string in dataStr in case we want
        #--> to concatenate with others
        self.dataStr = self.dataStr + melcmd
        return melcmd
        
    #--> randomized version of the single curve code
    #--> uses the position of the particles but adds
    #--> a random value to each before generating the curve    
    def writeRandomCurve(self):
        melcmd = 'curve -d 3 '
        #--> counter for line-breaks for readability
        count = 1
        for xyz in self.data:
            randX = random.uniform (.1, .3)
            newX = xyz[0] + randX
            randY = random.uniform (.1, .3)
            newY = xyz[1] + randY
            randZ = random.uniform (.1, .3)
            newZ = xyz[2] + randZ
            #--> remember, the point coords are stored in a LIST of TUPLES
            #--> therefore xyz denotes the LIST index and the bracketed
            #--> numbers indicate the TUPLE index of that LIST index
            melcmd = melcmd + '-p %1.3f %1.3f %1.3f ' % (newX,newY,newZ)
            count += 1
            if count > 5:
                #--> adds a return and tab carriage for human-readability
                melcmd += '\n\t'
                count = 1
        melcmd = melcmd + ';'
        #--> stores the string in dataStr in case we want
        #--> to concatenate with others
        self.dataStr = self.dataStr + melcmd
        return melcmd
        
    #--> Construct the multiple strings that will become 
    #--> the Mel command to create multiple spikes
    def writeManyCurves(self):
        starter = 'curve -d 1 -p 0 0 0 '
        melcmd = starter
        for xyz in self.data:
            melcmd = melcmd + '-p %1.3f %1.3f %1.3f' % (xyz[0],xyz[1],xyz[2]) + ';\n'
            if xyz <= (self.data):
                melcmd = melcmd + starter
            else:
                melcmd = melcmd + ';'
        self.dataStr = self.dataStr + melcmd
        return melcmd
        
    #--> randomized version of the spikes
    def writeManyRandomCurves(self):
        starter = 'curve -d 1 -p 0 0 0 '
        melcmd = starter
        for xyz in self.data:
            randX = random.uniform (.1, .3)
            newX = xyz[0] + randX
            randY = random.uniform (.1, .3)
            newY = xyz[1] + randY
            randZ = random.uniform (.1, .3)
            newZ = xyz[2] + randZ
            melcmd = melcmd + '-p %1.3f %1.3f %1.3f' % (newX,newY,newZ) + ';\n'
            if xyz <= (self.data):
                melcmd = melcmd + starter
            else:
                melcmd = melcmd + ';'
        self.dataStr = self.dataStr + melcmd
        return melcmd
        
#============================================
  
#--> instance the above superclass
pCache = MayaParticleCache()
projUtils = PU.ProjectUtilities()
  
def particlesToMayaCurves(tnode, startAt, endFrame, curveType):
    # If we prefer to base the duration of the simulation on the users
    # render globals the next line can be activated
    #endFrame = mc.getAttr("defaultRenderGlobals.endFrame");
    
    #--> sets the script up to work on the correct file
    pCache.setDataPath(projUtils.getDataDir() + "/" + projUtils.getSceneName() + ".mel");
    
    for currFrame in range(endFrame):
        #--> we increment first instead of after because "currFrame"
        #--> starts at zero and there is no frame zero
        currFrame += 1;
        mc.currentTime(currFrame);
        print("frame %s" % currFrame)
        
        if currFrame == 1:
            pCache.reset()
        if currFrame >= startAt and currFrame <= endFrame:
            pCache.updateCache(tnode)
        if currFrame == endFrame:
            if curveType == 1:
                #--> single curve
                return pCache.writeCurve()
            elif curveType == 2:
                #--> spikes
                return pCache.writeManyCurves()
            elif curveType == 3:
                #--> single curve randomized
                return pCache.writeRandomCurve()
            elif curveType == 4:
                #--> spikes randomized
                return pCache.writeManyRandomCurves()
            else:
                print "FAIL: Did not recognize curve type"
  
def writeToFile():
    return pCache.writeToFile()