import java.awt.*;
import javax.swing.*;

public class BoardPanel extends JPanel
{
    ComradesFrame CF;
    int CLICKED_x = 0;
    int CLICKED_y = 0;
    int CLICKED_b = 0;
    boolean CLICKED = false;
    Color WHITE_PIECES, BLACK_PIECES, LIGHT_SQUARES, DARK_SQUARES;
    Color CASTLING_COLOR, BACK_GROUND, MOVE_ARROWS, YELLOW_BUTTON, CLICKED_COLOR;
    Color WHITE_MOVE_INDICATOR, BLACK_MOVE_INDICATOR, EN_PASSANT_COLOR;
    boolean WHITE_ALL_OUTLINE, BLACK_ALL_OUTLINE, WHITE_HALF_OUTLINE, BLACK_HALF_OUTLINE, WHITE_MATERIAL_OUTLINE, BLACK_MATERIAL_OUTLINE;
    int SIZE;

    public BoardPanel (ComradesFrame cf)
    {
	super ();
	CF = cf;
	SIZE = CF.SIZE; 
	ImportColors ();
   }

    public Dimension getPreferredSize ()
    {
	return new Dimension (400, 400);
    }

    public Dimension getMinimumSize ()
    {
	return new Dimension (400, 400);
    }

    public Dimension getMaximumSize ()
    {
	return new Dimension (405, 400); // valid ?
    }

    public void ImportColors ()
    {
	WHITE_PIECES = CF.WHITE_PIECES;
	BLACK_PIECES = CF.BLACK_PIECES;
	LIGHT_SQUARES = CF.LIGHT_SQUARES;
	DARK_SQUARES = CF.DARK_SQUARES;
	BACK_GROUND = CF.BACK_GROUND;
	CASTLING_COLOR = CF.CASTLING_COLOR;
	MOVE_ARROWS = CF.MOVE_ARROWS;
	YELLOW_BUTTON = CF.YELLOW_BUTTON;
	CLICKED_COLOR = CF.CLICKED_COLOR;
	WHITE_MOVE_INDICATOR = CF.WHITE_MOVE_INDICATOR;
	BLACK_MOVE_INDICATOR = CF.BLACK_MOVE_INDICATOR;
	EN_PASSANT_COLOR = CF.EN_PASSANT_COLOR;
        WHITE_ALL_OUTLINE = CF.WHITE_ALL_OUTLINE;
        BLACK_ALL_OUTLINE = CF.BLACK_ALL_OUTLINE;
        WHITE_HALF_OUTLINE = CF.WHITE_HALF_OUTLINE;
        BLACK_HALF_OUTLINE = CF.BLACK_HALF_OUTLINE;
        WHITE_MATERIAL_OUTLINE = CF.WHITE_MATERIAL_OUTLINE;
        BLACK_MATERIAL_OUTLINE = CF.BLACK_MATERIAL_OUTLINE;
    }

