private void updateForecast(Sim_event ev) {
    	int pktID = (Integer) ev.get_data();	// ID of flow to be updated
    	FlowPacket fp = null;					// Reference to flow packet that needs forecast update
    	double duration = 0.0;					// New forecast duration from current Gridsim.clock()
    	long remSizeOld = 0;					// Previous remaining size 
    	double bandwidthOld = 0.0;				// Previous bottleneck BW
    	int sourceID = ev.get_src();			// ID of source of notification (FlowLink)
    	int cancelledFlow = 0;					// Count of canceled future events that match old forecast
    	
        //System.out.println(super.get_name() + ".updateForecast(): updating pkt id # " + pktID);

        // If flow hasn't already finished and been cleared...
        if ((fp = (FlowPacket) activeFlows_.get(pktID)) != null) {
        	remSizeOld = fp.getRemSize();
        	bandwidthOld = fp.getBandwidth();
        	//System.out.println(super.get_name() + "updateForecast(): rem size is " + remSizeOld + 
        	//		"BW old is " + bandwidthOld + " last update " + fp.getUpdateTime());
        	Iterator it = (fp.getLinks()).iterator();
        	
        	// Find the source link of this notification and the associated bottleneck bandwidth
        	while (it.hasNext()) {
        		FlowLink fl = (FlowLink) it.next();
        		if (fl.get_id() == sourceID) {
        			fp.setBandwidth(fl.getBaudRate());
        			fp.setBottleneckID(sourceID);
        		}
        	}
        	
        	fp.setRemSize((long)((remSizeOld) - ((GridSim.clock()-fp.getUpdateTime())*(bandwidthOld/NetIO.BITS))));
        	duration = (fp.getRemSize()*NetIO.BITS)/fp.getBandwidth();
        	//System.out.println(super.get_name() + " new forecast end time is " + (GridSim.clock() + duration));
        	
        	// Find old forecast and delete it!
        	FilterFlow filter = new FilterFlow(fp.getID(), GridSimTags.FLOW_HOLD);  	
            cancelledFlow = this.sim_cancel(filter, null);
        	
            /**** // debugging
        	if (cancelledFlow != 0) {
        		System.out.println(super.get_name() + ".updateForecast(): old forecast cancelled #matches " 
        				+ cancelledFlow);
        	}
            ******/
        	
        	//System.out.println(super.get_name() + " setting updated forecast for packet #" + fp.getID());
        	// Make a note of the time when this forecast update was performed
        	fp.setUpdateTime(GridSim.clock());
        	// Set new future event with the correct finish time
            super.sim_schedule(super.get_id(), duration, GridSimTags.FLOW_HOLD , new Integer(fp.getID()));
            
        }
    }