/*
 * Created on 29/09/2004, 11:51:24
 *
*/
package compphys_640364;

import java.util.Random;
import java.awt.*;

/**
 * @author Patrick Donelan
 * 
 */
public class Lattice {
    public static final int COLD = 0;
    public static final int HOT = 1;
    public static final int SPIN_UP = 1;
    public static final int SPIN_DOWN = -1;
    public int[][] l;
    private Random r;
    private MultiThreadedApplet mta;
    private AppletWorker aw;
    
    public Lattice(MultiThreadedApplet mta, AppletWorker aw){
        this.mta = mta;
        this.aw = aw;
        l = new int[Settings.nx][Settings.ny];
        r = new Random(984861666);
        if (Settings.latticeStartState==COLD) {
            init_cold();
        } else {
            init_hot();
        }
    }
    
    private void init_cold() {
        for (int i=0; i<Settings.nx; i++) {
            for (int j=0; j<Settings.ny; j++) {
               l[i][j]=SPIN_DOWN;
            }
        }
    }
    
    public void init_hot() {
        int randomSpin;
        for (int i=0;i<Settings.nx;i++) {
            for (int j=0; j<Settings.ny; j++) {
                // Randomly generate either 0 or 1
                randomSpin = r.nextInt(2);
                
                if (randomSpin == 0) {
                    randomSpin = SPIN_DOWN;
                } else if (randomSpin == 1) {
                    randomSpin = SPIN_UP;
                } else {
                    System.out.println("Error: Random number generator seems to be broken!");
                }
                l[i][j]=randomSpin;
            }
        }
    }
    
    public void displayLattice() {
        for (int i=0;i<Settings.nx;i++) {
            System.out.print("| ");
            for (int j=0; j<Settings.ny; j++) {
                System.out.print(l[i][j] + " | ");
            }
            System.out.println();
        }
    }
    
    // Performs one random visit for each site in lattice
    public void sweep() {
        for (int i=0; i<Settings.nx*Settings.ny; i++){
            visit();
        }
    }
    
    public void visit() {
        int rx = r.nextInt(Settings.nx);
        int ry = r.nextInt(Settings.ny);
        int north,south,east,west;
        
        // Get neighbouring points (using wrap-around)
        if (ry + 1 == Settings.ny) {
            north = 0;
        } else {
            north = ry + 1;
        }
        if (ry - 1 == -1) {
            south = Settings.ny - 1;
        } else {
            south = ry - 1;
        }
        if (rx + 1 == Settings.nx) {
            east = 0;
        } else {
            east = rx + 1;
        }
        if (rx - 1 == -1) {
            west = Settings.nx - 1;
        } else {
            west = rx - 1;
        }
        
        int epsilon = - l[rx][ry] * (l[rx][north] + l[rx][south] + l[east][ry] + l[west][ry]); 
        double delta_e = -2.0 * epsilon;
        
        if (delta_e < 0){
            flip(rx,ry);
            return;
        }
        if (Math.exp(-Settings.beta * delta_e) > r.nextDouble()){
            flip(rx,ry);
        }
    }
    
    private void flip(int x,int y){
        Graphics g = mta.getGraphics();
        
        if (l[x][y] == SPIN_DOWN){
            g.setColor(Settings.colourUp);
            l[x][y]=SPIN_UP;
        } else {
            g.setColor(Settings.colourDown);
            l[x][y]=SPIN_DOWN;
        }
        
        if (Settings.displayWhileAutomating || aw.thread_status != AppletWorker.AUTOMATING) {
            g.fillRect(Settings.appletBorderX + x*Settings.pointSizeX, 
                       Settings.appletBorderY + y*Settings.pointSizeY, 
                       Settings.pointSizeX, Settings.pointSizeY);
        }
    }
    
    public double magnetisation() {
        double m=0;
        int N = Settings.nx * Settings.ny;
        
        for (int i=0; i<Settings.nx; i++) {
            for (int j=0; j<Settings.ny; j++) {
                m+=l[i][j];
                }
        }
        
        return m = m / N;
    }    
}

