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

import java.io.* ;
import java.net.* ;
import java.util.* ;

/********************************************************************************/
/********************************************************************************/

public class Backgammon extends JFrame {

	/****************************************/

	private ImageIcon blue   = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("blue.png"   ) ) ) ;
	private ImageIcon green  = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("green.png"  ) ) ) ;
	private ImageIcon red    = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("red.png"    ) ) ) ;
	private ImageIcon black  = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("black.png"  ) ) ) ;
	private ImageIcon blank  = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("blank.png"  ) ) ) ;

	private ImageIcon bone   = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("bone.png"   ) ) ) ;
	private ImageIcon btwo   = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("btwo.png"   ) ) ) ;
	private ImageIcon bthree = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("bthree.png" ) ) ) ;
	private ImageIcon bfour  = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("bfour.png"  ) ) ) ;
	private ImageIcon bfive  = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("bfive.png"  ) ) ) ;
	private ImageIcon bsix   = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("bsix.png"   ) ) ) ;

	private ImageIcon gone   = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("gone.png"   ) ) ) ;
	private ImageIcon gtwo   = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("gtwo.png"   ) ) ) ;
	private ImageIcon gthree = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("gthree.png" ) ) ) ;
	private ImageIcon gfour  = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("gfour.png"  ) ) ) ;
	private ImageIcon gfive  = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("gfive.png"  ) ) ) ;
	private ImageIcon gsix   = new ImageIcon( Toolkit.getDefaultToolkit().getImage( Backgammon.class.getResource("gsix.png"   ) ) ) ;

	/****************************************/

	private JTextField ipField    = new JTextField() ;
	private JButton serverButton  = new JButton( "Server" ) ;
	private JButton connectButton = new JButton( "Connect" ) ;
	private JButton donnectButton = new JButton( "Disconnect" ) ;
	private JButton quitButton    = new JButton( "Quit" ) ;
	private JLabel statusLabel    = new JLabel( red ) ;

	/****************************************/

	private MyJPanel board  = new MyJPanel() ;
	private JLabel myDie1   = new JLabel( blank ) ;
	private JLabel myDie2   = new JLabel( blank ) ;
	private JLabel yourDie1 = new JLabel( blank ) ;
	private JLabel yourDie2 = new JLabel( blank ) ;

	/****************************************/

	private int point[] = new int[27] ;// 1-24 = regular points, 25 = my (black's) bar, 26 = your (white's) bar
	private boolean myTurn ;
	private int startPoint ;
	private int d1, d2 ;
	private int doubles ;

	/****************************************/

	private boolean beServer = false ;              //true = server, false = client
	private boolean connected = false ;
	private ServerSocket server ;
	private Socket s ;
	private BufferedReader in ;
	private BufferedWriter out ;

	/********************************************************************************/

	public static void main( String args[] ) {
		Backgammon app = new Backgammon() ;
		app.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE) ;
	}

	/********************************************************************************/

	public Backgammon() {

		super("Backgammon title") ;

		clearBoard() ;

		/****************************************/

		JPanel buttons = new JPanel() ;
		buttons.setLayout( new GridLayout(1,6,1,1) ) ;

		buttons.add( ipField ) ;
		buttons.add( serverButton ) ;
		buttons.add( connectButton ) ;
		buttons.add( donnectButton ) ;
		buttons.add( quitButton ) ;
		buttons.add( statusLabel ) ;

		add( buttons, BorderLayout.NORTH ) ;

		MyNetworkHandler nh = new MyNetworkHandler() ;
		ipField.addActionListener( nh ) ;
		serverButton.addActionListener(nh) ;
		connectButton.addActionListener(nh) ;
		donnectButton.addActionListener(nh) ;
		quitButton.addActionListener(nh) ;

		/****************************************/

		board.setLayout( new GridLayout(3,6) ) ;
		board.setBackground( Color.LIGHT_GRAY ) ;
		add( board, BorderLayout.CENTER ) ;

		myDie1.setVisible(myTurn) ;
		myDie2.setVisible(myTurn) ;
		yourDie1.setVisible(!myTurn) ;
		yourDie2.setVisible(!myTurn) ;

		JPanel leftDie = new JPanel() ;
		leftDie.setOpaque(false) ;
		leftDie.setLayout( new GridLayout(1,2) ) ;
		leftDie.add( myDie1 ) ;
		leftDie.add( myDie2 ) ;

		JPanel rightDie = new JPanel() ;
		rightDie.setOpaque(false) ;
		rightDie.setLayout( new GridLayout(1,2) ) ;
		rightDie.add( yourDie1 ) ;
		rightDie.add( yourDie2 ) ;

		for( int i = 0 ; i < 6 ; i++ ) {
			board.add( new JLabel() ) ;
		}
		board.add( new JLabel() ) ;
		board.add( leftDie ) ;
		board.add( new JLabel() ) ;
		board.add( new JLabel() ) ;
		board.add( rightDie ) ;
		board.add( new JLabel() ) ;
		for( int i = 0 ; i < 6 ; i++ ) {
			board.add( new JLabel() ) ;
		}

		/****************************************/

		setSize(1200,900) ;
		setVisible(true) ;

		/****************************************/
	}

	/********************************************************************************/

	private void clearTurn() {
		myTurn = false ;
		startPoint = 0 ;
		d1 = d2 = 0 ;
		doubles = 0 ;
		myDie1.setIcon( blank ) ;
		myDie2.setIcon( blank ) ;
		yourDie1.setIcon( blank ) ;
		yourDie2.setIcon( blank ) ;
	}

	private void clearBoard() {

		for( int i = 0 ; i < point.length ; i++ ) {
			point[i] = 0 ;
		}

		point[1] = 2 ;
		point[6] = -5 ;
		point[8] = -3 ;
		point[12] = 5 ;
		point[13] = -5 ;
		point[17] = 3 ; 
		point[19] = 5 ;
		point[24] = -2 ;

		yourDie1.setIcon( blank ) ;
		yourDie2.setIcon( blank ) ;

		clearTurn() ;
		repaint() ;
	}

	/********************************************************************************/

	private boolean cantMove() {

		if( point[25] >= 1 )  {
			if( ( d1 != 0 && point[d1] >= -1 ) || ( d2 != 0 && point[d2] >= -1 ) ) { return false ; } else { return true ; }
		}

		for( int i = 1 ; i <= 24 ; i++ ) {
			if( d1 != 0 && i+d1 <= 24 ) { if( point[i] > 0 && point[i+d1] >= -1 ) return false ; }
			if( d2 !=-0 && i+d2 <= 24 ) { if( point[i] > 0 && point[i+d2] >= -1 ) return false ; }
		}

		int maxPoint = 0 ;
		for( int i = 1 ; i <= 24 ; i++ ) {
			if( point[i] > 0 ) {
				maxPoint = i ;
				break ;
			}
		}

		if( 19 <= maxPoint && maxPoint <= 24 && point[25] == 0 ) return false ; //All stone in inner table

		return true ;
	}

	/********************************************************************************/
	/********************************************************************************/

	private class MyNetworkHandler implements ActionListener {

		public void actionPerformed( ActionEvent e ) {

			ServiceThread service = new ServiceThread() ;

			if( e.getSource() == serverButton && ! beServer && ! connected ) {
			       	beServer = true ;
				service.start() ;
			}

			if( e.getSource() == connectButton && ! beServer && ! connected ) {
				beServer = false ;
				service.start() ;
			}

			if( e.getSource() == donnectButton ) {
				service.cstop() ;
			}
			
			if ( e.getSource() == quitButton ) {
				/*
				if( connected ) {
					try {
						out.write("QUIT\n") ;
						out.flush() ;
					} catch( IOException ee ) {
						//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
					}
				}
				*/

				service.cstop() ;
				System.exit(0) ;
			}

		} //actionPerformed

		/********************************************************************************/
		/********************************************************************************/

		private class ServiceThread extends Thread {

			private final int SLEEP = 100 ;

			/****************************************/

			public void run() {

				if( beServer ) {

					try {
						server = new ServerSocket(8888);
						statusLabel.setIcon( blue ) ;
					} catch( IOException ee ) {
						//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
					}

					try {
						s = server.accept();
						server.close() ;

						connected = true ;
						statusLabel.setIcon( green ) ;

						in  = new BufferedReader( new InputStreamReader(  s.getInputStream()  ));
						out = new BufferedWriter( new OutputStreamWriter( s.getOutputStream() ));
						out.flush() ;

					} catch( IOException ee ) {
						//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
					}

				} else {

					try {
						InetAddress inet =  InetAddress.getByName( ipField.getText() ) ;
						s = new Socket( inet, 8888 ) ;
						connected = true ;
					       	statusLabel.setIcon( green ) ;
						
						in  = new BufferedReader( new InputStreamReader(  s.getInputStream()  ));
						out = new BufferedWriter( new OutputStreamWriter( s.getOutputStream() ));
						out.flush() ;

						if( Math.random() < 0.5 )  {
							JOptionPane.showMessageDialog( null, "You go first." ) ;
							myTurn = true ;
							out.write("TURN 0\n") ;
						} else {
							JOptionPane.showMessageDialog( null, "You go second." ) ;
							myTurn = false ;
							out.write("TURN 1\n") ;
						}
						out.flush() ;

					} catch( IOException ee ) {
						//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
					}
				}

				try {

					boolean cont = true ;
					while( cont ) {

						if( in.ready() ) {
						
							String receivedString = in.readLine() ;
						
							Scanner received = new Scanner( receivedString ) ; 
							String request = received.next() ;

							if( request.equals("QUIT") ) {
								cont = false ;
								JOptionPane.showMessageDialog( null, "Your opponent has closed the connection." ) ;
								clearBoard() ;
								repaint() ;
							}

							if( request.equals("TURN")  ) {
								int t = received.nextInt() ;
								if( t == 0 ) {
									myTurn = false ;
									JOptionPane.showMessageDialog( null, "You go second." ) ;
								}
								if( t == 1 ) {
									myTurn = true ;
									JOptionPane.showMessageDialog( null, "You go first." ) ;
								}
							}

							if( request.equals("YOULOSE")  ) {
								JOptionPane.showMessageDialog( null, "YOU LOSE." ) ;
								clearBoard() ;
								myTurn = true ;
								repaint() ;
							}

							if( request.equals("DONE") ) {
								clearTurn() ;
								myTurn = true ;
								repaint() ;
							}

							if( request.equals("DIE") ) {

								d1 = received.nextInt() ;
								d2 = received.nextInt() ;

								if( d1 == d2 ) {
									doubles = 4 ;
								} else {
									doubles = 0 ;
								}

								switch( d1 ) {
									case 1 : yourDie1.setIcon( bone   ) ; break ;
									case 2 : yourDie1.setIcon( btwo   ) ; break ;
									case 3 : yourDie1.setIcon( bthree ) ; break ;
									case 4 : yourDie1.setIcon( bfour  ) ; break ;
									case 5 : yourDie1.setIcon( bfive  ) ; break ;
									case 6 : yourDie1.setIcon( bsix   ) ; break ;
								}

								switch( d2 ) {
									case 1 : yourDie2.setIcon( bone   ) ; break ;
									case 2 : yourDie2.setIcon( btwo   ) ; break ;
									case 3 : yourDie2.setIcon( bthree ) ; break ;
									case 4 : yourDie2.setIcon( bfour  ) ; break ;
									case 5 : yourDie2.setIcon( bfive  ) ; break ;
									case 6 : yourDie2.setIcon( bsix   ) ; break ;
								}

								repaint() ;

							} //DIE

							if( request.equals("OFF") ) {

								int sp = received.nextInt() ;
								int d  = received.nextInt() ;

								if( d1 == d ) {

									if( doubles == 0 ) {
										d1 = 0 ;
										yourDie1.setIcon( blank ) ;
									} else {
										doubles-- ;
										if( doubles == 3 ) {
											switch( d1 ) {
												case 1 : yourDie1.setIcon( gone   ) ; break ;
												case 2 : yourDie1.setIcon( gtwo   ) ; break ;
												case 3 : yourDie1.setIcon( gthree ) ; break ;
												case 4 : yourDie1.setIcon( gfour  ) ; break ;
												case 5 : yourDie1.setIcon( gfive  ) ; break ;
												case 6 : yourDie1.setIcon( gsix   ) ; break ;
											}
										} else if ( doubles == 2 ) {
											d1 = 0 ;
											yourDie1.setIcon( blank ) ;
										}
									}

									point[25-sp]++ ;
									repaint() ;

								} else if ( d2 == d ) {

									if( doubles == 0 ) {
										d2 = 0 ;
										yourDie2.setIcon( blank ) ;
									} else {
										doubles -- ;
										if( doubles == 1 ) {
											switch( d2 ) {
												case 1 : yourDie2.setIcon( gone   ) ; break ;
												case 2 : yourDie2.setIcon( gtwo   ) ; break ;
												case 3 : yourDie2.setIcon( gthree ) ; break ;
												case 4 : yourDie2.setIcon( gfour  ) ; break ;
												case 5 : yourDie2.setIcon( gfive  ) ; break ;
												case 6 : yourDie2.setIcon( gsix   ) ; break ;
											}
										} else if ( doubles == 0 ) {
											d2 = 0 ;
											yourDie2.setIcon( blank ) ;
										}
									}

									point[25-sp]++ ;
									repaint() ;

								}


							} //OFF

							if( request.equals("MOVE") ) {

								int sp = received.nextInt() ;
								int dp = received.nextInt() ;

								if( d1 == dp-sp%25 ) {

									if( doubles == 0 ) {
										d1 = 0 ;
										yourDie1.setIcon( blank ) ;
									} else {
										doubles-- ;
										if( doubles == 3 ) {
											switch( d1 ) {
												case 1 : yourDie1.setIcon( gone   ) ; break ;
												case 2 : yourDie1.setIcon( gtwo   ) ; break ;
												case 3 : yourDie1.setIcon( gthree ) ; break ;
												case 4 : yourDie1.setIcon( gfour  ) ; break ;
												case 5 : yourDie1.setIcon( gfive  ) ; break ;
												case 6 : yourDie1.setIcon( gsix   ) ; break ;
											}
										} else if ( doubles == 2 ) {
											d1 = 0 ;
											yourDie1.setIcon( blank ) ;
										}
									}

									if( sp == 25 )  {
										point[26]++ ;
									} else {
										point[25-sp]++ ;
									}
									if( point[25-dp] == 1 ) {
										point[25-dp] = 0 ;
										point[25]++ ;
									}
									point[25-dp]-- ;

								} else if( d2 == dp-sp%25 ) {

									if( doubles == 0 ) {
										d2 = 0 ;
										yourDie2.setIcon( blank ) ;
									} else {
										doubles -- ;
										if( doubles == 1 ) {
											switch( d2 ) {
												case 1 : yourDie2.setIcon( gone   ) ; break ;
												case 2 : yourDie2.setIcon( gtwo   ) ; break ;
												case 3 : yourDie2.setIcon( gthree ) ; break ;
												case 4 : yourDie2.setIcon( gfour  ) ; break ;
												case 5 : yourDie2.setIcon( gfive  ) ; break ;
												case 6 : yourDie2.setIcon( gsix   ) ; break ;
											}
										} else if ( doubles == 0 ) {
											d2 = 0 ;
											yourDie2.setIcon( blank ) ;
										}
									}

									if( sp == 25 )  {
										point[26]++ ;
									} else {
										point[25-sp]++ ;
									}
									if( point[25-dp] == 1 ) {
										point[25-dp] = 0 ;
										point[25]++ ;
									}
									point[25-dp]-- ;

								}

								repaint() ;

							} //MOVE
						}

						Thread.sleep(SLEEP) ;

					} //while-loop

				} catch( Exception ee ) {
					//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
				}

				cstop() ;

			} //run

			/****************************************/

			public void cstop() {

				if( connected ) {

					try {
						out.write("QUIT\n") ;
						out.flush() ;
						s.close() ;
						connected = false ;
						statusLabel.setIcon( red ) ;

						//
					} catch( IOException ee ) {
						//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
					}

					beServer = false ;

				} else {

					if( beServer ) {

						try {
							server.close() ;
						       	beServer = false ;
							statusLabel.setIcon( red ) ;
						} catch( IOException ee ) { 
							//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ; 
						}
					}
				}

				clearBoard() ;

			}//cstop

		} //SerivceThread

		/********************************************************************************/
		/********************************************************************************/

	} //MyNetworkHandler


	/********************************************************************************/
	/********************************************************************************/


	private class MyJPanel extends JPanel {

		/********************************************************************************/

		public MyJPanel() {
			MouseHandler mh = new MouseHandler() ;
			addMouseListener( mh ) ;
		}

		/********************************************************************************/

		private boolean inSquare( int px, int py, int x[], int y[] ) {
			return ( x[0] <= px && y[0] <= py && px <= x[1] && py <= y[1] ) ;
		}

		private int inPoint( int px, int py ) {

			int h = getHeight() / 2 ;
			int w = getWidth() / 13 ;
			int p = h / 10 ;

			//Bar clicked
			int a[] = { 6*w, 7*w } ;
			int b[] = { 0, 2*h } ;
			if ( inSquare( px, py, a, b ) ) {
			       return 25	;
			}

			//Die clicked
			int c[] = { (int)(2.5*w), 4*w } ;
			int d[] = { h-p, h+p } ;
			if( inSquare( px, py, c, d ) ) {
				return 27 ;
			}

			//Point 1 - 6 clicked
			for( int i = 7 ; i < 13 ; i++ ) {
				int x[] = { i*w, i*w+w } ;
				int y[] = { 0, h-p } ;
				if( inSquare( px, py, x, y ) ) {
					return 13-i ;
				}
			}

			//Pont 7 - 12 clicked
			for( int i = 0 ; i < 6 ; i++ ) {
				int x[] = { i*w, i*w+w } ;
				int y[] = { 0, h-p } ;
				if( inSquare( px, py, x, y ) ) {
					return 12-i ;
				}
			}

			//Pont 13 - 18 clicked
			for( int i = 0 ; i < 6 ; i++ ) {
				int x[] = { i*w, i*w+w } ;
				int y[] = { h+p, 2*h } ;
				if( inSquare( px, py, x, y ) ) {
					return i+13 ;
				}
			}

			//Point 19 - 24 clicked
			for( int i = 7 ; i < 13 ; i++ ) {
				int x[] = { i*w, i*w+w } ;
				int y[] = { h+p, 2*h } ;
				if( inSquare( px, py, x, y ) ) {
					return i+12 ;
				}
			}

			return -1 ;
		}

		/********************************************************************************/

		public void paintComponent( Graphics g ) {

			super.paintComponent(g) ;

			g.setFont( new Font( "SansSerif", Font.BOLD, 24 ) ) ;

			int h = getHeight() / 2 ;		//Half height board height
			int w = getWidth() / 13 ;		//Width of a point or bar
			int p = h / 10 ;			//Height of space between points
			int s = (h-p)/5 ;			//Stone diameter
			int se = s/5 ;				//Selection indicator diameter

			//Display the die
			myDie1.setVisible(myTurn) ;
			myDie2.setVisible(myTurn) ;
			yourDie1.setVisible(!myTurn) ;
			yourDie2.setVisible(!myTurn) ;

			//Draw the bar
			int a[] = { 6*w, 7*w, 7*w, 6*w } ;
			int b[] = { 0, 0, 2*h, 2*h } ;
			g.setColor( Color.GRAY ) ;
			g.fillPolygon( a, b, 4 ) ;

			//Draw the points
			for( int i = 0 ; i < 6 ; i++ ) {
				int x[] = { i*w, i*w+w, i*w+w/2 } ;
				int y[] = { 0, 0, h - p } ;
				int z[] = { 2*h, 2*h, h + p } ;
				if( i % 2 == 0 ) {
					g.setColor( Color.BLUE ) ;
					g.fillPolygon( x, y, 3 ) ;
					g.setColor( Color.RED ) ;
					g.fillPolygon( x, z, 3 ) ;
				} else {
					g.setColor( Color.RED ) ;
					g.fillPolygon( x, y, 3 ) ;
					g.setColor( Color.BLUE ) ;
					g.fillPolygon( x, z, 3 ) ;
				}
			}

			for( int i = 7 ; i < 13 ; i++ ) {
				int x[] = { i*w, i*w+w, i*w+w/2 } ;
				int y[] = { 0, 0, h - p } ;
				int z[] = { 2*h, 2*h, h + p } ;
				if( i % 2 == 0 ) {
					g.setColor( Color.RED ) ;
					g.fillPolygon( x, y, 3 ) ;
					g.setColor( Color.BLUE ) ;
					g.fillPolygon( x, z, 3 ) ;
				} else {
					g.setColor( Color.BLUE ) ;
					g.fillPolygon( x, y, 3 ) ;
					g.setColor( Color.RED ) ;
					g.fillPolygon( x, z, 3 ) ;
				}
			}

			//Draw the stones on points
			for( int i = 1 ; i <= 26 ; i++ ) {
				if( point[i] != 0 ) {

					if( point[i] > 0 ) {
						g.setColor( Color.BLACK ) ;
					} else {
						g.setColor( Color.WHITE ) ;
					}

					int nPoints =  Math.abs(point[i]) ;
					int off = (int)(0.5*(w-s)) ;

					if(  i <= 6 ) {
						for( int j = 0 ; j < Math.min(5,nPoints) ; j++ ) g.fillOval( (13-i)*w + off, j*s, s, s ) ;
						Color c = g.getColor() ;
						if( c == Color.BLACK ) g.setColor( Color.WHITE ) ; else g.setColor( Color.BLACK ) ;
						if( nPoints > 5 ) g.drawString( String.valueOf(Math.abs(point[i])), (int)((13.5-i)*w) - 8, (int)(s/2) + 5 ) ;
						g.setColor( c ) ;
					}

					if(  7 <= i && i <= 12 ) {
						for( int j = 0 ; j < Math.min(5,nPoints) ; j++ ) g.fillOval( (12-i)*w + off, j*s, s, s ) ;
						Color c = g.getColor() ;
						if( c == Color.BLACK ) g.setColor( Color.WHITE ) ; else g.setColor( Color.BLACK ) ;
						if( nPoints > 5 ) g.drawString( String.valueOf(Math.abs(point[i])), (int)((12.5-i)*w) - 8, (int)(s/2) + 5 ) ;
						g.setColor( c ) ;
					}

					if( 13 <= i && i <= 18 ) {
						for( int j = 0 ; j < Math.min(5,nPoints) ; j++ ) g.fillOval( (i-13)*w + off, 2*h-(j+1)*s, s, s ) ;
						Color c = g.getColor() ;
						if( c == Color.BLACK ) g.setColor( Color.WHITE ) ; else g.setColor( Color.BLACK ) ;
						if( nPoints > 5 ) g.drawString( String.valueOf(Math.abs(point[i])), (int)((i-12.5)*w) - 8, 2*h-(int)(s/2) + 5 ) ;
						g.setColor( c ) ;
					}

					if( 19 <= i && i <= 24 ) {
						for( int j = 0 ; j < Math.min(5,nPoints) ; j++ ) g.fillOval( (i-12)*w + off, 2*h-(j+1)*s, s, s ) ;
						Color c = g.getColor() ;
						if( c == Color.BLACK ) g.setColor( Color.WHITE ) ; else g.setColor( Color.BLACK ) ;
						if( nPoints > 5 ) g.drawString( String.valueOf(Math.abs(point[i])), (int)((i-11.5)*w) - 8, 2*h-(int)(s/2) + 5 ) ;
						g.setColor( c ) ;
					}

					if( i == 25 ) {
						for( int j = 0 ; j < Math.min(5,nPoints) ; j++ ) g.fillOval( 6*w + off, j*s, s, s ) ;
						Color c = g.getColor() ;
						if( c == Color.BLACK ) g.setColor( Color.WHITE ) ; else g.setColor( Color.BLACK ) ;
						if( nPoints > 5 ) g.drawString( String.valueOf(Math.abs(point[i])), (int)(6.5*w) - 8, (int)(s/2) + 5 ) ;
						g.setColor( c ) ;
					}

					if( i == 26 ) {
						for( int j = 0 ; j < Math.min(5,nPoints) ; j++ ) g.fillOval( 6*w + off, 2*h-(j+1)*s, s, s ) ;
						Color c = g.getColor() ;
						if( c == Color.BLACK ) g.setColor( Color.WHITE ) ; else g.setColor( Color.BLACK ) ;
						if( nPoints > 5 ) g.drawString( String.valueOf(Math.abs(point[i])), (int)(6.5*w) - 8, 2*h-(int)(s/2) + 5 ) ;
						g.setColor( c ) ;
					}
				}
			}

			//Draw selected points
			if( startPoint > 0 ) {
				int off = (int)(0.5*(w-se)) ;
				if( startPoint <= 6 ) {
					Color c = g.getColor() ;
					g.setColor( Color.YELLOW ) ;
				       	g.fillOval( (13-startPoint)*w + off, h-p, se, se ) ;
				       	g.setColor( c ) ;
				}
				if( 7 <= startPoint && startPoint <= 12 ) {
					Color c = g.getColor() ;
					g.setColor( Color.YELLOW ) ;
				       	g.fillOval( (12-startPoint)*w + off, h-p, se, se ) ;
				       	g.setColor( c ) ;
				}
				if( 13 <= startPoint && startPoint <= 18 ) {
					Color c = g.getColor() ;
					g.setColor( Color.YELLOW ) ;
				       	g.fillOval( (startPoint-13)*w + off, h+p-se, se, se ) ;
				       	g.setColor( c ) ;
				}
				if( 19 <= startPoint && startPoint <= 24 ) {
					Color c = g.getColor() ;
					g.setColor( Color.YELLOW ) ;
				       	g.fillOval( (startPoint-12)*w + off, h+p-se, se, se ) ;
				       	g.setColor( c ) ;
				}
				if( startPoint == 25 ) {
					Color c = g.getColor() ;
					g.setColor( Color.YELLOW ) ;
				       	g.fillOval( 6*w + off, h-p, se, se ) ;
				       	g.setColor( c ) ;
				}
			}

		} //paintComponent

		/********************************************************************************/
		/********************************************************************************/

		private class MouseHandler implements MouseListener {

			public void mouseClicked( MouseEvent e ) {

				if( ! connected ) {
					JOptionPane.showMessageDialog( null, "YOU CAN'T START PLAYING\nYou don't have a connection yet." ) ;
					return ;
				}

				/*****/

				if( ! myTurn ) {
					JOptionPane.showMessageDialog( null, "WAIT YOUR TURN." ) ;
					return ;
				}

				/*****/

				//Where was the click and what point does it belong to?
				//25 = bar, 27 = myDie

				int x = e.getX() ;
				int y = e.getY() ;
				int p = inPoint( x, y ) ;

				/****/

				//Die were selected, but we already have a roll
				if( p != 27 && d1 == 0 && d2 == 0 ) {
					JOptionPane.showMessageDialog( null, "ROLL FIRST!" ) ;
					return ;
				}

				/****/

				//New selection is a point, but not the bar, and there are still stones on the bar
				if( 1 <= p && p <= 25 && startPoint == 0 && point[25] > 0 && p != 25 ) {
					JOptionPane.showMessageDialog( null, "YOU MUST SELECT THE BAR!\nYou still have stones on the bar." ) ;
					return ;
				}

				/****/

				//New selection is a point or the bar with stones
				if( 1 <= p && p <= 25 && startPoint == 0 && point[p] > 0 ) {

					startPoint = p ;

					//What is the furthest point from the inner table
					int maxPoint = 0 ;
					for( int i = 1 ; i <= 24 ; i++ ) {
						if( point[i] > 0 ) {
							maxPoint = i ;
							break ;
						}
					}

					//Are all the stones in the inner table?
					if( 19 <= maxPoint && maxPoint <= 24 && point[25] == 0 ) {

						System.out.printf("We're in the inner table: p = %d  d1 = %d  d2 = %d\n", p, d1, d2 ) ;

						if( ( p == maxPoint && ( p + d1 > 24 ) ) || ( p + d1 == 25 ) ) {

							try {
								out.write("OFF " + p + " " + d1 + "\n") ;
								out.flush() ;
							} catch( IOException ee ) {
								//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
							}

							point[p]-- ;
							startPoint = 0 ;

							if( doubles == 0 ) {
								d1 = 0 ;
								myDie1.setIcon( blank ) ;
							} else {
								doubles-- ;
								if( doubles == 3 ) {
									switch( d1 ) {
										case 1 : myDie1.setIcon( gone   ) ; break ;
										case 2 : myDie1.setIcon( gtwo   ) ; break ;
										case 3 : myDie1.setIcon( gthree ) ; break ;
										case 4 : myDie1.setIcon( gfour  ) ; break ;
										case 5 : myDie1.setIcon( gfive  ) ; break ;
										case 6 : myDie1.setIcon( gsix   ) ; break ;
									}
								} else if ( doubles == 2 ) {
									d1 = 0 ;
									myDie1.setIcon( blank ) ;
								}
							}

							repaint() ;
							if( ( d1 != 0 || d2 != 0 ) && cantMove() ) {
								try {
									out.write("DONE\n") ;
									out.flush() ;
								} catch( IOException ee ) {
									//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
								}
								JOptionPane.showMessageDialog( null, "NO MORE POSSIBLE MOVES.\nSkipping remainder of your turn." ) ;
								clearTurn() ;
							}

						} else  if( ( p == maxPoint && ( p + d2 > 24 ) ) || ( p + d2 == 25 ) ) {

							try {
								out.write("OFF " + p + " " + d2 + "\n") ;
								out.flush() ;
							} catch( IOException ee ) {
								//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
							}

							point[p]-- ;
							startPoint = 0 ;

							if( doubles == 0 ) {
								d2 = 0 ;
								myDie2.setIcon( blank ) ;
							} else {
								doubles -- ;
								if( doubles == 1 ) {
									switch( d2 ) {
										case 1 : myDie2.setIcon( gone   ) ; break ;
										case 2 : myDie2.setIcon( gtwo   ) ; break ;
										case 3 : myDie2.setIcon( gthree ) ; break ;
										case 4 : myDie2.setIcon( gfour  ) ; break ;
										case 5 : myDie2.setIcon( gfive  ) ; break ;
										case 6 : myDie2.setIcon( gsix   ) ; break ;
									}
								} else if ( doubles == 0 ) {
									d2 = 0 ;
									myDie2.setIcon( blank ) ;
								}
							}

							repaint() ;
							if( ( d1 != 0 || d2 != 0 ) && cantMove() ) {

								try {
									out.write("DONE\n") ;
									out.flush() ;
								} catch( IOException ee ) {
									//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
								}
								JOptionPane.showMessageDialog( null, "NO MORE POSSIBLE MOVES.\nSkipping remainder of your turn." ) ;
								clearTurn() ;
							}

						}

					} //Are all the stones in the inner table?

					int remaining = 0 ;
					for( int i = 1 ; i <= 25 ; i++ ) {
						if( point[i] > 0 ) {
							remaining += point[i] ;
						}
					}

					if( remaining == 0 ) {
						repaint() ;
						try {
							out.write("YOULOSE\n") ;
							out.flush() ;
						} catch( IOException ee ) {
							//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
						}
						JOptionPane.showMessageDialog( null, "YOU WIN!\n" ) ;
						clearBoard() ;
						repaint() ;
					}

					if( d1 == 0 && d2 == 0 ) {
						try {
							out.write("DONE\n") ;
							out.flush() ;
						} catch( IOException ee ) {
							//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
						}
						clearTurn() ;
					}

					repaint() ;
					return ;

				} //New selection is a point or the bar with stones

				/****/

				// Continue processing a selection
				if( 1 <= p && p <= 25 && startPoint != 0 && point[startPoint] > 0 ) {
							       
					if( d1 == p-startPoint%25 && ! ( point[p] <= -2 )  ) { 

						try {
							out.write("MOVE " + startPoint + " " + p + "\n") ;
							out.flush() ;
						} catch( IOException ee ) {
							//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
						}

						if( point[p] == -1 ) {
							point[p] = 0 ;
							point[26]-- ;
						}

						point[startPoint]-- ;
						point[p]++ ;
						startPoint = 0 ;

						if( doubles == 0 ) {
							d1 = 0 ;
							myDie1.setIcon( blank ) ;
						} else {
							doubles-- ;
							if( doubles == 3 ) {
								switch( d1 ) {
									case 1 : myDie1.setIcon( gone   ) ; break ;
									case 2 : myDie1.setIcon( gtwo   ) ; break ;
									case 3 : myDie1.setIcon( gthree ) ; break ;
									case 4 : myDie1.setIcon( gfour  ) ; break ;
									case 5 : myDie1.setIcon( gfive  ) ; break ;
									case 6 : myDie1.setIcon( gsix   ) ; break ;
								}
							} else if ( doubles == 2 ) {
								d1 = 0 ;
								myDie1.setIcon( blank ) ;
							}
						}

						repaint() ;

						if( ( d1 != 0 || d2 != 0 ) && cantMove() ) {
							try {
								out.write("DONE\n") ;
								out.flush() ;
							} catch( IOException ee ) {
								//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
							}
							JOptionPane.showMessageDialog( null, "NO MORE POSSIBLE MOVES.\nSkipping remainder of your turn." ) ;
							clearTurn() ;
						}

				       } else if( d2 == p-startPoint%25 && ! ( point[p] <= -2 ) ) {

						try {
							out.write("MOVE " + startPoint + " " + p + "\n") ;
							out.flush() ;
						} catch( IOException ee ) {
							//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
						}

						if( point[p] == -1 ) {
							point[p] = 0 ;
							point[26]-- ;
						}

						point[startPoint]-- ;
						point[p]++ ;
						startPoint = 0 ; 

						if( doubles == 0 ) {
							d2 = 0 ;
							myDie2.setIcon( blank ) ;
						} else {
							doubles -- ;
							if( doubles == 1 ) {
								switch( d2 ) {
									case 1 : myDie2.setIcon( gone   ) ; break ;
									case 2 : myDie2.setIcon( gtwo   ) ; break ;
									case 3 : myDie2.setIcon( gthree ) ; break ;
									case 4 : myDie2.setIcon( gfour  ) ; break ;
									case 5 : myDie2.setIcon( gfive  ) ; break ;
									case 6 : myDie2.setIcon( gsix   ) ; break ;
								}
							} else if ( doubles == 0 ) {
								d2 = 0 ;
								myDie2.setIcon( blank ) ;
							}
						}

						repaint() ;

						if( ( d1 != 0 || d2 != 0 ) && cantMove() ) {
							try {
								out.write("DONE\n") ;
								out.flush() ;
							} catch( IOException ee ) {
								//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
							}
							JOptionPane.showMessageDialog( null, "NO MORE POSSIBLE MOVES.\nSkipping remainder of your turn." ) ;
							clearTurn() ;
						}

					} else if( startPoint == p ) {

						if( point[25] > 0 && startPoint == 25 ) {
							JOptionPane.showMessageDialog( null, "YOU CAN'T DESELECT!\nYou still have stones on the bar." ) ;
						} else {
							startPoint = 0 ;
						}
						repaint() ;
					}

					if( d1 == 0 && d2 == 0 ) {
						try {
							out.write("DONE\n") ;
							out.flush() ;
						} catch( IOException ee ) {
							//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
						}
						clearTurn() ;
					}

					return ;

				} //Continue processing a selection

				/*****/

				//Roll new die
				if( p == 27 && d1 == 0 && d2 == 0 ) {

					d1 = 1 + (int)(6*Math.random()) ;
					d2 = 1 + (int)(6*Math.random()) ;

					if( d1 == d2 ) {
						doubles = 4 ;
					} else {
						doubles = 0 ;
					}

					switch( d1 ) {
						case 1 : myDie1.setIcon( bone   ) ; break ;
						case 2 : myDie1.setIcon( btwo   ) ; break ;
						case 3 : myDie1.setIcon( bthree ) ; break ;
						case 4 : myDie1.setIcon( bfour  ) ; break ;
						case 5 : myDie1.setIcon( bfive  ) ; break ;
						case 6 : myDie1.setIcon( bsix   ) ; break ;
					}

					switch( d2 ) {
						case 1 : myDie2.setIcon( bone   ) ; break ;
						case 2 : myDie2.setIcon( btwo   ) ; break ;
						case 3 : myDie2.setIcon( bthree ) ; break ;
						case 4 : myDie2.setIcon( bfour  ) ; break ;
						case 5 : myDie2.setIcon( bfive  ) ; break ;
						case 6 : myDie2.setIcon( bsix   ) ; break ;
					}

					repaint() ;
					if( cantMove() ) {
						try {
							out.write("DONE\n") ;
							out.flush() ;
						} catch( IOException ee ) {
							//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
						}
						JOptionPane.showMessageDialog( null, "NO POSSIBLE MOVES.\nSkipping your turn." ) ;
						clearTurn() ;
					}

					try {
						out.write("DIE " + d1 + " " + d2 + "\n") ;
						out.flush() ;
					} catch( IOException ee ) {
						//JOptionPane.showMessageDialog( null, ee.toString(), "ERROR!", JOptionPane.ERROR_MESSAGE ) ;
					}

					return ;
				}

			}//mouseClicked

			public void mouseEntered( MouseEvent e ) {}
			public void mousePressed( MouseEvent e ) {} 
			public void mouseReleased( MouseEvent e ) {}
			public void mouseExited( MouseEvent e ) {}


		} //MouseHandler

		/********************************************************************************/
		/********************************************************************************/

	} //MyJPanel

/********************************************************************************/
/********************************************************************************/

}

