import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JPanel;

public class BreakoutDraw extends JPanel
{
  private static final long serialVersionUID = 1L;
  private BufferedImage image_buf;
  private Graphics2D graphics;
  private int ballX, ballY, ballSpeedX, ballSpeedY;
  private final int BALL_DIAMETER = 11;
  private final int BALL_HISTORY_COUNT = 50;
  private final int BLOCK_GAP = 2;
  
  private Point[] ballHistory = new Point[BALL_HISTORY_COUNT];
  private int historyIdx = 0;
  private int panelWidth, panelHeight;

  
  private static final Color[] BLOCK_COLORS = 
  { new Color(194,214,155), //sage
    new Color(250,191,141), //pumpkin
    new Color(217,149,148), //sand red
    new Color(178,161,199)  //wisteria
  };
  
  private static final Color BALL_COLOR = new Color(149,179,215); //denim
  private final int BLOCK_ROWS = 12;
  private final int BLOCK_COLUMNS = 10;
  
  private final int BLOCK_HEIGHT = 20;
  private int blockWidth, blockBoarder; 
  
  private int[][] blocks = new int[BLOCK_COLUMNS][BLOCK_ROWS];
  private Random rand;


  public BreakoutDraw(Breakout frame)
  { rand = new Random();
    for (int i=0; i<BALL_HISTORY_COUNT; i++)
    { ballHistory[i] = new Point(-100,-100);
    }
  }


  public void setBounds(int left, int top, int width, int height)
  { super.setBounds(left, top, width, height);
    
    panelWidth = width;
    panelHeight = height;

    if (graphics != null) graphics.dispose();

    image_buf = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    graphics = image_buf.createGraphics();
    
    blockWidth  = (width-BLOCK_COLUMNS*BLOCK_GAP)/BLOCK_COLUMNS;
    blockBoarder = 1+(width-(blockWidth+BLOCK_GAP)*BLOCK_COLUMNS)/2;
    
    clear();
  }


  public void clear()
  { graphics.setColor(Color.WHITE);
    graphics.fillRect(0, 0, panelWidth, panelHeight);
    ballX = rand.nextInt(panelWidth-BALL_DIAMETER);
    ballY = panelHeight-BALL_DIAMETER;
    ballSpeedX = rand.nextInt(20)-10;
    if (ballSpeedX == 0) ballSpeedX=1;
    ballSpeedY = -10;
    
    
    graphics.setColor(BLOCK_COLORS[0]);
    for (int x=0; x<BLOCK_COLUMNS; x++)
    { for (int y=0; y<BLOCK_ROWS; y++)
      { if (rand.nextFloat() < 2f) 
        { blocks[x][y] = 1;
          graphics.fillRect(columnToPixelLeft(x), rowToPixelTop(y), 
              blockWidth, BLOCK_HEIGHT);
        }
        else blocks[x][y] = 0;
      }
    }
      
    graphics.setColor(BALL_COLOR);
    graphics.fillOval(ballX, ballY, BALL_DIAMETER, BALL_DIAMETER);
    this.repaint();
  }
  
  private int columnToPixelLeft(int column)
  { return column*(blockWidth+BLOCK_GAP) + blockBoarder;
  }
  
  private int pixelToColumn(int x)
  { int column = (x - blockBoarder)/(blockWidth+BLOCK_GAP);
    if (column < 0) return 0;
    if (column >=BLOCK_COLUMNS) return BLOCK_COLUMNS-1;
    return column;
  }
  
  private int rowToPixelTop(int row)
  { return row*(BLOCK_HEIGHT+BLOCK_GAP)+BLOCK_GAP;
  }
  
  private int pixelToRow(int y)
  { if (y < BLOCK_GAP) return -1;
    if (y > rowToPixelTop(BLOCK_ROWS-1)+BLOCK_HEIGHT) return -1;
    return (y-BLOCK_GAP)/(BLOCK_HEIGHT+BLOCK_GAP);
  }

  public void nextTurn()
  { historyIdx = (historyIdx +1) % BALL_HISTORY_COUNT;
    Point p = ballHistory[historyIdx];
    graphics.setColor(Color.WHITE);
    graphics.fillOval(p.x, p.y, BALL_DIAMETER, BALL_DIAMETER);
    p.x = ballX;
    p.y = ballY;
    ballX += ballSpeedX;
    ballY += ballSpeedY;
    
   
    
    if (ballY <= 0) 
    { ballSpeedY = -ballSpeedY;
      ballY = 0;
    }
    else if (ballY+BALL_DIAMETER >= panelHeight) 
    { ballSpeedY = -ballSpeedY;
      ballY = panelHeight-BALL_DIAMETER;
    }
    else
    { int row = pixelToRow(ballY);
      if (row >=0)
      { ballSpeedY = -ballSpeedY;
        ballY = rowToPixelTop(BLOCK_ROWS-1)+BLOCK_HEIGHT;
        int column1 = pixelToColumn(ballX);
        int column2 = pixelToColumn(ballX+BALL_DIAMETER);
        if (column1 >=0)
        { int colorIdx = blocks[column1][row] % BLOCK_COLORS.length;
          graphics.setColor(BLOCK_COLORS[colorIdx]);
          graphics.fillRect(columnToPixelLeft(column1), rowToPixelTop(row), 
              blockWidth, BLOCK_HEIGHT);
          blocks[column1][row]++;
        }
        if (column2 >= 0 && column2 != column1)
        { int colorIdx = blocks[column2][row] % BLOCK_COLORS.length;
          graphics.setColor(BLOCK_COLORS[colorIdx]);
          graphics.fillRect(columnToPixelLeft(column2), rowToPixelTop(row), 
              blockWidth, BLOCK_HEIGHT);
          blocks[column2][row]++;
        }
      }
    }
    if (ballX <= 0) 
    { ballSpeedX = -ballSpeedX;
      ballX = 0;
    }
    else if (ballX+BALL_DIAMETER >= panelWidth) 
    { ballSpeedX = -ballSpeedX;
      ballX = panelWidth - BALL_DIAMETER;
    }
    
    graphics.setColor(BALL_COLOR);
    graphics.fillOval(ballX, ballY, BALL_DIAMETER, BALL_DIAMETER);
    
    this.repaint();
  }
  
  public void paintComponent(Graphics g)
  { super.paintComponent(g);
    g.drawImage(image_buf, 0, 0, null);
  }
}