import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

//-----------------------------------------------------------------------------
/**
 * @author Bryan Ritter
 * @version at least 2012-10-30_07:24:09.551503668_                     AM_Tue_Week+44_(-04:00:00EDT)
 */
//-----------------------------------------------------------------------------

class Car{
	// This is the version that generates the next car
	public Car(int id, int currentTime){
		//System.out.println("a new car being created!");
		Random generator = new Random();
		this.remainingPumpingTime = this.pumpingDuration = generator.nextInt(25)+1; // generate random numbers 1 to 25
		this.carReadyToPumpTime = currentTime + generator.nextInt(6);// generate random numbers 0 to 5 to add to currentTime...
		this.carID = id;
		//System.out.println("a new car has created!");
	}

	private int carID;
	/**
	 * @return the carID
	 */
	public int getCarID() {
		return carID;
	}

	private int carReadyToPumpTime;
	/**
	 * @return the pumpStartingTime
	 */
	public int getCarReadyToPumpTime() {
		return carReadyToPumpTime;
	}

	private int pumpingDuration;
	/**
	 * @return the pumpingDuration
	 */
	public int getPumpingDuration() {
		return pumpingDuration;
	}

	private int remainingPumpingTime;
	/**
	 * @return the remainingPumpingTime
	 */
	public int getRemainingPumpingTime() {
		return remainingPumpingTime;
	}

	/**
	 * 
	 * @return the remaining time left to pump
	 */
	int pumpCar(){
		//assert(remainingPumpingTime > 0);
		this.remainingPumpingTime--;

		return this.remainingPumpingTime; // returns the remaining time left to pump
	}
}

//-----------------------------------------------------------------------------
class pump{
	public pump(int pumpID, int currentTime) {
		//System.out.println("new pump being created!");
		this.myArr = new ArrayList<Car>();
		this.currentCar = 0; // in 'pump' this refers to the car at the pump
		this.qSize = 0;
		this.pumpID = pumpID;
		this.maxQSize =0;
	}

	private int maxQSize;
	/**
	 * @return the maxQSize
	 */
	public int getMaxQSize() {
		return maxQSize;
	}

	private int currentCar;
	private int qSize;
	private int pumpID;

	private ArrayList<Car> myArr;

	public void addCar(int id, int currentTime){
		this.qSize++;
		if(this.qSize>maxQSize){
			this.maxQSize = this.qSize;
		}
		myArr.add(new Car(id, currentTime));
	}
	public void addCar(Car myNewCar){
		this.qSize++;
		if(this.qSize>maxQSize){
			this.maxQSize = this.qSize;
		}
		myArr.add(myNewCar);
	}

	private int min_transit=Integer.MAX_VALUE;
	/**
	 * @return the min_transit
	 */
	public int getMin_transit() {
		return min_transit;
	}

	private int max_transit=Integer.MIN_VALUE;
	/**
	 * @return the max_transit
	 */
	public int getMax_transit() {
		return max_transit;
	}

	private int pumpMaxWait = 0;
	// returns the number of cars in line
	/**
	 * @return the pumpMaxWait
	 */
	public int getPumpMaxWait() {
		return pumpMaxWait;
	}

	public int usePump(int currentTime){
		//System.out.println("currentTime: " + currentTime);
		if(this.qSize > 0){ // if there are cars at the pump//, and the curentCar is finished 
			//System.out.println("qSize: " + qSize + " MyArr.get(" + currentCar + ").pumpCar(" + currentTime + ");");
			//System.out.println(myArr.get(currentCar));
			//System.out.println(currentCar);

			myArr.get(currentCar).pumpCar();

			if(myArr.get(currentCar).getRemainingPumpingTime()==0){ // pumpCar pumps the car and returns the time left at the pump
				System.out.println(" at " + currentTime + ", car " + myArr.get(currentCar).getCarID() + ", leaves pump [" + this.pumpID + "]");
				// ?could there be a better place for this 'if' statement?
				if(pumpMaxWait < currentTime-(myArr.get(currentCar).getCarReadyToPumpTime()+myArr.get(currentCar).getPumpingDuration())){
					pumpMaxWait = currentTime-(myArr.get(currentCar).getCarReadyToPumpTime()+myArr.get(currentCar).getPumpingDuration());
				}
				if(max_transit < currentTime - myArr.get(currentCar).getCarReadyToPumpTime() ){
					max_transit = currentTime - myArr.get(currentCar).getCarReadyToPumpTime();
				}
				if(min_transit > currentTime - myArr.get(currentCar).getCarReadyToPumpTime() ){
					min_transit = currentTime - myArr.get(currentCar).getCarReadyToPumpTime();
				}
				//myArr.remove(currentCar);
				//myArr.get(currentCar); // TODO: put somewhere
				this.qSize--; // this car has been removed
				this.currentCar++;
			} // else{ // do nothing... //}
		}
		return this.qSize;
	}

