import java.util.*;
import javax.swing.*;
//-----------------------------------------------------------------------------
//C a r S i m u l a t o r
//Klassen står for udførslen og koordineringen af selve simulationen
class CarSimulator implements Runnable
{
//Private variabler
private int MAX_CARQUEUES; //Angiver det makismale antal af køer
private int nrOfQueues = MAX_CARQUEUES;//Angiver det nuværende antal køer
private int meanArrivalTime = 0; //Angiver den gennemsnitlige ankomst tid i milisekunder for biler
private int diviasionArrivalTime = 0; //Angiver ankomst afvigelsen.
private Thread runner = null; //Producer tråden
private CarQueue[] carQueues; //Array af bil køer.!
//Funktioner
CarSimulator(CarQueuePanel[] carQueuePanels, SimulationResultPanel simulationResultPanel)
{
MAX_CARQUEUES = carQueuePanels.length;
carQueues = new CarQueue[MAX_CARQUEUES];
for(int i = 0; i < MAX_CARQUEUES; i++)
carQueues[i] = new CarQueue(carQueuePanels[i]);
CarQueue.setSimulationResultPanel(simulationResultPanel);
}
public boolean newSimulationSession(int meanArrivalTime, //Gennemsnitlige bil ankomst (sek)
int diviasionArrivalTime, //afvigelsen for ankomsten (sek)
int payTime, //betalings tiden (sek)
int nrOfQueues)//Antallet af ønskede simulerede køer
{
if(meanArrivalTime <= 0 || diviasionArrivalTime < 0 || meanArrivalTime < diviasionArrivalTime ||
payTime <= 0 || nrOfQueues <= 0 || nrOfQueues > MAX_CARQUEUES)
return false;
//Statiske variabler i CarQueue klargøres!
CarQueue.setPaymentTime(payTime);
CarQueue.resetTimeCalculations();
this.nrOfQueues = nrOfQueues;
this.meanArrivalTime = meanArrivalTime * 1000;
this.diviasionArrivalTime = diviasionArrivalTime * 1000;
for(int i = 0; i < nrOfQueues; i++)
carQueues[i].openQueue();
runner = new Thread(this);
runner.start();
return true;
}
public void stopSimulation()
{ if(runner != null)
{ runner.interrupt();
runner = null;
for(int i = 0; i < nrOfQueues; i++)
carQueues[i].closeQueue();
}
}
public void run()
{ int timeOffset = meanArrivalTime-diviasionArrivalTime;
try
{ while(!runner.interrupted())
{ carQueues[findSmallestQueue()].putNewCarInQueue(new Car());
runner.sleep((int)(Math.random()*2*diviasionArrivalTime + timeOffset));
}
}catch(InterruptedException e) {}
}
private int findSmallestQueue()
{ int nrOfSmallestQueue = 0;
int minimum = carQueues[nrOfSmallestQueue].nrOfCarsInQueue();
for(int i = 1; i < nrOfQueues; i++)
{ if(carQueues[i].nrOfCarsInQueue() < minimum)
{ nrOfSmallestQueue = i;
minimum = carQueues[i].nrOfCarsInQueue();
}
}
return nrOfSmallestQueue;
}
}
//-----------------------------------------------------------------------------
//C a r Q u e u e
//Klassen holder styr på selve bil køen og sørger for at hive bilerne ud af køen
//når det bliver deres tur til at betale. Herudover holder klassen også styr på
//de statistiske data som skal indsamles under simulationen.
class CarQueue implements Runnable
{
//Statiske variabler. (tider er angivet i milisekunder!)
static int payTime = 0;
static long totalWaitingTime = 0;
static long maximalWaitingTime = 0;
static int nrOfProcessedCars = 0;
static SimulationResultPanel simulationResultPanel = null;
//Statiske funktioner, der virker på de statiske variabler
public static void setPaymentTime(int time) { payTime = time * 1000; }
public static void setSimulationResultPanel(SimulationResultPanel srp)
{ simulationResultPanel = srp;
}
public static void resetTimeCalculations()
{ totalWaitingTime = 0;
maximalWaitingTime = 0;
nrOfProcessedCars = 0;
}
//Funktionen tilføjer en færdig bils statistiske data til de statiske variabler.
private static synchronized void finishedCar(long aCarsWaitingTime)
{ nrOfProcessedCars++;
simulationResultPanel.setProcessedCars(nrOfProcessedCars); //Grafik
totalWaitingTime += aCarsWaitingTime;
simulationResultPanel.setMeanWaitingTime((int)((totalWaitingTime/nrOfProcessedCars)/1000)); //Grafik
if(aCarsWaitingTime > maximalWaitingTime)
{ maximalWaitingTime = aCarsWaitingTime;
simulationResultPanel.setMaximalWaitingTime((int)(maximalWaitingTime/1000)); //Grafik
}
}
//Private variabler
private long freeTime = 0; //Angíver det tidspunkt hvor boden igen bliver fri.
private long openingTime = 0; //Angiver det tidspunkt i milis hvor boden blev åbnet!
private int processedCars = 0; //Antallet af behandlede biler for boden
private LinkedList carQueue = null; //Selve bil køen
private Thread runner = null; //Consumer tråden!
private CarQueuePanel myOutputPanel = null; //Noget grafik snavs så vi kan få opdateret parametrene
//Funktioner
CarQueue(CarQueuePanel myOutputPanel) { this.myOutputPanel = myOutputPanel; }
public void openQueue()
{ freeTime = 0;
processedCars = 0;
openingTime = System.currentTimeMillis();
carQueue = new LinkedList();
runner = new Thread(this);
runner.start();
}
public void closeQueue()
{ if(runner != null)
{ runner.interrupt();
runner = null;
openingTime = System.currentTimeMillis() - openingTime;
}
}
public void run()
{
boolean stoppedWaiting = false;
long myFreeTime = 0;
try
{ Car myNextCar = null;
while(!Thread.interrupted())
{
myFreeTime = System.currentTimeMillis();
stoppedWaiting = true;
while(!Thread.interrupted() && (myNextCar = nextCar()) == null);
freeTime += System.currentTimeMillis() - myFreeTime;
myOutputPanel.setFreeTime((int)(freeTime/1000)); //Grafik
stoppedWaiting = false;
try{ Thread.sleep(payTime); }catch(InterruptedException e) { return ; }
finishedCar(myNextCar.calculateCarWaitingTime());
processedCars++;
myOutputPanel.setFinishedCars(processedCars); //Grafik
}
}
catch(InterruptedException e)
{
if(stoppedWaiting) //Grafik
myOutputPanel.setFreeTime((int)((freeTime+(System.currentTimeMillis()-myFreeTime))/1000));
}
}
public synchronized int nrOfCarsInQueue() { return carQueue.size(); }
//Producer adgang til kø.
public synchronized void putNewCarInQueue(Car aCar)
{ carQueue.addFirst(aCar);
myOutputPanel.setWaitingCars(carQueue.size()); //Grafik
notifyAll();
}
//Consumer adgang til kø
private synchronized Car nextCar() throws InterruptedException
{
if(carQueue.size() == 0)
{
try{ wait(); }catch(InterruptedException e) { throw e; }
}
else
{
myOutputPanel.setWaitingCars(carQueue.size()-1); //Grafik
return (Car)carQueue.removeLast();
}
return null;
}
}
//-----------------------------------------------------------------------------
//C a r
//Klassen holder styr på hvornår en bil ankommer til en bil kø ved broen!
class Car
{
private long arrivalTime = 0; //Angiver tidspunktet for bilens ankomst til køen
Car() { arrivalTime = System.currentTimeMillis(); }
public long calculateCarWaitingTime() { return System.currentTimeMillis() - arrivalTime; }
}
//-----------------------------------------------------------------------------