import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;

/**
  *This class implements the View half of the Model/View architecture.
  *It is an Applet to be able to run on remote browsers
  *It is a MouseMotionListener to "track" the mouse to move the paddle
  *It is a MouseListener to detect button presses to pause the game
  */
public class BricklesView extends Applet
        implements MouseMotionListener,MouseListener{
	static final int fieldX = 0;
	static final int fieldY = 0;
	static final int fieldWidth = 440;
	static final int fieldHeight = 320;
	static final int _mouseSensitivity = 3;
	int flipflop;
  	protected int xPaddle;
  	protected int yPaddle;
	protected Puck thePuck;
	protected Paddle thePaddle;
   	protected Brick theBrick;
   	protected BrickPile theBrickPile;
	protected Dimension dim;
	protected Image offScreenImage;
	protected Graphics offScreenGraphics;
	protected BricklesGame _game;
      protected BricklesGame game;
	protected boolean threadSuspended;

	/**
	  *This is the default constructor that only adds the listeners
	  */ 
	public BricklesView(){
                	addMouseMotionListener(this);
			addMouseListener(this);
	}

	/**
	  *This routine initializes the drawing field and the off screen
	  *image used to improve the animation quality
	  */
	public void init(){
		flipflop = 0;
		setBackground(Color.white);
		resize(fieldWidth,fieldHeight);
            dim = this.getSize();
		xPaddle = (int)(fieldWidth/2);
		yPaddle = (int)(fieldHeight*.75);
		offScreenImage = createImage(dim.width,dim.height);
		offScreenGraphics = offScreenImage.getGraphics();
	}

	/**
	  *THis is where the game starts
	  *It is the method called when the Applet is ready to start
	  *post: game is in the start state
	  */
	public void start(){
		_game = new BricklesGame(this);
		_game.start();
		try{
			Thread.sleep(10);
		}
		catch(InterruptedException e){}

		repaint();
	}

	/**
	  *Standard applet routine
	  */
	public void update(Graphics g){
		paint(g);
	}

	/**
	  *This is the main routine for drawing the screen
	  *Several message are sent to the "model" to obtain current information
	  *Only the location of the paddle is obtained directly from mouse events
	  *@param g This is the set of Graphics properties that determine how the 
	  *screen will be painted
	  *post: The current state of the game is graphically reprsented
	  */
	public void paint(Graphics g){
		if(offScreenGraphics == null)
			showStatus("Graphics object is null");
		offScreenGraphics.setColor(getBackground());
		offScreenGraphics.fillRect(0,0,dim.width,dim.height);
		offScreenGraphics.setColor(getForeground());
		offScreenGraphics.drawRect(1,1,dim.width - 1, dim.height - 1);
		offScreenGraphics.drawImage(thePaddle.getBitMap(),thePaddle.getPosition().x,thePaddle.getPosition().y,this);
		if (!(thePuck == null)){
      		offScreenGraphics.drawImage(thePuck.getBitMap(), thePuck.getPosition().x,thePuck.getPosition().y, this);
     		}
      	if (!(theBrickPile == null)){
      		for(int i=0;i<theBrickPile.getSize();i++){
           		theBrick = theBrickPile.getBrickAt(i);
            	if(!theBrick.isHit()){
      	  		offScreenGraphics.drawImage(theBrick.getBitMap(),theBrick.getPosition().x,theBrick.getPosition().y,this);
         		}
      	}
      }
		g.drawImage(offScreenImage,0,0,this);
		try{
			Thread.sleep(10);
		}
		catch(InterruptedException e){}
	}


	  /**
	  *This method uses the standard Mouse Event name
	  *It is invoked by the MouseMotionListener
	  *@param e The data from the mouse event
	  *Updates the position of the mouse
	  *FlipFlop allows some mouse events to be ignored
	  */
        public void mouseMoved(MouseEvent e) {
		flipflop++;
		if((flipflop % _mouseSensitivity) == 0){
			flipflop = 0;
                  xPaddle = e.getX();
			thePaddle.setPosition(xPaddle,thePaddle.getPosition().y);
		}
        }

	/**
	  *This method uses the standard Mouse Event name
	  *It is invoked by the MouseMotionListener
	  *@param evt The data from the mouse event
	  */
      public void mouseDragged(MouseEvent evt) {
        
	}

	/**
	  *This method uses the standard Mouse Event name
	  *It is invoked by the MouseMotionListener
	  *@param evt The data from the mouse event
	  */
	public void mouseClicked(MouseEvent evt) {
        
	}

	/**
	  *This method uses the standard Mouse Event name
	  *It is invoked by the MouseMotionListener
	  *@param evt The data from the mouse event
	  *resumes a stopped game when the cursor enters the window
	  */
	public void mouseEntered(MouseEvent evt) {
      	_game.resume();  
	}

	/**
	  *This method uses the standard Mouse Event name
	  *It is invoked by the MouseMotionListener
	  *@param evt The data from the mouse event
	  *pauses a running game when the mouse cursor leaves the window
	  */
	public void mouseExited(MouseEvent evt) {
		_game.pause();
	}

	/**
	  *This method uses the standard Mouse Event name
	  *It is invoked by the MouseListener
	  *@param evt The data from the mouse event
	  *pauses a running game when the right mouse button is pressed
	  */
	public synchronized void mousePressed(MouseEvent evt){
		_game.pause();			
	}

	/**
	  *This method uses the standard Mouse Event name
	  *It is invoked by the MouseListener
	  *@param evt The data from the mouse event
	  *resumes a paused game when the right mouse button is released 
	  */
	public void mouseReleased(MouseEvent evt){
		_game.resume();
	}

	/**
	  *@return the width of the playingField
	  */
	public int getFieldWidth(){
		return fieldWidth;
	}

	/**
	  *@return the height of the playingField
	  */
	public int getFieldHeight(){
		return fieldHeight;
	}

	/**
	  *Gives the View a reference to the Paddle
	  *@param newPaddle the current game paddle
	  */
	protected void setPaddle(Paddle newPaddle){
		thePaddle = newPaddle;
	}

	/**
	  *Gives the View a reference to the current Puck
	  *@param newPuck the current Puck
	  */
	protected void setPuck(Puck newPuck){
		thePuck = newPuck;
	}

	/**
	  *Gives the View a reference to the BrickPile
	  *@param newBrickPile 
	  */
   	protected void setBrickPile(BrickPile newBrickPile){
   		theBrickPile = newBrickPile;
   	}

	/**
	  *Provides access to the message window at the bottom of the Applet window
	  *@param str The string to be displayed in the Applet window
	  */
	public void showMessage(String str){
		showStatus(str);
	}

	/**
	  *Provides access to the current Paddle
	  *@return the current Paddle
	  */
	protected Paddle getPaddle(){
		return thePaddle;
	}

	/**
	  *Provides access to the BrickPile
	  *@return the current BrickPile
	  */
   	protected BrickPile getBrickPile(){
		return theBrickPile;
	}
}
