/*
 * bondTupleSpaceEnabledStrateyg.java
 * @contains allows agents to access data
 *    and communicate with other agents
 *    thru Tuplespace. 
 *
 * @author Kyungkoo Jun
 * Bond group, CS, Purdue Univ.
 * @date October 20, 2000
 * 
 * modified by Kyungkoo Jun, Nov 8, 2000
 *   --- add getModelFromChannel()
 * modified by Kyungkoo Jun, Nov 7, 2000
 *   --- add getFromChannel(), putIntoChannel(), setupChannel();
 * modified by Kyungkoo Jun, Nov 2, 2000
 *   --- rename setToTupleSpace() into putIntoTupleSpace()
 * 
 */
package bond.agent.strategydb;

import com.ibm.tspaces.*;
import bond.agent.*;
import bond.agent.interfaces.*;
import java.io.*;

/*
  Strategies extending this strategy are able to
  communicate with other agents through TupleSpace
  TupleSpace was implemented by using IBM's TSpace
 */

public class bondTupleSpaceEnabledStrategy
extends bondDefaultStrategy 
{

  protected TupleSpace space, save;
  boolean inited = false;


  public Object getFromTupleSpace(String host, String sname, String s) 
    throws Exception
  {
    if (!setTupleSpace(host, sname))
      return null;
    return getFromTupleSpace(s);
  }

  public Object getFromTupleSpace(String s) 
    throws Exception
  {
    Tuple msg = space.waitToTake(s, new Field(Serializable.class));
    return (Object)msg.getField(1).getValue();
  }

  public Object copyFromTupleSpace(String host, String sname, String s) 
    throws Exception
  {
    if (!setTupleSpace(host, sname))
      return null;
    return copyFromTupleSpace(s);
  }

  public Object copyFromTupleSpace(String s) 
    throws Exception
  {
    Tuple msg = space.waitToRead(s, new Field(Serializable.class));
    return (Object)msg.getField(1).getValue();
  }

  public boolean putIntoTupleSpace(String host, String sname, String s, Serializable o) 
    throws Exception 
  {
    if (!setTupleSpace(host, sname))
      return false;
    return putIntoTupleSpace(s, o);
  }

  public boolean putIntoTupleSpace(String s, Serializable o)
    throws Exception
  {
      space.write(s, o);
      return true;
  }

  public boolean setTupleSpace(String host, String sname) {
    try {
      space = new TupleSpace(sname, host);
      return true;
    }
    catch (TupleSpaceException e) {
      System.out.println("Tuplespace init exception");
      return false;
    }
    catch (Exception e) {
      System.out.println("Tuplespace init exception");
      return false;
    }
  }

  public Object getFromChannel(String cname) {

    try {

      space.waitToRead(cname, new Field(Integer.class), new Field(Serializable.class));

      int iheadindex, itailindex;
      Tuple headindex = space.waitToTake(cname, "head", new Field(Serializable.class));
      Tuple tailindex = space.waitToRead(cname, "tail", new Field(Serializable.class));


      if (headindex != null && tailindex != null) {
	iheadindex = ((Integer)headindex.getField(2).getValue()).intValue();
	itailindex = ((Integer)tailindex.getField(2).getValue()).intValue();
	if (iheadindex > itailindex) {
	  space.write(cname, "head", new Integer(iheadindex));
	  return null;
	}
      }
      else {
	return null;
      }
      
      Tuple nextmodel = space.waitToTake(cname, new Integer(iheadindex), new Field(Serializable.class));
      if (nextmodel != null) {
	iheadindex++;
	space.write(cname, "head", new Integer(iheadindex));
	return (Object)nextmodel.getField(2).getValue();
      }
      else {
	return null;
      }
    }
    catch (TupleSpaceException e) {
      e.printStackTrace();
      return null;
    }
    catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }

  public Object getFromChannel(String host, String sname, String cname) {
    if (!setTupleSpace(host, sname))
      return null;
    return getFromChannel(cname);
  }

  public boolean getModelFromChannel(String host, String sname, String cname) {
    if (!setTupleSpace(host, sname))
      return false;
    return getModelFromChannel(cname);
  }

  public boolean getModelFromChannel(String cname) {
    Object o = getFromChannel(cname);
    if (o == null)
      return false;

    return fsm.agent.populateModel(o);
  }

  public boolean putIntoChannel(String cname, Serializable o) {

    try {
      int i_tail;
      Tuple tailindex = space.waitToTake(cname, "tail", new Field(Serializable.class));
      if (tailindex != null) {
	i_tail = ((Integer)tailindex.getField(2).getValue()).intValue();
      }
      else {
	return false;
      }
      i_tail++;
      space.write(cname, "tail", new Integer(i_tail));
      space.write(cname, new Integer(i_tail), o);
      return true;

    }
    catch (TupleSpaceException e) {
      return false;
    }
    catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }

  public boolean putIntoChannel(String host, String sname, String cname, Serializable o) {

    if (!setTupleSpace(host, sname))
      return false;
    return putIntoChannel(cname, o);

  }

  public boolean setupChannel(String cname) {

    try {
      space.write(cname, "head", new Integer(1));
      space.write(cname, "tail", new Integer(0));
      return true;
    }
    catch (TupleSpaceException e) {
      return false;
    }
    catch (Exception e) {
      e.printStackTrace();
      return false;
    }

  }

  public boolean setupChannel(String host, String sname, String cname) {
    if (!setTupleSpace(host, sname))
      return false;
    return setupChannel(cname);
  }


  public void install(bondFiniteStateMachine fsm) {
    super.install(fsm);

    if (!inited) {
      String host = (String)getModel("TupleServer");
      String sname = (String)getModel("SpaceName");
      if (host == null || sname == null) {
	inited = true;
	return;
      }
      inited = setTupleSpace(host, sname);
      System.out.println("Tuple Space Inited "+host+" "+sname);
    }
  }

}