    public void DrawCastling (Graphics G)
    {
	BoardPosition BP = CF.BOARD_POSITION;
	G.setColor (CASTLING_COLOR);
	int u = (CF.REVERSE ? 4 : 5); // file
	if ((!CF.REVERSE && BP.WhiteOOO) || (CF.REVERSE && BP.BlackOO))
	    {
		G.drawLine (u * SIZE + SIZE / 2, 9 * SIZE + SIZE / 4,
			    u * SIZE + 7, 9 * SIZE + SIZE / 4);
		G.drawLine (u * SIZE + SIZE / 2, 9 * SIZE + SIZE / 4 - 1,
			    u * SIZE + 7, 9 * SIZE + SIZE / 4 - 1);
		G.drawLine (u * SIZE + 7, 9 * SIZE + SIZE / 4,
			    u * SIZE + 12, 9 * SIZE + 5);
		G.drawLine (u * SIZE + 7, 9 * SIZE + SIZE / 4 - 1,
			    u * SIZE + 12, 9 * SIZE + 6);
		G.drawLine (u * SIZE + 7, 9 * SIZE + SIZE / 4 - 1,
			    u * SIZE + 12, 9 * SIZE + SIZE / 2 - 6);
		G.drawLine (u * SIZE + 7, 9 * SIZE + SIZE / 4,
			    u * SIZE + 12, 9 * SIZE + SIZE / 2 - 7);
	    }	    
	if ((!CF.REVERSE && BP.WhiteOO) || (CF.REVERSE && BP.BlackOOO))
	    {
		G.drawLine (u * SIZE + SIZE / 2, 9 * SIZE + SIZE / 4,
			    (u + 1) * SIZE - 7, 9 * SIZE + SIZE / 4);
		G.drawLine (u * SIZE + SIZE / 2, 9 * SIZE + SIZE / 4 - 1,
			    (u + 1) * SIZE - 7, 9 * SIZE + SIZE / 4 - 1);
		G.drawLine ((u + 1) * SIZE - 7, 9 * SIZE + SIZE / 4,
			    (u + 1) * SIZE - 12, 9 * SIZE + 5);
		G.drawLine ((u + 1) * SIZE - 7, 9 * SIZE + SIZE / 4 - 1,
			    (u + 1) * SIZE - 12, 9 * SIZE + 6);
		G.drawLine ((u + 1) * SIZE - 7, 9 * SIZE + SIZE / 4 - 1,
			    (u + 1) * SIZE - 12, 9 * SIZE + SIZE / 2 - 6);
		G.drawLine ((u + 1) * SIZE - 7, 9 * SIZE + SIZE / 4,
			    (u + 1) * SIZE - 12, 9 * SIZE + SIZE / 2 - 7);
	    }	    
	if ((!CF.REVERSE && BP.BlackOOO) || (CF.REVERSE && BP.WhiteOO))
	    {
		G.drawLine (u * SIZE + SIZE / 2, 3 * SIZE / 4 + 1,
			    u * SIZE + 7, 3 * SIZE / 4 + 1);
		G.drawLine (u * SIZE + SIZE / 2, 3 * SIZE / 4,
			    u * SIZE + 7, 3 * SIZE / 4);
		G.drawLine (u * SIZE + 7, 3 * SIZE / 4,
			    u * SIZE + 12, SIZE - 5);
		G.drawLine (u * SIZE + 7, 3 * SIZE / 4 + 1,
			    u * SIZE + 12,  SIZE - 6);
		G.drawLine (u * SIZE + 7, 3 * SIZE / 4 + 1,
			    u * SIZE + 12, SIZE / 2 + 6);
		G.drawLine (u * SIZE + 7, 3 * SIZE / 4,
			    u * SIZE + 12, SIZE / 2 + 7);
	    }	    
	if ((!CF.REVERSE && BP.BlackOO) || (CF.REVERSE && BP.WhiteOOO))
	    {
		G.drawLine (u * SIZE + SIZE / 2, 3 * SIZE / 4 + 1,
			    (u + 1) * SIZE - 7, 3 * SIZE / 4 + 1);
		G.drawLine (u * SIZE + SIZE / 2, 3 * SIZE / 4,
			    (u + 1) * SIZE - 7, 3 * SIZE / 4);
		G.drawLine ((u + 1) * SIZE - 7, 3 * SIZE / 4,
			    (u + 1) * SIZE - 12, SIZE - 5);
		G.drawLine ((u + 1) * SIZE - 7, 3 * SIZE / 4 + 1,
			    (u + 1) * SIZE - 12,  SIZE - 6);
		G.drawLine ((u + 1) * SIZE - 7, 3 * SIZE / 4 + 1,
			    (u + 1) * SIZE - 12, SIZE / 2 + 6);
		G.drawLine ((u + 1) * SIZE - 7, 3 * SIZE / 4,
			    (u + 1) * SIZE - 12, SIZE / 2 + 7);
	    }	    
    }

