/*
** thread_sync_example.java should provide a basic program structure for a GUI
** program in Java that can be used by the students of the SPIN course if they
** have problems with their code.
**
** In first the class and task name have to be replaced with the name of your
** class and the paint() and run() functions must be adapted to your needs.
*/

/* Importing packages needed. */
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;

import javax.swing.JFrame;
import javax.swing.JPanel;

/******************************************************************************
 This is our main class. It extends JPanel so we can use the drawing         
 functions provided by this class.                                          
******************************************************************************/
public class thread_sync_example extends JPanel {
	/******************************************************************************
	 Define global constants and variables that can be seen by all functions in
	 the class.
	******************************************************************************/

	/* Define global constants, e.g. the window size (in pixels). */
	final static int X_WINDOW_SIZE = 800;
	final static int Y_WINDOW_SIZE = 600;

	/* Upper left corner of the window on our screen. */
	final static int X_WINDOW_LOCATION = 100;
	final static int Y_WINDOW_LOCATION = 100;
	
	/* Define how many grid points we have and the size of a pixel. */
	final int GRID_SIZE = 150;
	final int PIXEL_SIZE = 5;

	/* Define gobal variables like the X and Y positions of a particle. */
	int grid[][] = new int[GRID_SIZE][GRID_SIZE];

	/* Dummy variable needed for synchronozation. */
	Object lockobject = new Object(); //  Not needed here as we lock (or rather not lock) on the the array grid

	/************************* end global variables ******************************/

	/******************************************************************************
	 The main function is called when we start the program (It has to be static!).
	******************************************************************************/
	public static void main(String[] args) {
		/* Create a new JFrame object which provides a very basic window for the
		 * application. The title can be chosen arbitrarily. */
		JFrame top = new JFrame("What happens if I dont sync my threads?");
		
		/* Position and size of the window. */
		top.setBounds(X_WINDOW_LOCATION, Y_WINDOW_LOCATION, X_WINDOW_SIZE, Y_WINDOW_SIZE);

		/* What do we do if we get a close signal? */
		top.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		/* Make a new instance of our class thread_sync_example. */
		thread_sync_example thread_sync_instance = new thread_sync_example();
		
		/* Add the JPanel to the window we created. All graphical output is now
		 * displayed in the window. */
		top.getContentPane().add(thread_sync_instance);
		
		/* Make a new thread where we do the numerical calculations in the program. */ 
		thread_sync_example_task task = thread_sync_instance.new thread_sync_example_task(thread_sync_instance);

		/* Start the thread. This automatically calls the function run() in
		 * thread_sync_example_task. */
		task.start();
		
		/* Make the window visible. Do this last otherwise your risk that you have no output on your screen. */
		top.setVisible(true);
	}
	/******************************* end main ***********************************/

	/******************************************************************************
	 The function paint() is called whenever the event handler of the program gets
	 a message that tells it to repaint the JPanel (e.g. we have another window
	 that was overlapping with it). It is also exectued when we use the repaint()
	 function somewhere in the code.
	******************************************************************************/
	public void paint(Graphics g) {
		int xs, ys, xs_max, ys_max;
		// clear drawing area
		/* Get the area that we want to redraw. */
		Rectangle bounds = getBounds();

		/* Clear the area (sometimes you might not want this so just comment it if not needed. */
		g.clearRect(bounds.x, bounds.y, bounds.width, bounds.height);

		/* Maybe rescale the variables to the screen size? */

		/* Here we do the drawing loop. This part has to be changed for every program.
		 * We have to lock all shared variables to avoid that they are changed while
		 * we do the drawing operation. */

		synchronized(lockobject) {
			// YOUR CODE COMES HERE
			for (int i = 0; i < GRID_SIZE; i++) {
				for (int j = 0; j < GRID_SIZE; j++) {
					int color = grid[i][j];
					if (color == 0) {
						g.setColor(Color.GREEN);
					} else {
						g.setColor(Color.BLUE);
					}
				int x = PIXEL_SIZE * i;
				int y = PIXEL_SIZE * j;
				g.fillRect(x, y, PIXEL_SIZE, PIXEL_SIZE);
				}
			}
		}
	}
	/****************************** end paint ************************************/

	/******************************************************************************
	 We make a new thread that does the computations. Here all the numerics are
	 implemented. This part has to be changed for every program you write.
	******************************************************************************/
	private class thread_sync_example_task extends Thread {
		/* Again global variables that can be seen by all functions in the thread. */
		JPanel panel;
		public thread_sync_example_task(JPanel panel) {
			/* This function is the constructor of the class and will be called
			 * whenever we make a new instance of thread_sync_example_task. Global
			 * variables of thread_sync_example_task can be initialized here. */
			this.panel = panel;
			// INITIALZE VARIABLES
		}

		public void update_grid() {
			/* This function goes through all grid points and changes their values. */
			for (int i = 0; i < GRID_SIZE; i++) {
				for (int j = 0; j < GRID_SIZE; j++) {
					if (grid[i][j] == 0) {
						grid[i][j] = 1;
					} else {
						grid[i][j] = 0;
					}

				}
			}
		}

		/******************************************************************************
		 The function run() is called whenever we start a task. Here we implement the
		 main loop that does the actual calculations.
		******************************************************************************/
		public void run() {
			/* First initialize variables (if you did not do it before). */
			for (int i = 0; i < GRID_SIZE; i++) {
				for (int j = 0; j < GRID_SIZE; j++) {
					grid[i][j] = 0;
				}
			}

			while (true) {
				/* Main loop of the program. */
				
				synchronized(lockobject) {
				/* Again lock the global variables. */
					update_grid();
				}

				/* Send a paint message to thread_sync_example to repaint the window. */
				panel.repaint();
				
				/* Short delay so we can see how the program evolves. */
//				try {
//					sleep(250);
//				} catch (InterruptedException e) {}
			}
		}
	/********************************** end run **********************************/
	}
	/******************************** end thread *********************************/
}
/******************************* end class ***********************************/

