import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
 * Created on 12-mar-2006
 *
 */
public class Ten4TenGame extends Thread {

    public static final String LOG_FILE_NAME = "/home/antonio/ten4tengame.log";

    int[][] currentMatrix = new int[10][10];

    int[] path = new int[100];

    int depth = 0;

    BufferedWriter fout;

    boolean LOG_ENABLED = true;

    int topNumber = 0;

    /**
     * se si rendesse necessario forzare una situazione di stallo
     */
    private int forceReturn = 0;

    public Ten4TenGame() throws IOException {
        super();

        // this.fout = new BufferedWriter(
        // new FileWriter(Ten4TenGame.LOG_FILE_NAME));
        for (int i = 0; i < this.currentMatrix.length; i++) {
            for (int j = 0; j < currentMatrix[i].length; j++) {
                currentMatrix[i][j] = 0;
            }
        }
    }

    private boolean isValidIndex(int x, int y) {
        if (x >= 0 && x < 10) {
            if (y >= 0 && y < 10) {
                return true;
            }
        }
        return false;
    }

    private void doStep(int x, int y, int nextNumber) {
        if (this.isValidIndex(x, y)) {
            if (this.currentMatrix[x][y] == 0) {
                this.currentMatrix[x][y] = nextNumber;

                if (nextNumber > this.topNumber) {
                    this.topNumber = nextNumber;
                    // this.printMatrix(nextNumber);
                }
                if (nextNumber > 99) {
                    this.printMatrix(nextNumber);
                }

                this.step(x, y, nextNumber);
                this.currentMatrix[x][y] = 0;
            }
        }
    }

    private void upsx(int x, int y, int nextNumber) {
        int x1 = x - 2;
        int y1 = y - 2;
        this.doStep(x1, y1, nextNumber);
    }

    private void up(int x, int y, int nextNumber) {
        int x1 = x;
        int y1 = y - 3;
        this.doStep(x1, y1, nextNumber);
    }

    private void updx(int x, int y, int nextNumber) {
        int x1 = x + 2;
        int y1 = y - 2;
        this.doStep(x1, y1, nextNumber);
    }

    private void left(int x, int y, int nextNumber) {
        int x1 = x - 3;
        int y1 = y;
        this.doStep(x1, y1, nextNumber);
    }

    private void right(int x, int y, int nextNumber) {
        int x1 = x + 3;
        int y1 = y;
        this.doStep(x1, y1, nextNumber);
    }

    private void downsx(int x, int y, int nextNumber) {
        int x1 = x - 2;
        int y1 = y + 2;
        this.doStep(x1, y1, nextNumber);
    }

    private void down(int x, int y, int nextNumber) {
        int x1 = x;
        int y1 = y + 3;

        this.doStep(x1, y1, nextNumber);
    }

    private void downdx(int x, int y, int nextNumber) {
        int x1 = x + 2;
        int y1 = y + 2;
        this.doStep(x1, y1, nextNumber);
    }

    /**
     * stampa per tutti i livelli il numero del ramo che si sta ispezionando
     * (valore da 1 a 8)
     */
    private void printStatus(int[] oldPath) {
        int[] currentPath = this.path.clone();
        for (int i = 0; i < currentPath.length; i++) {
            if (currentPath[i] != oldPath[i]) {
                System.out.print("Change on level: " + i);
                System.out.println("; Top Number is: " + this.topNumber);
                return;
            } else {
                // System.out.print("p" + i + ":" + this.path[i] + ";");
            }
        }
        // System.out.println("");
    }

    /**
     * esegue un passo di elaborazione, è una funzione ricorsiva che seleziona
     * in ordine tutte i possibili movimenti, sarà poi il metodo dei movimenti a
     * verificare se è possibile muoversi in quella direzioen
     * 
     * @param x
     *            coordinata x sulla matrice
     * @param y
     *            coordinata y sulla matrice
     * @param currentNumber
     *            ultimo numero posizionato nella matrice
     */
    private void step(int x, int y, int currentNumber) {
        this.depth += 1;

        int nextNumber = ++currentNumber;
        if (this.depth < 100) {
            this.path[depth] = 1;
            this.up(x, y, nextNumber);
            if (this.forceReturn > 0) {
                this.forceReturn -= 1;
                return;
            }

            this.path[depth] = 2;
            this.left(x, y, nextNumber);
            if (this.forceReturn > 0) {
                this.forceReturn -= 1;
                return;
            }

            this.path[depth] = 3;
            this.down(x, y, nextNumber);
            if (this.forceReturn > 0) {
                this.forceReturn -= 1;
                return;
            }

            this.path[depth] = 4;
            this.right(x, y, nextNumber);
            if (this.forceReturn > 0) {
                this.forceReturn -= 1;
                return;
            }

            this.path[depth] = 5;
            this.upsx(x, y, nextNumber);
            if (this.forceReturn > 0) {
                this.forceReturn -= 1;
                return;
            }

            this.path[depth] = 6;
            this.downsx(x, y, nextNumber);
            if (this.forceReturn > 0) {
                this.forceReturn -= 1;
                return;
            }

            this.path[depth] = 7;
            this.updx(x, y, nextNumber);
            if (this.forceReturn > 0) {
                this.forceReturn -= 1;
                return;
            }

            this.path[depth] = 8;
            this.downdx(x, y, nextNumber);
            if (this.forceReturn > 0) {
                this.forceReturn -= 1;
                return;
            }
        } else {
            System.out.println("");
            //System.out.println("Gloal Reached");
        }

        this.depth -= 1;
    }

    /**
     * stampa a monitor la matrice corrente
     * 
     * @param nextNumber
     */
    private void printMatrix(int nextNumber) {
        System.out.println("-maxNumber: " + nextNumber
                + "---------------------------");
        for (int i = 0; i < this.currentMatrix.length; i++) {
            System.out.print("|");
            for (int j = 0; j < this.currentMatrix[i].length; j++) {
                if (this.currentMatrix[i][j] < 10) {
                    System.out.print(" ");
                }
                if (this.currentMatrix[i][j] < 100) {
                    System.out.print(" ");
                }
                System.out.print(this.currentMatrix[i][j] + ",");
            }
            System.out.println("|");
        }
        System.out.println("------------------------------------------");
    }

    @Override
    public void run() {
        super.run();
        while (true) {
            int[] oldPath = this.path.clone();

            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            this.printStatus(oldPath);
        }
    }

    public void startFromCoordinates(int x, int y) {
        try {

            System.out.println("Starting from coordinate: (" + x + "," + y + ")");
            this.currentMatrix[x][y] = 1;
            this.step(x, y, 1);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * @param arg
     *            nessun argomento
     * @throws IOException
     * @throws FileNotFoundException
     *             se non può scrivere il file di log, stampa l'errore e esce
     */
    public static void main(String[] args) throws IOException {
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                Ten4TenGame tt = new Ten4TenGame();
                //tt.start();
                tt.startFromCoordinates(i, j);
                // tt[((i+1)*(j+1))-1] = new Ten4TenGame();
                // tt[((i+1)*(j+1))-1].start();
                // tt[((i+1)*(j+1))-1].startFromCoordinates(i,j);
            }
        }

    }

}