    public void DrawMoveArrows (Graphics G)
    {
	G.setColor (MOVE_ARROWS);
	MoveTree MT = CF.BOARD_POSITION.MOVE_TREE;
	if (MT.NOW != MT.ROOT)
	    {
		G.drawLine (SIZE - 5, 9 * SIZE + SIZE / 2, 5, 9 * SIZE + SIZE / 2);
		G.drawLine (5, 9 * SIZE + SIZE / 2, SIZE / 2, 9 * SIZE + 7);
		G.drawLine (5, 9 * SIZE + SIZE / 2, SIZE / 2, 10 * SIZE - 7);
	    }
	if (MT.NOW.getChildCount () > 0)
	    {
		G.drawLine (10 * SIZE - 5, 9 * SIZE + SIZE / 2, 9 * SIZE + 5, 9 * SIZE + SIZE / 2);
		G.drawLine (10 * SIZE - 5, 9 * SIZE + SIZE / 2, 9 * SIZE + SIZE / 2, 9 * SIZE + 7);
		G.drawLine (10 * SIZE - 5, 9 * SIZE + SIZE / 2, 9 * SIZE + SIZE / 2, 10 * SIZE - 7);
	    }
    }

    public void DrawSquares (Graphics G, BoardPosition BP)
    {
	int OFF_SET = CF.SIZE;
	for (int i = 0; i < 8; i++)
	    for (int j = 0; j < 8; j++)
		{
		    if ((i + j) % 2 == 0)
			G.setColor (LIGHT_SQUARES);
		    else
			G.setColor (DARK_SQUARES);
		    G.fillRect (SIZE * i + OFF_SET, SIZE * j + OFF_SET, SIZE, SIZE);
		}
	G.setColor (Color.black); // verity ?
	G.drawLine (OFF_SET - 1, OFF_SET - 1, OFF_SET - 1, OFF_SET + SIZE * 8);
	G.drawLine (OFF_SET - 1, OFF_SET - 1, OFF_SET + SIZE * 8, OFF_SET - 1);
	G.drawLine (OFF_SET + SIZE * 8, OFF_SET + SIZE * 8,
		    OFF_SET + SIZE * 8, OFF_SET - 1);
	G.drawLine (OFF_SET + SIZE * 8, OFF_SET + SIZE * 8,
		    OFF_SET - 1, OFF_SET + SIZE * 8);
	if (BP.EnPassant != 0)
	    {
		G.setColor (EN_PASSANT_COLOR);
		if (CF.REVERSE)
		    {
			int u = 9 - BP.EnPassant;
			if (BP.WTM)
			    G.fillArc (u * SIZE + 8, 6 * SIZE + 8,
				       SIZE - 17, SIZE - 17, 0, 360);
			else
			    G.fillArc (u * SIZE + 8, 3 * SIZE + 8,
				       SIZE - 17, SIZE - 17, 0, 360);
		    }
		else
		    {
			if (BP.WTM)
			    G.fillArc (BP.EnPassant * SIZE + 8, 3 * SIZE + 8,
				       SIZE - 17, SIZE - 17, 0, 360);
			else
			    G.fillArc (BP.EnPassant * SIZE + 8, 6 * SIZE + 8,
				       SIZE - 17, SIZE - 17, 0, 360);
		    }
	    }
    }

    public void DrawWhiteBlackIndicator (Graphics G, BoardPosition BP)
    {
        if (!CF.SET_UP)
	    {
		if (BP.WTM)
		    {
			G.setColor (WHITE_MOVE_INDICATOR);
			if (!CF.REVERSE)
			    G.fillArc (3, 8 * SIZE + 3, SIZE - 7, SIZE - 7, 0, 360);
			else
			    G.fillArc (3, SIZE + 3, SIZE - 7, SIZE - 7, 0, 360);
		    }
		else
		    {
			G.setColor (BLACK_MOVE_INDICATOR);
			if (!CF.REVERSE)
			    G.fillArc (3, SIZE + 3, SIZE - 7, SIZE - 7, 0, 360);
			else
			    G.fillArc (3, 8 * SIZE + 3, SIZE - 7, SIZE - 7, 0, 360);
		    }
	    }
	else
	    {
		if (BP.WTM)
		    G.setColor (Color.white);
		else
		    G.setColor (new Color (160, 160, 160));
		G.fillArc (3, 5 * SIZE + 3, SIZE - 7, SIZE - 7, 0, 360);
		if (!BP.WTM)
		    G.setColor (Color.black);
		else
		    G.setColor (new Color (160, 160, 160));
		G.fillArc (3, 4 * SIZE + 3, SIZE - 7, SIZE - 7, 0, 360);
	    }
	
    }
    
