// $Id: Field.java,v 1.2 2004/02/27 16:30:01 m31 Exp $
//
// This file is part of the program suite "Principia Mathematica II"
// which is a working prototype for the main project:
// "Hilbert II" - http://www.qedeq.org
//
// Copyright 2001-2004  Michael Meyling <mime@qedeq.org>.
//
// "Principia Mathematica II" is free software; you can redistribute
// it and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

package com.meyling.principia.gui.puzzle;


import javax.swing.*;

import java.awt.*;
import java.util.*;
import java.awt.event.*;

/**
 * Malt Quadrate.
 *
 * @version     $Revision: 1.2 $
 * @author      Michael Meyling
 */
class Field extends JPanel {

    /**
     * Breite eines Quadrats.
     */
    private int w;

    /**
     * Höhe eines Quadrates.
     */
    private int h;

    public int inside = 0;

    public boolean success = false;

    /**
     * Gerade ausgewähltes Stück.
     */
    int type = -1;

    Figure fig[];

    boolean old = false;

    int xo;
    int yo;

    int matrix[][];
    int position[][];
    final Color col[] = {Color.red, Color.green, Color.blue, Color.black, Color.yellow, Color.cyan,
        Color.gray, Color.orange, Color.pink, Color.magenta, Color.darkGray, Color.red};

    Puzzle parent;