	public int getPumpQLength(){
		return this.qSize;
	}
}

//-----------------------------------------------------------------------------
/**
 * @author Bryan Ritter
 * 
 */
public class GasStation {

	/**
	 * 
	 */
	public GasStation() {

		System.out.println("How long do you want this to run?");
		Scanner in = new Scanner(System.in);
		int runTime = in.nextInt();

		this.nextCarID = 0;
		this.currentTime = 0;
		this.shortestQ=0;
		this.incomingCar = new Car(nextCarID,currentTime);

		this.myPumps = new pump[4];
		// Initialize the pumps
		for (int i = 0; i < 4; i++){
			this.myPumps[i] = new pump(i, currentTime);
		}

		for(int currentTime = 0; currentTime < runTime; currentTime++){
			// use all pumps, then add ready cars
			//System.out.println("\\ at " + currentTime + ", car " + nextCarID + ", arrives, and joins queue[" + shortestQ + "]");
			while(this.incomingCar.getCarReadyToPumpTime()==currentTime){
				//System.out.println("currentTime: " + currentTime);
				//System.out.println("nextCar.getCarReadyToPumpTime(): " + nextCar.getCarReadyToPumpTime() );
				this.shortestQ = usePumps(currentTime);
				this.myPumps[this.shortestQ].addCar(this.incomingCar);
				System.out.println(" at " + currentTime + ", car " + nextCarID + ", arrives, and joins queue[" + shortestQ + "]");
				this.nextCarID++;
				this.incomingCar = new Car(nextCarID,currentTime);
				//System.out.println(" at " + currentTime + ", car " + nextCarID + ", arrives, and joins queue[" + shortestQ + "]");
			}
		}
		System.out.println("Simulation is finished?");
		// TODO: get the cars from the pumps, and ...
		int maxWait = myPumps[0].getPumpMaxWait();
		//int minWait = myPumps[0].getPumpMinWait(); // not asked for
		int maxTransit = myPumps[0].getMax_transit();
		int minTransit = myPumps[0].getMin_transit();

		for(int i = 1; i < 4; i++){
			if(maxWait < myPumps[i].getPumpMaxWait()){
				maxWait = myPumps[i].getPumpMaxWait();
			}

			if(maxTransit < myPumps[i].getMax_transit()){	
				minTransit = myPumps[i].getMax_transit();
			}
			if(minTransit > myPumps[i].getMax_transit()){	
				minTransit = myPumps[i].getMax_transit();
			}			
		}
		System.out.println("max_transit = " + maxTransit);
		System.out.println("min_wait = " + minTransit);
		System.out.println("max_wait = " + maxWait);

		for(int i = 0; i < 4; i++){
			System.out.println("maxQsize[" + i + "] = " + this.myPumps[i].getMaxQSize() );
		}
	}

	private pump[] myPumps;// = new pump[4];
	private int nextCarID;
	private int currentTime;
	private Car incomingCar;
	private int shortestQ;

	// TODO: fix bad programming style?, does two things at once...
	int usePumps(int currentTime){

		int newQLength;
		int shortestQ = 0;

		int shortestQLength = myPumps[0].usePump(currentTime);

		for(int i = 1; i < 4; i++){
			myPumps[i].usePump(currentTime); // = newQLength;
			newQLength = myPumps[i].getPumpQLength();
			if(newQLength < shortestQLength){
				shortestQLength = newQLength;
				shortestQ = i;
			}
		}
		return shortestQ;
	}

	//-----------------------------------------------------------------------------
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new GasStation();
	}
}
