/*****************************************************
 * Exerc 15_19										 *
 * Objetivo: mostrar que um Thread de prioridade mais*
 * alta retarda a execução dos demais de menor 	     *
 * prioridade.                                       *
 *****************************************************/

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.text.*;

public class Exerc15_19 extends JApplet
		implements Runnable, ActionListener {

	//Constantes
	final static int SIZE = 5;
	final static int INTERVAL = 5000;

	JLabel[] lb		= new JLabel[SIZE];
	JSlider[] sl 	= new JSlider[SIZE];
	JCheckBox[] ck 	= new JCheckBox[SIZE];
	Thread[] th 	= new Thread[SIZE];

	long time = System.currentTimeMillis();
	long count = 0;

	public void init() {

		Container c = this.getContentPane();
		c.setLayout(new GridLayout(SIZE, 3));

		for (int i = 0; i < SIZE; i++) {
			lb[i] = new JLabel("Thread prioridade " + (i+1));
			sl[i] = new JSlider(JSlider.HORIZONTAL, 0, INTERVAL, 0);
			ck[i] = new JCheckBox("Suspender?");
			ck[i].addActionListener(this);
			c.add(lb[i]);
			c.add(sl[i]);
			c.add(ck[i]);
		}
	}

	public void start() {
		for (int i = 0; i < SIZE; i++) {
			th[i] = new Thread(this, "Thread" + i);
			th[i].setPriority(i+1);
			th[i].start(); //Inicia o Thread (Estado Pronto)
		}
	}

	public void run() {
		DecimalFormat dt = new DecimalFormat("0,000");
		Thread currThread = Thread.currentThread();
		try {
			int index = getIndex(currThread);
			while(true) {
				try {
					sl[index].setValue((sl[index].getValue()+1)%INTERVAL);
					synchronized(this) {
						if (ck[index].isSelected()) {
							wait();
						}
					}

				} catch (InterruptedException e) {
					System.out.println(e.toString());
				}
				count++;

				if (time < System.currentTimeMillis() + 1000) {
					showStatus("Desempenho: " + dt.format(count) +" lps");
					count = 0;
					time+= 1000;
				}
			}
		} catch (IndexThreadOutOfBound e) {
			System.out.println(e.toString());
		}
	}

	private int getIndex(Thread t) throws IndexThreadOutOfBound {
		for (int i=0; i<th.length; i++) {
			if (th[i] == t) {
				return i;
			}
		}

		throw new IndexThreadOutOfBound();

	}

	public synchronized void actionPerformed(ActionEvent e) {
		for (int i = 0; i < SIZE; i++) {
			if (!ck[i].isSelected()) {
				//th[i].notify();
				notifyAll();
			}
		}
	}

	public synchronized void stop() {
		for (int i=0; i<th.length; i++) {
			th[i] = null;
		}
		notifyAll();
	}
}


class IndexThreadOutOfBound extends Exception {
	public IndexThreadOutOfBound() {
		super("Thread não está no intervalo");
	}

	public IndexThreadOutOfBound(String msg) {
		super(msg);
	}
}