import java.util.*;
import java.io.*;

import RTIcap.*;             // The package containing our stubs.
import npacrti.*;            // The package containing our stubs.
import org.omg.CosNaming.*;  // 
import org.omg.CORBA.*;      // All CORBA applications need these classes.

/**
*  This demo is prepared to demostrate how you can use JavaRTI package.
*  This is a Java version of HelloWorld example coming with HLA RTI
*  releases.
*
* @date May 11, 1998 ( Updated May 11, 1998 )
* @author H. Timucin Ozdemir
*
*/
public class 
HelloWorld implements Runnable
{
   String  myCountryName = "zzz";
   double  myPopulation  = 100.0;
   int     MaximumNumberOfIterations = 10;
   Thread  runner;
   short   federateId;
   ORB     orb;

   String countryTypeStr = new String("Country");
   String countryNameTypeStr = new String("Name");
   String countryPopuTypeStr = new String("Population");
   short countryTypeId = -1;
   int countryNameTypeId = -1, countryPopuTypeId = -1;

   String countryCommTypeStr = new String("Communication");
   String countryCommMsgTypeStr = new String("Message");

   short  countryCommTypeId = -1;
   int    countryCommMsgTypeId = -1;

   java.lang.Object guard = new java.lang.Object();

   /** RTI Mappers */

   Hashtable className       = new Hashtable();
   Hashtable attributeName   = new Hashtable();
   Hashtable interactionName = new Hashtable();
   Hashtable parameterName   = new Hashtable();

   RTIcap.RTIambassador rtiAmb;

   SimCountry    myCountry;
   EntityManager EntityMng = new EntityManager();

   boolean       advanceGranted = false;
   double        currentTime = 0.0; 
   double        timeStep = 5.0; 
   double        requestTime ; 

   /**
   */
   public 
   HelloWorld( RTIcap.RTIambassador _rtiAmb, String countryName, 
               double initialPopulation, int number_of_iterations, ORB _orb )
   {
       rtiAmb = _rtiAmb;
       myCountryName = countryName;
       myPopulation = initialPopulation;
       MaximumNumberOfIterations = number_of_iterations;  
       orb = _orb;

   }// end of CONSTRUCTOR

   /**
   */
   public void
   start()
   {
      if(runner==null) 
      {
         runner = new Thread(this);
         runner.start();

      } else   runner.start();

   }// end of start()

   /**
   */
   public void
   stop()
   {
      if(runner!=null) 
      {
         runner.stop();
         runner = null;

      }// end of if

   }// end of stop()

   /**
   *
   * Gets the RTTI (Meta-Object Protocol MOP) handles.
   *
   * Ask RTI about the class indentifier of each object, attribute, 
   * interaction and parameter. So that we can define, subscribe, publish,
   * and interpret these attributes/objects.
   *
   */
   boolean getRtiIds()
   {
      boolean ret = false;

      if( rtiAmb != null )
      {
           try
           {
           countryTypeId = rtiAmb.getObjectClassHandle(countryTypeStr);
           } catch( RTIcap.FederateNotExecutionMember icnd ) {}
             catch( RTIcap.NameNotFound icnd ) {}
             catch( RTIcap.RTIinternalError icnd ) {}


           try
           {
           countryNameTypeId = 
                  rtiAmb.getAttributeHandle(countryNameTypeStr,countryTypeId );
           } catch( RTIcap.ObjectClassNotDefined icnd ) {}
             catch( RTIcap.NameNotFound icnd ) {}
             catch( RTIcap.FederateNotExecutionMember icnd ) {}
             catch( RTIcap.RTIinternalError icnd ) {}

           try
           { 
           countryPopuTypeId = 
                  rtiAmb.getAttributeHandle(countryPopuTypeStr, countryTypeId );
           } catch( RTIcap.ObjectClassNotDefined icnd ) {}
             catch( RTIcap.NameNotFound icnd ) {}
             catch( RTIcap.FederateNotExecutionMember icnd ) {}
             catch( RTIcap.RTIinternalError icnd ) {}

        
           try
           { 
           countryCommTypeId = 
                  rtiAmb.getInteractionClassHandle(countryCommTypeStr);
           } catch( RTIcap.NameNotFound icnd ) {}
             catch( RTIcap.FederateNotExecutionMember icnd ) {}
             catch( RTIcap.RTIinternalError icnd ) {}

           try
           { 
           countryCommMsgTypeId = 
                  rtiAmb.getParameterHandle(countryCommMsgTypeStr,countryCommTypeId);
             ret = true;
           } catch( RTIcap.InteractionClassNotDefined icnd ) {}
             catch( RTIcap.NameNotFound icnd ) {}
             catch( RTIcap.FederateNotExecutionMember icnd ) {}
             catch( RTIcap.RTIinternalError icnd ) {}

           /** Place them into a hashtable */

      }// end of if
  
      return ret;

   }// end of getRtiIds()

   /**
   *
   * Describe our interest for publishing objects and attributes.
   * Describe our interest for receiving objects and attributes.
   * Describe our interest for publishing interations and parameters.
   * Describe our interest for receiving interations and parameters.
   *
   */
   boolean publishSubscribe()
   {

      boolean ret = false;

      if( rtiAmb != null )
      {
           short[] myAttributes = new short[2];  
           myAttributes[0] = (short) countryNameTypeId;
           myAttributes[1] = (short) countryPopuTypeId;

           try 
           {
             rtiAmb.subscribeObjectClassAttributes( countryTypeId, myAttributes , RTIcap._Boolean.RTI_TRUE);
           } catch( RTIcap.ObjectClassNotDefined  flsc) {}
             catch( RTIcap.AttributeNotDefined  fnem) {}
             catch( RTIcap.FederateNotExecutionMember  fnem) {}
             catch( RTIcap.RTIinternalError  ie) {}
             catch( RTIcap.RestoreInProgress  rip) {}
             catch( RTIcap.SaveInProgress  sip) {}

           try 
           {
             rtiAmb.publishObjectClass( countryTypeId, myAttributes );
           } catch( RTIcap.ObjectClassNotDefined  flsc) {}
             catch( RTIcap.AttributeNotDefined  fnem) {}
             catch( RTIcap.FederateNotExecutionMember  fnem) {}
             catch( RTIcap.RTIinternalError  ie) {}
             catch( RTIcap.RestoreInProgress  rip) {}
             catch( RTIcap.SaveInProgress  sip) {}

           try
           {
             rtiAmb.subscribeInteractionClass( countryCommTypeId, RTIcap._Boolean.RTI_TRUE);
           } catch( RTIcap.FederateLoggingServiceCalls  flsc) {}
             catch( RTIcap.FederateNotExecutionMember  fnem) {}
             catch( RTIcap.RTIinternalError  ie) {}
             catch( RTIcap.RestoreInProgress  rip) {}
             catch( RTIcap.InteractionClassNotDefined  icnd) {}
             catch( RTIcap.SaveInProgress  sip) {}

           try
           {
             rtiAmb.publishInteractionClass( countryCommTypeId );
             ret = true;
           } catch( RTIcap.FederateNotExecutionMember fnem) {}
             catch( RTIcap.RestoreInProgress rip) {}
             catch( RTIcap.InteractionClassNotDefined icnd) {}
             catch( RTIcap.SaveInProgress sip) {}
             catch( RTIcap.RTIinternalError ie) {}

      }// end of if

      return ret;

   }// end of publishSubscribe()

   /**
   * 
   * We want to join the Federation but we do not know its ID and
   * whether it is on. Therefore, we first try to create this Federation.
   * If this federation is  already exists, we will receive the exception.
   * If not, it will be created for us.
   * Then we need to join this execution and get ourself a federate id.
   * 
   */
   boolean joinFederationExecution(RTIcap.FederateAmbassador fedAmb)
   {

      boolean ret = false;

      if( rtiAmb != null )
      {

         try {
           rtiAmb.createFederationExecution("HelloWorld","HelloWorld.fed");
         } catch( RTIcap.FederationExecutionAlreadyExists icnd) {}
           catch( RTIcap.RTIinternalError ie) {}

         try {
           federateId = rtiAmb.joinFederationExecution(myCountryName,"HelloWorld",fedAmb);
             ret = true;
         } catch( RTIcap.FederateAlreadyExecutionMember fnem) {}
           catch( RTIcap.FederationExecutionDoesNotExist icnd) {}
           catch( RTIcap.CouldNotOpenFED fnem) {}
           catch( RTIcap.ErrorReadingFED fnem) {}
           catch( RTIcap.SaveInProgress sip) {}
           catch( RTIcap.RestoreInProgress rip) {}
           catch( RTIcap.RTIinternalError ie) {}

      }// end of if

      return ret;

   }// end of joinFederationExecution() 

   /**
   *
   * Before we leave the Federation
   *  1. Delete all the object that we are suppose(promised) to simulate.
   *  2. resign from the federation.
   *  3. Try to destroy the federation execution. Note that if there 
   *     are still federates in the Federation, the federation execution
   *     won't be stopped. Only, we resign it. 
   *
   */
   void leaveFederationExecution()
   {

      if( rtiAmb != null )
      {

         try 
         {
           rtiAmb.deleteObjectInstance(myCountry.getObjectID(),"destroy");
         } catch( RTIcap.DeletePrivilegeNotHeld ie) {}
           catch( RTIcap.ObjectNotKnown ie) {}
           catch( RTIcap.FederateNotExecutionMember ie) {}
           catch( RTIcap.SaveInProgress ie) {}
           catch( RTIcap.RestoreInProgress ie) {}
           catch( RTIcap.RTIinternalError ie) {}

         try 
         {
           rtiAmb.resignFederationExecution(RTIcap.ResignAction.DELETE_OBJECTS_AND_RELEASE_ATTRIBUTES);
         } catch( RTIcap.InvalidResignAction ie) {}
           catch( RTIcap.FederateOwnsAttributes ie) {}
           catch( RTIcap.FederateNotExecutionMember ie) {}
           catch( RTIcap.RTIinternalError ie) {}

         try 
         {
           rtiAmb.destroyFederationExecution("HelloWorld");
         } catch( RTIcap.FederationExecutionDoesNotExist icnd) {}
           catch( RTIcap.FederatesCurrentlyJoined ie) {}
           catch( RTIcap.RTIinternalError ie) {}

      }// end of if

   }// end of leaveFederationExecution() 

   /**
   *
   * To register a new object to the RTI
   *   1. Get an ObjectId for the country object type. This will define
   *      a new instane for us.
   *   2. Define our simulation object(myCountry) with return information 
   *      so that SimCountry object knows what its ObjectID in this 
   *      federation.
   *
   */
   boolean registerMyCountry()
   {
      boolean ret = false;
      int     objInstanceId;

      if( rtiAmb != null )
      {

         try 
         {
             objInstanceId = rtiAmb.registerObjectInstance(countryTypeId);
             myCountry = new SimCountry(rtiAmb,this,myCountryName,myPopulation,objInstanceId);
             ret = true;

         } catch( RTIcap.ObjectClassNotDefined sip) {}
           catch( RTIcap.ObjectClassNotPublished sip) {}
           catch( RTIcap.SaveInProgress sip) {}
           catch( RTIcap.RestoreInProgress rip) {}
           catch( RTIcap.FederateNotExecutionMember icnd) {}
           catch( RTIcap.RTIinternalError ie) {}

      }// end of if

      return ret;

   }// end of joinFederationExecution() 
   
   /**
   */
   public void 
   run()
   {
      int count = 0;

      /*******************************************************************/
      /** Define FederateAmbassador for HelloWorld. This objects serves  */
      /** as a callback mechanism so that RTI can bring us the necessary */ 
      /** events.                                                        */
      /*******************************************************************/
      HwFederateAmbassador fedAmb = new HwFederateAmbassador(EntityMng,this);
      orb.connect(fedAmb);
      
      /************************************************************/
      /** Create FederationExecution, get RTI id of the objects,  */
      /** attributes, interactions, and parameters.               */
      /** Define interest for Subscription/Publishing.            */
      /** Define my simulated object.                             */
      /************************************************************/
      if( joinFederationExecution(fedAmb) && getRtiIds() && 
          publishSubscribe() && registerMyCountry() )
      {
        
        /*********************************************************************/
        /** TimeConstrained : we want to receive timestamped events in order */
        /*********************************************************************/
        resetTimeAdvanceGranted();

        try
        { 
          rtiAmb.enableTimeConstrained( );
        } catch( RTIcap.TimeAdvanceAlreadyInProgress aa ) {}
          catch( RTIcap.EnableTimeConstrainedPending aa ) {}
          catch( RTIcap.TimeConstrainedAlreadyEnabled aa ) {}
          catch( RTIcap.FederateNotExecutionMember aa ) {}
          catch( RTIcap.SaveInProgress aa ) {}
          catch( RTIcap.RestoreInProgress aa ) {}
          catch( RTIcap.RTIinternalError aa ) {}

        /***************************************************/
        /** Tick RTI to get timeConstrainedEnabled message */
        /***************************************************/
        tickRTI(2);

        /**********************************************************/
        /** TimeRegulating : We want to vote for time advancement */
        /**********************************************************/
        resetTimeAdvanceGranted();

        try
        { 
          rtiAmb.enableTimeRegulation( currentTime, 5.0 );
        } catch( RTIcap.TimeAdvanceAlreadyInProgress aa ) {}
          catch( RTIcap.EnableTimeRegulationPending aa ) {}
          catch( RTIcap.ConcurrentAccessAttempted aa ) {}
          catch( RTIcap.TimeRegulationAlreadyEnabled aa ) {}
          catch( RTIcap.InvalidLookahead aa ) {}
          catch( RTIcap.InvalidFederationTime aa ) {}
          catch( RTIcap.FederateNotExecutionMember aa ) {}
          catch( RTIcap.SaveInProgress aa ) {}
          catch( RTIcap.RestoreInProgress aa ) {}
          catch( RTIcap.RTIinternalError aa ) {}

        /**************************************************/
        /** Tick RTI to get timeRegulationEnabled message */
        /**************************************************/
        tickRTI(2);

        try
        { 
           rtiAmb.enableAsynchronousDelivery( );
        } 
          catch( RTIcap.FederateNotExecutionMember aa ) {}
          catch( RTIcap.AsynchronousDeliveryAlreadyEnabled aa ) {}
          catch( RTIcap.ConcurrentAccessAttempted aa ) {}
          catch( RTIcap.SaveInProgress aa ) {}
          catch( RTIcap.RestoreInProgress aa ) {}
          catch( RTIcap.RTIinternalError aa ) {}

        /**************************************************/
        /** Add my simulation object to the EntityManager */
        /**************************************************/
        EntityMng.add( myCountry.getObjectID(), myCountry );

        /***************/
        /** Event Loop */
        /***************/
        while( count++ < MaximumNumberOfIterations )
        {
           /***************************************************/
           /** Simulate the current population for my country */
           /***************************************************/
           myCountry.UpdateTime(currentTime);

           /***************************************************************/
           /** Print state of all the simulated objects in the Simulation */
           /***************************************************************/
           printSimObjects();
       
           /*****************/
           /** Advance time */
           /*****************/
           resetTimeAdvanceGranted();
           requestTime = currentTime + timeStep;

           /************************************/
           /** Try to advance the current time */
           /************************************/
           do
           {

              try
              { 
                rtiAmb.timeAdvanceRequest( requestTime );
              } catch( RTIcap.TimeAdvanceAlreadyInProgress aa ) {}
                catch( RTIcap.EnableTimeConstrainedPending aa ) {}
                catch( RTIcap.EnableTimeRegulationPending aa ) {}
                catch( RTIcap.InvalidFederationTime aa ) {}
                catch( RTIcap.FederationTimeAlreadyPassed aa ) {}
                catch( RTIcap.FederateNotExecutionMember aa ) {}
                catch( RTIcap.SaveInProgress aa ) {}
                catch( RTIcap.RestoreInProgress aa ) {}
                catch( RTIcap.RTIinternalError aa ) {}

             mySleep(2);

           } while( !isTimeAdvanceGranted() );
           
        }// end of while()

        /************************************/
        /** Leave the Federation Execution  */
        /************************************/
        leaveFederationExecution();

      }// end of if 

   }// end of run()

   /**
   */
   public void
   resetTimeAdvanceGranted()
   { synchronized(guard) { advanceGranted = false; } 
   }// end of resetTimeAdvanceGranted()

   /**
   * This method will be invoked by HwFededarateAmbassador object whenever
   *
   *   timeAdvanceGrant 
   *   timeConstrainedEnabled
   *   timeRegulationEnabled
   *
   * messages received.
   *
   */
   public void
   setTimeAdvanceGranted()
   { synchronized(guard) { advanceGranted = true; } 
   }// end of setTimeAdvanceGranted()

   /**
   */
   public boolean
   isTimeAdvanceGranted()
   { return advanceGranted ; 
   }// end of isTimeAdvanceGranted()

   /**
   */
   public void
   setCurrentTime( double _newTime)
   { 
     if( _newTime >= currentTime ) currentTime = _newTime;

   }// end of setCurrentTime()

   /**
   *
   * Prints all the objects in the EntityManager. Note that some of them
   * actually denotes the last state of the objects which are simulated 
   * by other clients. 
   *
   */
   public void
   printSimObjects()
   {
      Enumeration e = EntityMng.getAllEntities();
      double pop;
      String name;
      int    objId;
      Country c;
      System.out.println(" At time : "+currentTime);

      for(;e.hasMoreElements();)
      {
         c = (Country) e.nextElement();

         if( c!= null )
         {
            objId = c.getObjectID();
            name  = c.getName();
            pop   = c.getPopulation();

            System.out.println(objId+" "+name+" "+pop);

         }// end of if

      }// end of for

   }// end of printSimObjects()

   /**
   */
   public short
   getPopuAttributeId()
   {  return (short)countryPopuTypeId; }

   /**
   */
   public short
   getNameAttributeId()
   {  return (short)countryNameTypeId; }

   /**
   */
   public final void
   mySleep(long aa)
   {  
      try
      { if(runner != null ) runner.sleep(aa);
      } catch( java.lang.InterruptedException ie) {}

   }// end of mySleep()

   /**
   *
   * Ticks the RTIambassador. This will cause the delivery of waiting 
   * events in the Receive Order Queue.
   *
   */
   public void
   tickRTI( long sleepTime )
   {
      while( !isTimeAdvanceGranted() )
      {
         try { rtiAmb.tick( ); } 
         catch( RTIcap.RTIinternalError aa ) {}

         mySleep(2);

      }// end of while() 

   }// end of tickRTI()

   /**
   */
   public static void 
   main(String args[])
   {
     try
     {
      
        // Create and initialize the ORB
        ORB orb = ORB.init(args, null);
      
        /*  ----- This Part is required if we are using Naming Service ---
        // Get the root naming context
        org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
        NamingContext ncRef = NamingContextHelper.narrow(objRef);
      
        // Resolve the object reference in naming
        NameComponent nc = new NameComponent("RTIKernel", " ");
        NameComponent path[] = {nc};
        RTIKernelInterface rtiKernel = RTIKernelInterfaceHelper.narrow(ncRef.resolve(path));
        */

        try 
        {
           BufferedReader input = new BufferedReader(new FileReader("../IOR"));
           String strIOR = input.readLine();  // get IOR address of RTIKernelInterface
           if( strIOR != null )
           {
      
              RTIKernelInterface rtiKernel = RTIKernelInterfaceHelper.narrow(orb.string_to_object(strIOR));

              // Get the Version of the Kernel
              String version = rtiKernel.getVersion();
              System.out.println(" Version is : "+version);      

              if(args.length>2)
              {
                 RTIambassador rtiAmb = rtiKernel.createRTIAmbassador();
                 HelloWorld hello = new HelloWorld(rtiAmb,args[0],Double.valueOf(args[1]).doubleValue(),Integer.parseInt(args[2]),orb);
                 hello.start();

              }// end of if

           } else System.out.println(" IOR file is empty| \n "+
                        "I can not find the address of RTIKernelInterface ");

        } catch(java.io.FileNotFoundException fnf) {}
          catch(java.io.IOException ioe) {}
          catch(NumberFormatException ioe) {}
          
     } catch(Exception e) 
       {
         System.out.println("ERROR : " + e);
         e.printStackTrace(System.out);
       }  

  }// end of main()

}// end of HelloWorld()