import java.util.Vector;
import java.util.Enumeration;

public class RecipePlan {
    Vector blocks = new Vector(); // ScheduleBlock's
    int maxTime = 0;
    Vector busyResources = new Vector(); // vector of ResourceAllocation's


    public boolean contains(RecipeBlock rb){
	for(Enumeration e = blocks.elements();
	    e.hasMoreElements();){
	    ScheduledBlock sb = (ScheduledBlock) e.nextElement();
	    if(sb.block == rb)
		return true;
	}
	return false;
    }

    public int time() {
	return maxTime;
    }

    public int size() {
	return blocks.size();
    }

    public int endTimeOf(RecipeBlock r){
	for(Enumeration e = blocks.elements();
	    e.hasMoreElements();){
	    ScheduledBlock sb = (ScheduledBlock) e.nextElement();
	    if(sb.block == r)
		return sb.endTime;
	}
	return 0;
    }

    public void addBlock(RecipeBlock rb, int when){
	blocks.addElement(new ScheduledBlock(rb, when));
	maxTime = ((when+rb.maxDuration) > maxTime) ? 
	    when+rb.maxDuration:maxTime;

	// Add resource allocations
	for(Enumeration e = rb.requiredResources.elements();
	    e.hasMoreElements();){
	    String r = (String) e.nextElement();
	    busyResources.addElement(new ResourceAllocation(r, when,
							    when+rb.maxDuration, rb));
	}
    }

    public void popBlock() {
	ScheduledBlock theblock = (ScheduledBlock) blocks.lastElement();
	RecipeBlock last = theblock.block;
	blocks.removeElement(theblock);
	maxTime = 0;
	for(Enumeration e = blocks.elements();
	    e.hasMoreElements();){
	    ScheduledBlock sb = (ScheduledBlock) e.nextElement();
	    maxTime = (sb.endTime > maxTime) ? sb.endTime:maxTime;
	}

	// Remove resource allocations
	for(Enumeration e = busyResources.elements();
	    e.hasMoreElements();){
	    ResourceAllocation ra = (ResourceAllocation) e.nextElement();
	    if(ra.block == last)
		busyResources.removeElement(ra);
	}
    }

    public int whenAvailable(String resource, int starting, int howlong){
	int ending = starting+howlong;
	for(Enumeration e = busyResources.elements();
	    e.hasMoreElements();){
	    ResourceAllocation ra = (ResourceAllocation) e.nextElement();
	    if(ra.resource.equals(resource)){
		if(((ending >= ra.start) && (ending < ra.end)) ||
		   ((starting >= ra.start) && (starting < ra.end)) ||
		   ((starting <= ra.start) && (ending > ra.end)))
		    return (ra.end-starting)+whenAvailable(resource, ra.end, howlong);
	    }
	}
	return 0;
    }

    public boolean goodToTime(int end, RecipeBlock added){
	int curStepStart = 0;
	int curStepEnd=0;
	Vector constraintList = new Vector();

	for(Enumeration e = blocks.elements();
	    e.hasMoreElements();
	    ){
	    ScheduledBlock sb = (ScheduledBlock) e.nextElement();
	    RecipeBlock rb = sb.block;
	    curStepEnd = sb.endTime;
	    curStepStart = sb.startTime;

	    // Add any constraints this has to our list
	    for(Enumeration e2 = rb.acceptableWaits.elements();
		     e2.hasMoreElements();){
		WaitConstraint wc = (WaitConstraint) e2.nextElement();
		System.out.println(wc.next.name+" has to start by "+((int) (wc.wait+curStepEnd)));
		constraintList.addElement(new WaitConstraint(wc.next, wc.wait+curStepEnd));
	    }

	    // Remove any constraints we've satisfied
	    // or check any constraints we've broken
	    for(Enumeration e2 = constraintList.elements();
		    e2.hasMoreElements();){
		WaitConstraint wc = (WaitConstraint) e2.nextElement();
		if(wc.next == rb){
		    if(wc.wait < curStepStart){
			System.out.println("      Current Step "+rb.name+" was supposed to have started by "+wc.wait+" not "+curStepStart);
			return false; // Missed it, barely
		    }
		    else{
			constraintList.removeElement(wc);
		    }
		}
		else
		    if(wc.wait < curStepEnd){
			System.out.println("      Step "+wc.next.name+" was supposed to have started by "+wc.wait);
			return false; // Missed it
		    }
	    }
	}
	return true;
    }

    public void print() {
	int start = 0;
	int end = 0;
	for(Enumeration e = blocks.elements();
	    e.hasMoreElements();){
	    ScheduledBlock sb = (ScheduledBlock) e.nextElement();
	    RecipeBlock rb = sb.block;
	    System.out.println("Time "+sb.startTime+" to "+sb.endTime+": "+rb.name);
	}
    }
}
