import javax.swing.JFrame;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

public class GridDisplay extends JPanel implements Runnable {
    /*@non_null@*/ private Grid grid;
    /*@non_null@*/ private SimObjectChooser simobjchooser;
    private boolean stopThread;
    final static int SLEEP_DELAY = 200;
    
    GridDisplay (/*@non_null@*/ Grid grid, /*@non_null@*/ SimObjectChooser simobjchooser) {
        this.grid = grid;
        this.simobjchooser = simobjchooser;
        this.stopThread = true;
        setOpaque (false); // This is necessary to make painting work
    }
    
    private int getSquareWidth ()
    //@ensures \result > 0
    {
        int swidth = getWidth() / grid.numColumns ();
        
        if (swidth > 0) {
            return swidth;
        } else {
            return 1;
        }
    }
    
    private int getSquareHeight ()
    //@ensures \result > 0
    {
        int sheight = getHeight() / grid.numRows ();
        
        if (sheight > 0) {
            return sheight;
        } else {
            return 1;
        }
    }
    
    private int getHorizontalOffset () {
        return (getWidth() - (getSquareWidth () * grid.numColumns ())) / 2;
    }
    
    private int getVerticalOffset () {
        return (getHeight() - (getSquareHeight () * grid.numRows ())) / 2;
    }
    
    public int numColumns () {
        return grid.numColumns ();
    }
    
    public void setObjectAt (int x, int y) 
  
    {
        if (stopThread) {
            // Only allow grid locations to be set if
            // the simulation is stopped.
            int row = (y - getVerticalOffset ()) / getSquareHeight ();
            int col = (x - getHorizontalOffset ()) / getSquareWidth ();
            
            grid.setObjectAt(x,y, new StackedObject(new FallingObject(), new FallingObject (), new FallingObject()));
            repaint ();
        }
    }
    
    public void startObjects () {
        //setObjectAt(1, grid.numColumns ()/2);
        setObjectAt(0, numColumns ()/2);
        repaint();
        grid.startObjects (); // Start SimObject threads.
        Thread displayThread = new Thread(this);
        displayThread.start();
    }
    
    public void run() {
        stopThread = false;
        
        while (!stopThread) {
            repaint ();
            try {
                Thread.sleep (SLEEP_DELAY);
            } catch (java.lang.InterruptedException e) {
                System.out.println("Display thread interrupted.");
                break;
            }
        }
    }
    
    public void pauseObjects () {
        grid.pauseObjects (); // Pause SimObject threads.
        this.stopThread = true;
    }
    
    public void paintComponent (Graphics g) throws RuntimeException
    {
        //@ assume g != null;
        int squarewidth = getSquareWidth ();
        int squareheight = getSquareHeight ();
        
        int hoffset = getHorizontalOffset ();
        int voffset = getVerticalOffset ();
        
        for (int row = 0; row < grid.numRows (); row++) {
            for (int col = 0; col < grid.numColumns (); col++) {
                SimObject tmp = grid.grabObjectAt (row,col);
                
                if (tmp == null) {
                    g.setColor (Color.black);
                } else {
                    g.setColor (tmp.getColor());
                }
                
                g.fillRect (hoffset + col * squarewidth, voffset + row * squareheight,
                squarewidth , squareheight );
            }
        }
    }
    
    public void moveObjectLeft(){ 
        grid.setUserDirection(new Direction (1,-1));
    }
    
    public void moveObjectRight () {
        grid.setUserDirection(new Direction (1,1)) ;
    }
    
    public void defaultDir () {
        grid.setUserDirection(new Direction (1,0));
    }
}