    Field(Puzzle p, int x, int y, int width, int height) {

        int i, j;
        final int dim[][][] = {{
            {0, 0, 0, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 1, 1, 1, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 0, 0, 0}
            },{
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0}
            },{
            {0, 0, 0, 0, 0},
            {0, 1, 0, 1, 0},
            {0, 1, 1, 1, 0},
            {0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0}
            },{
            {0, 0, 0, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 1, 1, 1, 0},
            {0, 0, 0, 0, 0}
            },{
            {0, 0, 0, 0, 0},
            {0, 1, 0, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 0, 1, 1, 0},
            {0, 0, 0, 0, 0}
            },{
            {0, 0, 0, 0, 0},
            {0, 0, 0, 1, 0},
            {0, 1, 1, 1, 0},
            {0, 1, 0, 0, 0},
            {0, 0, 0, 0, 0},
            },{
            {0, 0, 0, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 0, 1, 1, 0},
            {0, 0, 0, 0, 0}
            },{
            {0, 0, 0, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 0, 0, 0, 0}
            },{
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 1, 0},
            {0, 0, 0, 0, 0}
            },{
            {0, 1, 0, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 0, 0, 0}
            },{
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 1, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 0, 0, 0}
            },{
            {0, 0, 0, 0, 0},
            {0, 1, 0, 0, 0},
            {0, 1, 0, 0, 0},
            {0, 1, 1, 1, 0},
            {0, 0, 0, 0, 0}
            }};

        parent = p;

        w = (width-1) / 24;
        h = (height-1) / 15;
        reshape(x, y, w*24+1, h*15+1);

        final Vector figurs = new Vector();
        for (i=0; i<6; i++) {
            figurs.add(new Figure(dim[i], col[i]));
        }
        for (i=6; i<12; i++) { /* no mirrow symmetry */
            figurs.add(new Figure(dim[i], col[i], true));
        }
        fig = new Figure[12];
        figurs.copyInto(fig);

        matrix = new int [24][15];
        position = new int [24][15];

        for (i=0; i<24; i++) {
            for (j=0; j<15; j++){
                matrix[i][j]=-1;
            }
        }
        for (i=0; i<6; i++) {
            for (j=0; j<5; j++){
                matrix[i*4 + fig[i].xpos[j]][fig[i].ypos[j]] = i;
                position[i*4 + fig[i].xpos[j]][fig[i].ypos[j]] = j;
            }
        }
        for (i=0; i<6; i++) {
            for (j=0; j<5; j++){
                matrix[i*4 + fig[i+6].xpos[j]][fig[i+6].ypos[j]+5] = i+6;
                position[i*4 + fig[i+6].xpos[j]][fig[i+6].ypos[j]+5] = j;
            }
        }
        this.addMouseListener(new FieldMouseListener());
        this.addMouseMotionListener(new FieldMouseMotionListener());
    }


    boolean isInside(int x, int y){

        return (y >= 10 && x >= 6 && x < 18);

    }


    void checkSuccess() {

        if (success = inside == 60){
            repaint();
        }
    }


    public void paint(Graphics g) {

        int i, j;

        if (old && type>=0) {
            fig[type].paintXFigure(g, xo, yo, w, h);
            old = false;
        }
        g.setPaintMode();
        for (i=0; i<24; i++) {
            for (j=0; j<15; j++) {
                if (matrix[i][j]<0) {
                    if (isInside(i,j)) {
                        g.setColor(new Color(240, 240, 240));
                    }
                    else {
                        g.setColor(Color.white);
                    }
                }
                else {
                    g.setColor(col[matrix[i][j]]);
                }
                g.fillRect(i*w, j*h, w, h);
                g.setColor(Color.black);
                g.drawRect(i*w, j*h, w, h);
            }
        }
        if (success){
//            g.setColor(Color.red);
//            g.fillRect(0,0,24*w,15*h);
            g.drawString("Herzlichen Glückwunsch!", 9*w, 6*h - 4);
        }
    }

    public void reshape(int x, int y, int width, int height){

        w = (width-1) / 24;
        h = (height-1) / 15;
        super.reshape(x, y, w*24+1, h*15+1);
    }


    private class Figure {


        Color color;
        public int xpos[];
        public int ypos[];
        int turns;

        Figure(int matrix[][], Color col){

            int i,j,k=0;

            turns = -1;
            color = col;
            xpos = new int[5];
            ypos = new int[5];

            for (i=0; i<5; i++){
                for (j=0; j<5; j++){
                    if (matrix[i][j] == 1){
                        xpos[k] = j;
                        ypos[k++] = i;
                    }
                }
            }
        }

        Figure(int matrix[][], Color col, boolean t){

            this(matrix, col);
            if (t) turns = 0;
        }

        public void paintXFigure(Graphics g, int x, int y, int w, int h){

            int i;

            g.setXORMode(Color.red);
            for (i=0; i<5; i++){
                g.drawRect( x+(w*(2*xpos[i]-5))/2, y+(h*(2*ypos[i]-5))/2, w, h);
            }
        }

        public void paintFigure(Graphics g, int x, int y, int w, int h){

            int i;

            g.setPaintMode();
            g.setColor(color);
            for (i=0; i<5; i++){
                g.fillRect( x*w+1+w*xpos[i], y*h+1+h*ypos[i], w-1, h-1);
            }
        }

        public void paintFigureBack(Graphics g, int x, int y, int w, int h){

            int i;

            g.setPaintMode();
            for (i=0; i<5; i++) {
                if (y+ypos[i]>=10 && x+xpos[i] >= 6 && x+xpos[i] < 18) {
                    g.setColor(new Color(240, 240, 240));
                }
                else {
                    g.setColor(Color.white);
                }
                g.fillRect( x*w+1+w*xpos[i], y*h+1+h*ypos[i], w-1, h-1);
            }
        }

        public void turn(){

            int i, x,y;

            if (turns >= 0 && turns++ < 4){
                for (i=0; i<5; i++) {
                    x = xpos[i] - 2;
                    y = ypos[i] - 2;
                    xpos[i] = -y + 2;
                    ypos[i] = x + 2;
                }
            }
            else {
                for (i=0; i<5; i++) {
                    x = xpos[i] - 2;
                    y = ypos[i] - 2;
                    xpos[i] = -y + 2;
                    ypos[i] = -x + 2;
                }
                turns = 0;
            }
        }
    }



    private class FieldMouseMotionListener extends MouseMotionAdapter {
        public void mouseMoved(MouseEvent event) {
            Graphics g = Field.this.getGraphics();

            if (type >= 0) {
                if (old) {
                    fig[type].paintXFigure(g, xo, yo, w, h);
                }
                else {
                    old = true;
                }
                fig[type].paintXFigure(g, event.getX(), event.getY(), w, h);
                xo = event.getX();
                yo = event.getY();
            }
        }
        public void mouseDragged(MouseEvent event) {
            mouseMoved(event);
        }
    }



    private class FieldMouseListener extends MouseAdapter {

        public void mousePressed(MouseEvent event) {

            Graphics g = Field.this.getGraphics();
            int xn, yn;
            int i,j,k;
            boolean ok;

            if (type >= 0) {
                if (old) {
                    fig[type].paintXFigure(g, xo, yo, w, h);
                    old = false;
                }
                if (SwingUtilities.isMiddleMouseButton(event)
                    || SwingUtilities.isRightMouseButton(event)
                    || event.isShiftDown() || event.isControlDown()) {
                    fig[type].turn();
                    fig[type].paintXFigure(g, event.getX(), event.getY(), w, h);
                    xo = event.getX();
                    yo = event.getY();
                    old = true;
                }
                else {
                    xn = event.getX();
                    yn = event.getY();
                    xn = xn/w-2;
                    yn = yn/h-2;
                    ok = true;
                    for (i = 0; i<5; i++) {
                        j = fig[type].xpos[i]+xn;
                        k = fig[type].ypos[i]+yn;
                        if (0>j || j>=24 || 0>k || k>=15) {
                            ok = false;
                            break;
                        }
                        if (matrix[j][k]>=0) {
                            ok = false;
                            break;
                        }
                    }
                    if (ok) {
                        for (i = 0; i < 5; i++) {
                            j = fig[type].xpos[i]+xn;
                            k = fig[type].ypos[i]+yn;
                            if (0<=j && j<24 && 0<=k && k<15) {
                                matrix[j][k] = type;
                                position[j][k] = i;
                                if (isInside(j,k)) inside++;
                            }
                        }
                        fig[type].paintFigure(g, xn, yn, w, h);
                        type = -1;
                    }
                    else {
                        fig[type].paintXFigure(g, event.getX(), event.getY(), w, h);
                        xo = event.getX();
                        yo = event.getY();
                        old = true;
                    }
                }
            } else {
                if (old) {
                    fig[type].paintXFigure(g, xo, yo, w, h);
                    old = false;
                }
                xn = event.getX();
                yn = event.getY();
                xn = xn/w;
                yn = yn/h;
                j = xn;
                k = yn;
                if (0 <= j && j < 24 && 0 <= k && k < 15) {
                    type = matrix[j][k];
                }
                if (type >= 0) {
                    xn = j - fig[type].xpos[position[j][k]];
                    yn = k - fig[type].ypos[position[j][k]];
                    for (i = 0; i<5; i++) {
                        j = fig[type].xpos[i]+xn;
                        k = fig[type].ypos[i]+yn;
                        if (0<=j && j<24 && 0<=k && k<15) {
                            matrix[j][k] = -1;
                            position[j][k] = 0;
                            if (isInside(j,k)) inside--;
                        }
                    }
                    fig[type].paintFigureBack(g, xn, yn, w, h);
                    xn = (xn + 2) * w + w/2;
                    yn = (yn + 2) * h + h/2;
    /*                fig[type].paintXFigure(g, xn, yn, w, h);
                    xo = xn;
                    yo = yn;
                    old = true;
    */            }
            }
            checkSuccess();
        }

        public void mouseExited(MouseEvent event) {

            final Graphics g = Field.this.getGraphics();

            if (type>=0 && old) {
                fig[type].paintXFigure(g, xo, yo, w, h);
                old = false;
            }
        }



    }



}



