import net.jini.core.lease.Lease;
import net.jini.core.entry.Entry;
import net.jini.space.JavaSpace;
import java.lang.reflect.Method;

/**
 * Base class for master/worker paradigm.
 *
 * @author Michael S. Noble (mnoble@cfa.harvard.edu) Copyright (c) 2000
 * This code may only be used under the terms of GNU General Public License.
 */

public abstract class Master {

    protected void init() { init(null,null); }
    protected void init(Entry template) { init(template,null); }
    
    protected void init(Entry template,String spaceName) {
	timer = new Timer();
	if (spaceName == null) spaceName = "JavaSpaces";
	space = SpaceAccessor.getSpace(spaceName);
	timer.checkp("contact space");
	try { snapshot = space.snapshot(template); }
	catch (Exception e) {e.printStackTrace();}
    }

    protected Task generateTask() { return null; }

    protected void distributeTasks() {

	try {
	    Timer dt = new Timer();
	    while ((task = generateTask()) != null) {
	    	space.write(task,null,Lease.FOREVER);
		// Help the garbage collector a little
		task = null;
	    }
	    dt.checkp("distribute the tasks");

        } catch (Exception e) { e.printStackTrace(); }

    }

    protected void collectTasks() {

	try {

	    Task template = new Task();
	    Entry snapshot;
	    template.done = new Boolean(true);
            snapshot = space.snapshot(template);

	    Timer ct = new Timer();
	    while (numTasksProcessed > 0) {
		task = (Task)space.take(snapshot,null,0);
		if (task != null) {
		   numTasksProcessed--;
                   System.out.print("\n"+name()+": got result for task #"+
					task.id.intValue()+" ...");
		   metaResult = task.mergeResult(metaResult);
		}
		else
		   Thread.sleep(5);
	    }

            System.out.println("");
	    ct.checkp("collect the tasks\n");

        } catch (Exception e) { e.printStackTrace(); }

    }

    public void reportResults() {
	try { rMethod.invoke(task,new Object[] {metaResult} ); }
	catch (Exception e) { e.printStackTrace(); }
    }

    // Somewhat analogous to UNIX 'shift' function, which is used to step
    // over command line arguments (see UNIX 'man shift' for more detail)
    protected void shift(String[] args,int count) {
	int i=0;
	while (arg < args.length && (i++ < count))
	    args[arg++] = "";
    }
    protected void shift() { shift(args,1);}

    protected String name() { return "Master"; }
    protected double format(double x) {return Math.round(10000*x)/10000.0;}

    protected JavaSpace space;
    protected Task task;
    protected Timer timer;
    protected Reporter reporter;
    protected Entry snapshot;
    protected int numIters;
    protected int numObjs;
    protected Object metaResult;	// combined result from all workers
    protected Class  rClass;		// for use w/ reflection api
    protected Method rMethod;
    protected short numTasksProcessed;
    protected String[] args;
    protected int arg;
}
