/*
 *  bondFaultMonitor.java
 *     @contains It performs periodic monitoring. See 
 *       README in this directory for detail.
 *     @author Kyungkoo Jun
 *     Bond group, CS, Purdue Univ.
 *     created on Nov 14, 2000
 *
 *     modified by Kyungkoo Jun, Dec. 4, 2000
 *        - The agents that monitor each other form a ring 
            monitoring topology that does not have the Jellyfish
	    configuration.
 */

package bond.agent.FaultDetection;

import bond.core.*;

public class bondFaultMonitor
extends bondFaultDetectionExecutable
{

  static final long MONITORING_INTERVAL = 30000; 
  long etime;

  bondShadow bs; // to be monitored
  String id;
  Object blocker;
  boolean change = false;

  private void setTarget(String aliasid) {
    this.id  = aliasid;
    bs = bondFaultStatus.buildShadow(aliasid);
  }

  public String getTarget() {
    return id;
  }

  public bondFaultMonitor(bondFaultStatus fs, String id) {
    super(fs);
    blocker = new Object();
    setTarget(id);
    go();
  }

  public void quitMonitoring() {
    
    change = true;
    synchronized (blocker) {
      blocker.notify();
    }

  }

  String candidate = null;
  public void quitMonitoring(String id) {
    candidate = id;
    quitMonitoring();
  }

  public void run() {

    while (!finish) {

      if (change) {

	if (!fs.isFaulty(id)) {

	  // send "stop monitoring message"
	  bondMessage msg = new bondMessage("(tell :content stop-monitoring)", "FaultDetection");
	  if (candidate != null)
	    msg.setParameter(":candidate", candidate);


	  filelogger.log(fs.getMyID()+" youAreOrphan");

	  bondMessage rep = bs.ask(msg, this, bondFaultStatus.WAIT_TIME);
	  if (finish)
	    return;
	  if (rep == null || 
	      rep.getSubprotocol() == null ||
	      !rep.getSubprotocol().equals("FaultDetection")) {
	    if (fs.foundFaulty(id)) {
	      fs.disseminateInfo(id);
	      if (fs.amIorphan()) {
		fs.startMonitorSearcher(false);
	      }
	    }
	  }
	  else {
	    //ignore "ok" message
	  }
	}
	dir.unregister(this);
	return;
      }


      if (id != null && !fs.isFaulty(id)) {
	bondMessage msg = new bondMessage("(tell :content test-msg)", "FaultDetection");

	filelogger.log(fs.getMyID()+" testing "+id);

	etime = System.currentTimeMillis();
	bondMessage rep = bs.ask(msg, this, bondFaultStatus.WAIT_TIME);
	etime = System.currentTimeMillis() - etime;
	if (finish)
	  return;
	if (rep == null || 
	    rep.getSubprotocol() == null ||
	    !rep.getSubprotocol().equals("FaultDetection")) {
	  if (fs.foundFaulty(id)) {
	    bondFaultStatus.Log(fs.getMyID(), " found "+id+" is fault");
	    fs.disseminateInfo(id);
	    if (fs.amIorphan()) {
	      fs.startMonitorSearcher(false);
	    }
	  }
	}
	else {
	  //ignore "fine" message
	}
      }
      else {
	// in the case of failure of being monitored,
	// simply return
	dir.unregister(this);
	fs.removeMonitor(this);
	return;
      }
      synchronized (blocker) {
	try {
	  blocker.wait(MONITORING_INTERVAL - etime);
	}
	catch (InterruptedException e) {
	}
      }
    }
    dir.unregister(this);
  }
}
