from Tkinter import *
from visual import *
from random import *

import time,sys,thread


from NumericUnitCell import *

from AnglePlot import *


from VisualSphere import *
from VisualUnitCell import *
from PhaseSpace import *





class Simulation:
    paused = 1
    pause = 1
    
    def __init__(self, parent, nSpinsX, nSpinsY, stripeSpacingX, stripeSpacingY, Ja, Jbx, Jby, k, baseSigma, dt):
        self.parent = parent
        self.nSpinsX = nSpinsX
        self.nSpinsY = nSpinsY
        self.nTotSpins = nSpinsX*nSpinsY
        
        self.stripeSpacingX = stripeSpacingX
        self.stripeSpacingY = stripeSpacingY
        
        self.Ja = Ja
        self.Jbx = Jbx
        self.Jby = Jby
       
        self.k = k
        
        self.baseSigma = baseSigma
        
        self.dt = dt

        
        self.temp = 0.00*abs(self.Ja)

        self.MFu = 0.00*abs(self.Ja)
        self.MFd = 0.00*abs(self.Ja)



        self.tracerLength = int(256/self.nTotSpins**.25)

        self.t = 0.000
        
        self.dt = .001*self.nTotSpins**.25
        self.dtUpperLimit = int(3000*self.nTotSpins**.33)+1       # could model settings as maxwell boltzmann distribution for speed optimization

        self.innerLoopDuty = int(50*self.nTotSpins**-.5)+1        # Number of cycles per animation frame  
        self.outerLoopDuty = int(4*self.nTotSpins**-.5)+1         # Number of cycles per update (for other features such as k space)


        
        self.togglePointsVar = BooleanVar()
        self.toggleTracersVar = BooleanVar()
        self.toggleSphereVectorsVar = BooleanVar()
        self.toggleAxisVar = BooleanVar() 
        self.toggleAxisSyncVar = BooleanVar()

        self.toggleUCVectorsVar = BooleanVar()

        self.togglePhasePointsVar = BooleanVar()
        self.toggleAnglePlotVar = BooleanVar()




        self.togglePointsVar.set(0)
        self.toggleTracersVar.set(1)
        self.toggleSphereVectorsVar.set(0)
        self.toggleAxisVar.set(0)
        self.toggleAxisSyncVar.set(0)
        
        self.toggleUCVectorsVar.set(1)
        
        self.togglePhasePointsVar.set(0)
        self.toggleAnglePlotVar.set(0)
        



        self.nUC = NumericUnitCell(self.nSpinsX,self.nSpinsY)
        self.vUC = VisualUnitCell(self.nSpinsX,self.nSpinsY)
       
        self.vSphere = VisualSphere(self.nSpinsX,self.nSpinsY)

        self.phaseSpace = PhaseSpace(self.nSpinsX,self.nSpinsY)
        self.anglePlot = AnglePlot(self.nSpinsX,self.nSpinsY)



        
        self.nUC.setCouplings(self.Ja, self.Jbx, self.Jby, self.stripeSpacingX, self.stripeSpacingY)
        self.nUC.setState(self.k, self.baseSigma)

        
        spinSphereW.select()
        self.vSphere.addPoints(self.nUC.getState())
        self.vSphere.addTracers(self.nUC.getState())
        self.vSphere.addVectors(self.nUC.getState())


        spinUnitCellW.select()
        self.vUC.addVectors(self.nUC.getState())
        self.vUC.addAxis()

     
##        anglePlotW.select()
##        self.anglePlot.addCurves(self.nUC.getState(),self.t)
       
       
        thread.start_new_thread(self.animSpins,(self.innerLoopDuty,self.outerLoopDuty))
        self.pause = 0





    def animSpins(self,innerLoopDuty,outerLoopDuty):
        print '-----------------------------'
        print "Animation Started"
        print time.ctime()
        
        print 'Inner Loop Duty', innerLoopDuty
        print 'Outer Loop Duty', outerLoopDuty


        while 1:
            self.paused = self.pause
            if self.paused != 1:
                for k in range(outerLoopDuty):
                    for k in range(innerLoopDuty):
                        self.nUC.getMeanFields()

                        if self.MFu != 0.0 or self.MFd != 0.0:      self.nUC.addExternalField(self.MFu,self.MFd)

                        self.nUC.getTorques()             
                        self.nUC.timeEvolve(self.dt)
                        self.nUC.normalizeState()

                        currentState = self.nUC.getState()

                    if self.temp != 0.0:                            self.nUC.thermalize(self.temp)
                    
                    if self.toggleSphereVectorsVar.get() == 1:      self.vSphere.updateVectors(currentState)
                    if self.toggleTracersVar.get() == 1:            self.vSphere.updateTracers(currentState)
                    if self.togglePointsVar.get() == 1:             self.vSphere.updatePoints(currentState)

                if self.togglePhasePointsVar.get() == 1:        self.phaseSpace.addPoint(currentState)
                if self.toggleAnglePlotVar.get() == 1:          self.anglePlot.updateCurves(currentState, self.t)
                
                if self.toggleAxisSyncVar.get() == 1:           self.vSphere.updateViewAxis(self.nUC.getCommonAxis())
                if self.toggleAxisVar.get() == 1:               self.vSphere.updateAxis(norm(self.nUC.getCommonAxis()))
                
                if self.toggleUCVectorsVar.get() == 1:          self.vUC.updateVectors(currentState)

                self.t += self.dt


            


                
                




    def setJbx(self, Jbx):
        self.hold()
        self.Jbx = float(Jbx)
        self.nUC.setCouplings(self.Ja, self.Jbx, self.Jby, self.stripeSpacingX, self.stripeSpacingY)
        self.unhold()

    def setJby(self, Jby):
        self.hold()
        self.Jby = float(Jby)
        self.nUC.setCouplings(self.Ja, self.Jbx, self.Jby, self.stripeSpacingX, self.stripeSpacingY)
        self.unhold()


    def setMFu(self, MFd):
        self.hold()
        self.MFd = float(MFd)
        self.unhold()

    def setMFd(self, MFu):
        self.hold()
        self.MFu = float(MFu)
        self.unhold()

        
    def setTemp(self, temp):
        self.hold()
        self.temp = float(temp)*self.Ja
        self.unhold()

    def setDt(self, dt):
        self.hold()
        self.dt = float(dt)/1000000.0
        self.unhold()







    def randomize(self):
        self.hold()
        self.nUC.randomizeState()
        self.unhold()


    def reset(self):
        self.hold()

        self.t = 0.000
        
        self.nUC.setState(self.k, self.baseSigma)
        self.vSphere.resetTracers()

        self.phaseSpace.resetPoints()
        
        self.unhold()







    def hold(self):
        self.pause = 1
        while self.paused == 0: pass

    def unhold(self):
        self.pause = 0











    def togglePoints(self):
        self.hold()
        self.vSphere.togglePoints()
        self.unhold()
        
    def toggleVectors(self):
        self.hold()
        self.vSphere.toggleVectors()
        self.unhold()

    def toggleUCVectors(self):
        self.hold()
        self.vUC.toggleVectors()
        self.unhold()

    def toggleTracers(self):
        self.hold()
        self.vSphere.toggleTracers()
        self.unhold()

    def toggleAxis(self):
        self.hold()
        self.vSphere.toggleAxis()
        self.unhold()

    def toggleAxisSync(self):
        pass

    def togglePhasePoints(self):
        pass

    def toggleAnglePlot(self):
        self.t = 0.000
        pass
        

##    def setTracerLength(self, tracerLength):
##        self.hold()
##        self.tracerLength = float(tracerLength)
##        self.unhold()



