import java.util.*;
import java.io.*;
import java.net.*;
import java.lang.*;

public class fftmaster
{
   public static void main(String args[]) throws IOException
   {
      int job_id = 1;
      int task_id = 100;

      int main_pno;
      String main_pt;
      int gp_no;
      String gp_name;
      int pt_no;
      String  pt_name;

      int i,  status; 
		int nl;
      int matA[] = new int[16];

      JMPF def_obj = new JMPF(job_id, task_id);
      System.out.println("The hostname is " + def_obj.hostname);
      System.out.println("The host id is " + def_obj.host_id);

      gp_name = "gp1";
      gp_no = def_obj.CreatePortGroup(gp_name);

      System.out.println("Enter the no. of input elements : ");
      int no_ip_ele = System.in.read() - 48;
      nl = System.in.read();


      System.out.println("Enter the input elements : " );
      for (i = 0; i < no_ip_ele; i++)
      {
         matA[i] = System.in.read() - 48;
         nl = System.in.read();
      }

      main_pt = "main";
      main_pno = def_obj.CreatePort(main_pt);

// decimation is done by interchanging.
		int temp = matA[1];
		matA[1] = matA[2];
		matA[2] = temp;
      System.out.println ("No of input elements are "+no_ip_ele);

// send the inputs to the worker processes.
      for (i = 0; i <= (no_ip_ele/2); i+=2)
      {
         pt_no = def_obj.LocatePort(String.valueOf(i), true);
         String string = String.valueOf(1) + " ";
         string = string + String.valueOf(matA[i]) + " ";
         string = string + String.valueOf(matA[i+1]) + " ";
         status = def_obj.Send(pt_no, string);
			System.out.println("data is sent to the " +i+ "th worker");
         pt_no = def_obj.LocatePort(String.valueOf(i+1), true);
		   System.out.println("data is sent to the " +(i+1)+ "th worker");
         status = def_obj.Send(pt_no, string);
      } 

// receive the first stage results and store in the matrix A.
      Integer S = new Integer(2);
      synchronized(S)
      {
         for (i = 0; i < no_ip_ele; i++)
         {
            String str = def_obj.ReceiveString(main_pno);
            StringTokenizer st = new StringTokenizer(str);
            matA[i] = Integer.parseInt(st.nextToken());
         }
      }

// Send the first stage results to the workers for second stage calculation.
      for (i = 0; i < (no_ip_ele/2); i+=1)
      {
         pt_no = def_obj.LocatePort(String.valueOf(i), true);
         String string = String.valueOf(0) + " ";
         string = string + String.valueOf(matA[i]) + " ";
         string = string + String.valueOf(matA[i+2]) + " ";
         status = def_obj.Send(pt_no, string);
			System.out.println("data is sent to the " +i+ "th worker");
         pt_no = def_obj.LocatePort(String.valueOf(i+2), true);
		   System.out.println("data is sent to the " +(i+2)+ "th worker");
         status = def_obj.Send(pt_no, string);
      } 
// receive the second stage results and store in the matrix A.
      synchronized(S)
      {
         for (i = 0; i < no_ip_ele; i++)
         {
            String str = def_obj.ReceiveString(main_pno);
            System.out.println("After receive...");
            StringTokenizer st = new StringTokenizer(str);
            matA[i] = Integer.parseInt(st.nextToken());
         }
      }


      System.out.println("The result of the FFT calculation : " );
      for (i = 0; i < no_ip_ele; i++)
      {
         System.out.print(matA[i] + "   ");
         System.out.println("\n");
      }

      def_obj.ClosePorts();
   }
}

