from visual import *

from Tracer import *
from Spin import *
from Bonds import *

from SpinLattice import *
from BondLattice import *

 
class VisualLattice:
    def __init__(self, nSpinsX, nSpinsY, stripeSpacingX, stripeSpacingY, tracerLength, k):
        self.window = display(title='Spin Lattice', width=720, height=400, x=150, y=600, background=(.0,.0,.0))
        self.window.fov = pi/900.0
        self.window.lights = [vector(.5,.5,.5), vector(-.5,-.5,-.5)]
        self.window.up = (0.0,0.0,1.0)
        self.window.forward = (0.0,0.5,-0.3)
        self.window.center = (nSpinsX,nSpinsY,0.0)
        self.window.range = 2.0
        self.window.autoscale = 0
        self.window.visible = 0
        self.window.select()

        self.nSpinsX = nSpinsX
        self.nSpinsY = nSpinsY

        self.stripeSpacingX = stripeSpacingX
        self.stripeSpacingY = stripeSpacingY
        
        self.k = k

        self.tvWindow = 1

    
        self.SpinLattice = SpinLattice(nSpinsX, nSpinsY, k)

        self.tracerArray = [ None ] * nSpinsX
        for x in range(nSpinsX):
            self.tracerArray[x] = [0] * nSpinsY
            for y in range(nSpinsY):
                self.tracerArray[x][y] = Tracer(tracerLength)

        self.fieldTracerArray = [ None ] * nSpinsX
        for x in range(nSpinsX):
            self.fieldTracerArray[x] = [0] * nSpinsY
            for y in range(nSpinsY):
                self.fieldTracerArray[x][y] = Tracer(tracerLength)

##        self.xyzComponentGraph = curve(x=arange(-self.nSpinsX,0.0,1.0),y=-1.5,radius=.02,color=color.yellow)

        self.toggleTracers()
        self.toggleVectors()


        self.BondLattice = BondLattice(nSpinsX, nSpinsY)


        self.window.range = self.nSpinsX/2.0
        self.window.forward = norm(vector(0.0,1.5/self.nSpinsX+1.0,-(1.0/self.nSpinsX + 1.0/self.nSpinsY)**1.7))
        self.window.visible = self.tvWindow
        self.window.center = (-self.nSpinsX/2.0,-self.nSpinsY/2.0,0.0)



        self.axisOrigin = vector(-self.nSpinsX-.3,-self.nSpinsY-.3,0.0)
        
        self.xAxis = []
        self.yAxis = []
        self.zAxis = []
        
        for x in arange(-0.1,1.01,1.1):     self.xAxis.append(vector(x,0,0) + self.axisOrigin)
        for y in arange(-0.1,1.01,1.1):     self.yAxis.append(vector(0,y,0) + self.axisOrigin)
        for z in arange(-0.5,0.51,1.0):     self.zAxis.append(vector(0,0,z) + self.axisOrigin)
        
        self.xAxisLine = curve(pos=self.xAxis, color=(.9,.9,.9), visible=self.tvWindow)
        self.yAxisLine = curve(pos=self.yAxis, color=(.9,.9,.9), visible=self.tvWindow)
        self.zAxisLine = curve(pos=self.zAxis, color=(.9,.9,.9), visible=self.tvWindow)

        self.xAxisLabel = label(pos=vector(1.0,0,0) + self.axisOrigin, text='x', xoffset=0, yoffset=-.001, space=.1, height=10, box=0, opacity=0, line=0, border=4, color=(.9,.9,.9), visible=self.tvWindow)
        self.yAxisLabel = label(pos=vector(0,1.0,0) + self.axisOrigin, text='y', xoffset=-.001, yoffset=.001, space=.1, height=10, box=0, opacity=0, line=0, border=4, color=(.9,.9,.9), visible=self.tvWindow)
        self.zAxisLabel = label(pos=vector(0,0,0.5) + self.axisOrigin, text='z', xoffset=.001, yoffset=.001, space=.1, height=10, box=0, opacity=0, line=0, border=4, color=(.9,.9,.9), visible=self.tvWindow)







    ## BOND METHODS

    def addBonds(self):
        self.BondLattice.addBonds()
           
    def updateBonds(self, nLattice):
        self.BondLattice.updateBonds(nLattice)

    def toggleBonds(self):
        self.BondLattice.toggleBonds()




              
    ## VECTOR METHODS

    def addVectors(self):
        self.SpinLattice.addVectors()
        
    def updateVectors(self, nLattice):
        self.SpinLattice.updateVectors(nLattice)

    def toggleVectors(self):
        self.SpinLattice.toggleVectors()

    ## TORQUE VECTOR METHODS

    def addTorqueVectors(self):
        self.SpinLattice.addTorqueVectors()
        
    def updateTorqueVectors(self, nLattice):
        self.SpinLattice.updateTorqueVectors(nLattice)
      
    def toggleTorqueVectors(self):
        self.SpinLattice.toggleTorqueVectors()

    ## FIELD VECTOR METHODS

    def addFieldVectors(self):
        self.SpinLattice.addFieldVectors()
        
    def updateFieldVectors(self, nLattice):
        self.SpinLattice.updateFieldVectors(nLattice)
      
    def toggleFieldVectors(self):
        self.SpinLattice.toggleFieldVectors()

    ## POINT METHODS

    def addPoints(self):
        self.SpinLattice.addPoints()

    def updatePoints(self, nLattice):
        self.SpinLattice.updatePoints(nLattice)

    def togglePoints(self):
        self.SpinLattice.togglePoints()





    ## TRACER METHODS

          
    def updateTracers(self, nLattice):
        spinLattice = self.SpinLattice.returnSpinLattice()
        
        currentState = nLattice.returnState()
        phiScale = nLattice.returnPhiScale()+.001
        phiArray = nLattice.returnPhiArray()
        phaseArray = nLattice.returnPhaseArray()
        zArray = nLattice.returnzArray()

        for x in range(self.nSpinsX):
            for y in range(self.nSpinsY):
                xModXSpacing = x%nLattice.stripeSpacingX
                yModYSpacing = y%nLattice.stripeSpacingY
                
                location = spinLattice[x][y].getVectorPos() + spinLattice[x][y].getVectorAxis()