    public void DrawMaterialImbalance (Graphics G, BoardPosition BP)
    {
	char buffer[] = new char[1];
	int PIECES[] = { 0, 0, 0, 0, 0, 0, 0 };
        char TABLE[] = { 0, 79, 77, 86, 84, 87, 76, 80, 78, 66, 82, 81, 75 };
	G.setFont (CF.chess_font_small);
	for (int i = 1; i <= 8; i++)
	    for (int j = 1; j <= 8; j++)
		{
		    if (BP.AT[i][j] > 0)
			PIECES[BP.AT[i][j]]++;
		    else
			PIECES[-BP.AT[i][j]]--;
		}
	int h = 0, v = (CF.REVERSE ? 2 * SIZE - 2 * SIZE / 3 : 9 * SIZE);
        G.setColor (WHITE_MATERIAL_OUTLINE ? BLACK_PIECES : WHITE_PIECES);
	for (int p = 5; p > 0; p--)
	    for (int i = 0; i < PIECES[p]; i++)
		{
                    buffer[0] = (char) (TABLE[p + (WHITE_MATERIAL_OUTLINE ? 6 : 0)] +  32);
		    G.drawChars (buffer, 0, 1, 9 * SIZE + h, v);
		    h += SIZE / 3;
		    if (SIZE - h < 3)
			{
			    h = 0;
			    if (CF.REVERSE)
				v += SIZE / 3;
			    else
				v -= SIZE / 3;
			}
		}
	G.setColor (BLACK_MATERIAL_OUTLINE ? WHITE_PIECES : BLACK_PIECES);
	h = 0;
	v = (!CF.REVERSE ? 2 * SIZE - 2 * SIZE / 3 : 9 * SIZE);
	for (int p = 5; p > 0; p--)
	    for (int i = 0; i > PIECES[p]; i--)
		{
                    buffer[0] = (char) (TABLE[p + (BLACK_MATERIAL_OUTLINE ? 6 : 0)] +  32);
		    G.drawChars (buffer, 0, 1, 9 * SIZE + h, v);
		    h += SIZE / 3;
		    if (SIZE - h < 3)
			{
			    h = 0;
			    if (!CF.REVERSE)
				v += SIZE / 3;
			    else
				v -= SIZE / 3;
			}
		}
    }
    
