// © National University of Singapore. All rights reserved.

// Department of Computer Science
// National University of Singapore
// 3, Science Drive 2, Singapore 117543
// Tel: (65) 874 2830 Fax: (65) 779 4580

// Torus.java
// simulation model of the torus network
import spades_Java.*;

public class Torus extends Executive {
  // size of torus network
  static int M = 16;
  static int N = 16;
  static int NumNode = M * N;
  // The torus network
  torus_node torus[]; 

  // The following functions generate neighbours of current node i
  int North(int i)
  { return ((i < M) ? i-M+NumNode : i-M);}

  int West(int i)
  { return ((i%M == 0) ? i+M-1 : i-1);}

  int South(int i)
  { return ((i + M > NumNode-1) ? i+M-NumNode	: i+M);}

  int East(int i)
  { return ((i%M == M-1) ? i-M+1 : i+1);}

  public void init()
  {
    int i, j, ppno;
    
    torus = new torus_node[NumNode];

    for (i=0; i<NumNode; i++) 
    {
      // create torus nodes and set up the links
      String name = "torus["+i+"]";
      torus[i] = new torus_node(name);
      torus[i].node_id = i;
      torus[i].succ[0] = North(i);
      torus[i].succ[1] = West(i);
      torus[i].succ[2] = South(i);
      torus[i].succ[3] = East(i);
    }

    for (i=0; i<NumNode; i++) 
    {
      // generate 5 jobs for each of the torus nodes
      for (j=0; j<5; j++) 
      {
        Job job = new Job(i, this);
        mapProcess(job, torus[i]);      
        activate(job, exponential(0.1));
      }
    }
  }

  // main program
  public static void main(String args[])
  {
    Torus sc = new Torus();
    sc.initialize(args.length, args);
    sc.startSimulation();
  }
}

// a torus node modeled from a resource
class torus_node extends Resource
{
  public int succ[] = new int[4];   // store neighbour ids
  public int node_id;   						// id of this torus node
  
  public torus_node(String name)
  { super(name, 5.0, 1);}
}

// A job that is sent for execution at each of the torus node
class Job extends SProcess
{
  Torus torus;
  private int loc;       // current location of job
  private int dest;      // final destination of job

  public Job(int l, Torus t)
  {
    super();
    name = toString().toCharArray();
    torus = t;
    loc = l;                         
    
    // the next destination is generated using a random distribution
    dest = (int) (uniform() * torus.NumNode);
  }

  // main body of job
  public void execute() 
  {
		switch(getPhase())
		{
			case 1	:
			{
    			if (loc == dest) 
    			{ 
      				wait(5+exponential(60));
							phase = 2;
					}
    			else 
    			{   
    				// generate next location to go to
      				loc = torus.torus[loc].succ[(int)(uniform()*4)];
	      			work(torus.torus[loc], 5+exponential(60), 1); 
    			}
					break;
  		}
			case 2	:
			{
	 			// activate a new job then the current job term$
      	Job job = new Job(loc, torus);
      	activate(job, 5+exponential(60));
      	terminate();
			}
		}
  }
}