##                tAngle = phaseArray[xModXSpacing][yModYSpacing]
                zFlip = zArray[xModXSpacing][yModYSpacing]

                new = currentState[x][y]
                k1 = norm(self.k)
                z = zFlip*dot(new, k1)[0]/(phiScale*phiArray[xModXSpacing][yModYSpacing])
                color = ((1.0+z)/2.0,1.0-(z)**2,(1.0-z)/2.0)

                self.tracerArray[x][y].step(location, color)


##                if yModYSpacing == 0:
##                    if xModXSpacing == 0:
##                        self.xyzComponentGraph.pos[x] = spinLattice[x][y].getVectorPos() + spinLattice[x][y].getVectorAxis()
##                    else:
##                        self.xyzComponentGraph.pos[x] = spinLattice[x][y].getVectorPos()

       

    def updateFieldTracers(self, nLattice):
        spinLattice = self.SpinLattice.returnSpinLattice()
        
        currentState = nLattice.returnMeanFieldArray()
        phiScale = nLattice.returnPhiScale()+.001
        phiArray = nLattice.returnPhiArray()
        phaseArray = nLattice.returnPhaseArray()
        zArray = nLattice.returnzArray()

        for x in range(self.nSpinsX):
            for y in range(self.nSpinsY):
                xModXSpacing = x%nLattice.stripeSpacingX
                yModYSpacing = y%nLattice.stripeSpacingY
                
                location = spinLattice[x][y].getVectorPos()+ spinLattice[x][y].getVectorAxis()/2+currentState[x][y][0]/2

##                tAngle = phaseArray[xModXSpacing][yModYSpacing]
                zFlip = zArray[xModXSpacing][yModYSpacing]

                new = currentState[x][y]
                k1 = norm(self.k)
                z = zFlip*dot(new, k1)[0]/(phiScale*phiArray[xModXSpacing][yModYSpacing])
                color = ((1.0+z)/2.0,1.0-(z)**2,(1.0-z)/2.0)

                self.fieldTracerArray[x][y].step(location, color)
              
    def resetTracers(self):
        for x in range(self.nSpinsX):
            for y in range(self.nSpinsY):
                self.tracerArray[x][y].delTracer()

                
    def toggleTracers(self):
        for x in range(self.nSpinsX):
            for y in range(self.nSpinsY):
                self.tracerArray[x][y].toggleVisibility()
                self.fieldTracerArray[x][y].toggleVisibility()








    def toggleWindow(self):
        self.tvWindow = (self.tvWindow+1)%2

        if self.tvWindow == 1:
            self.window.visible = self.tvWindow
            
            self.xAxisLine.visible = self.tvWindow
            self.yAxisLine.visible = self.tvWindow
            self.zAxisLine.visible = self.tvWindow

            self.xAxisLabel.visible = self.tvWindow
            self.yAxisLabel.visible = self.tvWindow
            self.zAxisLabel.visible = self.tvWindow
        else:
            self.xAxisLine.visible = self.tvWindow
            self.yAxisLine.visible = self.tvWindow
            self.zAxisLine.visible = self.tvWindow

            self.xAxisLabel.visible = self.tvWindow
            self.yAxisLabel.visible = self.tvWindow
            self.zAxisLabel.visible = self.tvWindow
            
            self.window.visible = self.tvWindow
                
    def returnArray(self):
        return self.spinArray

##    def updateState(self):
##        self.spinArray = self.numerics.returnState()
##        self.meanFieldArray = self.numerics.returnMeanFieldArray()
##        self.energies = self.numerics.returnEnergies()
##        self.bondEnergies = self.numerics.returnBondEnergies()
        