    public void DrawMajorBoard (Graphics G, BoardPosition BP)
    {
	int OFF_SET = CF.SIZE;
	char buffer[] = new char[1];
	int ilo = 1, ihi = 8, jlo =1, jhi = 8;
	if (CF.SET_UP)
	    {
		ilo--;
		jlo--;
		ihi++;
		jhi++;
		for (int i = 2; i <= 7; i++)
		    BP.AT[i][0] = i - 1;
		for (int i = 2; i <= 7; i++)
		    BP.AT[i][9] = 1 - i;
		G.setColor (YELLOW_BUTTON);
		G.fillArc (9 * SIZE + 3, 3, SIZE - 7, SIZE - 7, 0, 360);
	    }
	else
	    DrawMaterialImbalance (G, BP);
	G.setFont (CF.chess_font);
	for (int i = ilo; i <= ihi; i++)
	    for (int j = jlo; j <= jhi; j++)
		{
		    int s = BP.AT[i][j];
		    if (s > 0)
			s = -s; // HACK
		    if (BLACK_ALL_OUTLINE && BP.AT[i][j] < 0)
			s = -s;
		    if (WHITE_ALL_OUTLINE && BP.AT[i][j] > 0)
			s = -s;
                    if (BLACK_HALF_OUTLINE && BP.AT[i][j] < 0 && ((i + j) % 2) == 0)
			s = -s;
		    if (WHITE_HALF_OUTLINE && BP.AT[i][j] > 0 && ((i + j) % 2) != 0)
			s = -s;
		    switch (s)
			{
			case 1: buffer[0] = 80 + 32; break;
			case 2: buffer[0] = 78 + 32; break;
			case 3: buffer[0] = 66 + 32; break;
			case 4: buffer[0] = 82 + 32; break;
			case 5: buffer[0] = 81 + 32; break;
			case 6: buffer[0] = 75 + 32; break;
			case -1: buffer[0] = 79 + 32; break;
			case -2: buffer[0] = 77 + 32; break;
			case -3: buffer[0] = 86 + 32; break;
			case -4: buffer[0] = 84 + 32; break;
			case -5: buffer[0] = 87 + 32; break;
			case -6: buffer[0] = 76 + 32; break;
			case 0: default: continue;
			}
		    int horz, vert;
		    if (!CF.REVERSE) // attend ?
			{
			    horz = SIZE * i;
			    vert = SIZE * (9 - j);
			}
		    else
			{
			    horz = SIZE * (9 - i);
			    vert = SIZE * j;
			}
		    if (BP.AT[i][j] > 0)
			G.setColor (WHITE_PIECES);
		    else
			G.setColor (BLACK_PIECES);
		    if (WHITE_ALL_OUTLINE && BP.AT[i][j] > 0)
			G.setColor (BLACK_PIECES);
		    if (BLACK_ALL_OUTLINE && BP.AT[i][j] < 0)
			G.setColor (WHITE_PIECES);
                    if (WHITE_HALF_OUTLINE && BP.AT[i][j] > 0 && ((i + j) % 2) != 0)
                        G.setColor (BLACK_PIECES);
                    if (BLACK_HALF_OUTLINE && BP.AT[i][j] < 0 && ((i + j) % 2) == 0)
                        G.setColor (WHITE_PIECES);

		    G.drawChars (buffer, 0, 1, horz, vert + OFF_SET);
		}
	if (CLICKED)
	    {
		G.setColor (CLICKED_COLOR);
		int x, y;
		if (CF.REVERSE) // HACK
		    {
			x = OFF_SET + SIZE * (9 - CLICKED_x) - 1;
			y = OFF_SET + SIZE * CLICKED_y - 1;
		    }
		else
		    {
			x = OFF_SET + SIZE * CLICKED_x - 1;
			y = OFF_SET + SIZE * (9 - CLICKED_y) - 1;
		    }
		G.drawLine (x, y, x - SIZE + 1, y);
		G.drawLine (x, y, x, y - SIZE + 1);
		G.drawLine (x - SIZE + 1, y - SIZE + 1, x - SIZE + 1, y);
		G.drawLine (x - SIZE + 1, y - SIZE + 1, x, y - SIZE + 1);
	    }
    }

    public void paintComponent (Graphics G)
    {
	BoardPosition BP = CF.BOARD_POSITION;
	G.setColor (BACK_GROUND);
	G.fillRect(0, 0, 1000, 1000);
	DrawSquares (G, BP); // HACK ep
	DrawWhiteBlackIndicator (G, BP);

	char buffer[] = new char[1];
	if (CF.SET_UP)
	    {
		G.setColor (new Color (65, 105, 205));
		G.setFont (new Font ("SansSerif", Font.BOLD, 35));
		buffer[0] = 'C';
		G.drawChars (buffer, 0, 1, 9, 35);
	    }
	DrawMajorBoard (G, BP);
	if (CF.SET_UP)
	    return;
	DrawCastling (G);
	DrawMoveArrows (G);
    }
}

