#include <RTI.hh>
#include <fedtime.hh>
#include <NullFederateAmbassador.hh>

#include <iostream>

RTIfedTime* temps = new RTIfedTime(0.0);
RTIfedTime* lookahead = new RTIfedTime(1.0);

class Federe_Interactif : public RTI::RTIambassador, public NullFederateAmbassador
{
public:
  Federe_Interactif() {}
  virtual ~Federe_Interactif() throw (RTI::FederateInternalError) {}
  
private:
  void timeAdvanceGrant (const RTI::FedTime& theTime)
  throw (
    RTI::InvalidFederationTime,
    RTI::TimeAdvanceWasNotInProgress,
    RTI::FederateInternalError)
  {
    *(temps) = theTime;
    std::cout << std::endl << "t=" << ((RTIfedTime&)theTime).getTime() << " : <----- timeAdvanceGrant(" << ((RTIfedTime&)theTime).getTime() << ")"<< std::endl << std::endl;
  }

  void receiveInteraction (
          RTI::InteractionClassHandle       theInteraction, // supplied C1
    const RTI::ParameterHandleValuePairSet& theParameters,  // supplied C4
    const RTI::FedTime&                     theTime,        // supplied C4
    const char                             *theTag,         // supplied C4
          RTI::EventRetractionHandle        theHandle)      // supplied C1
  throw (
    RTI::InteractionClassNotKnown,
    RTI::InteractionParameterNotKnown,
    RTI::InvalidFederationTime,
    RTI::FederateInternalError)
  {
    std::cout << std::endl << "t=" << ((RTIfedTime&)theTime).getTime() << " : <----- receiveInteraction(" << ((RTIfedTime&)theTime).getTime() << ")" << std::endl;
  }

  void receiveInteraction (
          RTI::InteractionClassHandle       theInteraction, // supplied C1
    const RTI::ParameterHandleValuePairSet& theParameters,  // supplied C4
    const char                             *theTag)         // supplied C4
  throw (
    RTI::InteractionClassNotKnown,
    RTI::InteractionParameterNotKnown,
    RTI::FederateInternalError)
  {
    std::cout << std::endl << "     <----- receiveInteraction" << std::endl;
  }
};


//VARIABLE
Federe_Interactif* myFedere_Interactif = new Federe_Interactif();

int main(int argc, char **argv)
{

  int i;
  float d;
  char c, entree;

  if (argc!=2)
  {
    std::cout <<"Vous devez donner en parametre le nom du federe" << std::endl;
    exit(1);
  }

  while(1)
  {
    std::cout <<"Voulez-vous creer la federation ? [y/n]" << std::endl;
    scanf("%c", &c);
    scanf("%c", &entree);
    if (c=='y' || c=='n') break;
    std::cout <<"Vous devez entrer 'y' ou 'n'" << std::endl;
  }

//CREER
  if (c=='y')
  {
    myFedere_Interactif->createFederationExecution("Federation_Interactive","Federation_Interactive.fed");
    std::cout << "federation creee" << std::endl;
  }

//REJOINDRE
  myFedere_Interactif->joinFederationExecution(argv[1], "Federation_Interactive", myFedere_Interactif);
  std::cout << "federation rejointe" << std::endl;

//PUBLIER
  myFedere_Interactif->publishInteractionClass(myFedere_Interactif->getInteractionClassHandle("msg"));
  std::cout << "interaction publiee" << std::endl;

//SOUSCRIRE
  myFedere_Interactif->subscribeInteractionClass(myFedere_Interactif->getInteractionClassHandle("msg"), RTI::RTI_TRUE);
  std::cout << "interaction souscrite" << std::endl;

//DECLARER REGULATEUR ET CONTRAIN
#ifdef WITH_CERTI
  myFedere_Interactif->queryFederateTime(*temps);
  myFedere_Interactif->enableTimeRegulation(*temps, *lookahead);
  myFedere_Interactif->enableTimeConstrained();
  myFedere_Interactif->modifyLookahead(*(new RTIfedTime(1.0)));
#else
  bool timeRegulation = false;
  while (!timeRegulation)
  {
    try
      { myFedere_Interactif->enableTimeRegulation(*temps,*lookahead); }
    catch (RTI::EnableTimeRegulationPending&)
      { myFedere_Interactif->tick(0.1, 0.2); }
    catch (RTI::TimeRegulationAlreadyEnabled&)
      { timeRegulation = true; }
  }
  bool timeConstrained = false;
  while (!timeConstrained)
  {
  try
    { myFedere_Interactif->enableTimeConstrained(); }
  catch (RTI::EnableTimeConstrainedPending&)
    { myFedere_Interactif->tick(0.1, 0.2); }
  catch (RTI::TimeConstrainedAlreadyEnabled&)
    { timeConstrained = true; }
  }
#endif
  std::cout << "federe regulateur et contraint" << std::endl;

//SYNCHRONISER
  std::cout << std::endl << "Synchro manuel, tapez ENTREE continuer";
  getchar();
  std::cout << "federation synchronisee" << std::endl << std::endl;
  
  while(1)
  {
    while(1)
    {
      std::cout << std::endl <<"Choisissez une action : " << std::endl;
      std::cout <<"  1 : timeAdvanceRequest()" << std::endl;
      std::cout <<"  2 : nextEventRequest()" << std::endl;
      std::cout <<"  3 : sendInteraction()" << std::endl;
      std::cout <<"  5 : tick()" << std::endl;
      std::cout <<"  8 : Quitter la federation" << std::endl;
      if (c=='y')
        std::cout <<"  9 : Detruire la federation" << std::endl;
      scanf("%i", &i);
      scanf("%c", &entree);
      if (i==1 || i==2 || i==3 || i==5 || i==8) break;
      if (c=='y')
        { if (i==9) break; }
      if (c=='n')
        std::cout <<"Vous devez entrer 1, 2, 3, 5 ou 8" << std::endl << std::endl;
      if (c=='y')
        std::cout <<"Vous devez entrer 1, 2, 3, 5, 8 ou 9" << std::endl << std::endl;
    }

//TIME_ADVANCE_REQUEST
    if (i==1)
    {
      std::cout << std::endl << "t=" << temps->getTime() << " : Donner la date a laquelle vous souhaitez avancer : ";
      scanf("%f", &d);
      scanf("%c", &entree);
      myFedere_Interactif->timeAdvanceRequest(*(new RTIfedTime(d)));
      std::cout << std::endl << "t=" << temps->getTime() << " : -----> timeAdvanceRequest(" << d << ")" << std::endl;
    }

//NEXT_EVENT_REQUEST
    else if (i==2)
    {
      std::cout << std::endl << "t=" << temps->getTime() << " : Donner la date a laquelle vous souhaitez avancer : ";
      scanf("%f", &d);
      scanf("%c", &entree);
      myFedere_Interactif->nextEventRequest(*(new RTIfedTime(d)));
      std::cout << std::endl << "t=" << temps->getTime() << " : -----> nextEventRequest(" << d << ")" << std::endl;
    }

//SEND_INTERACTION
    else if (i==3)
    {
      std::cout << std::endl << "t=" << temps->getTime() << " : Donner la valeur de l'estampille voulue : ";
      scanf("%f", &d);
      scanf("%c", &entree);
      myFedere_Interactif->sendInteraction(myFedere_Interactif->getInteractionClassHandle("msg"), *(RTI::ParameterSetFactory::create(0)), *(new RTIfedTime(d)), "msg");
      std::cout << std::endl << "t=" << temps->getTime() << " : -----> sendInteraction(getInteractionClassHandle(-, -, " << d << ", -)" << std::endl;
    }

//TICK
    else if (i==5)
    {
      myFedere_Interactif->tick(0.1, 0.2);
      std::cout << std::endl << "t=" << temps->getTime() << " : -----> tick" << std::endl;
    }

//QUITTER
    else if (i==8)
    {
      myFedere_Interactif->resignFederationExecution(RTI::DELETE_OBJECTS_AND_RELEASE_ATTRIBUTES);
      std::cout << std::endl << "federation quittee" << std::endl;
      if (c=='n')
        break;
    }

//DETRUIRE
    else if (i==9)
    {
      myFedere_Interactif->destroyFederationExecution("Federation_Interactive");
      std::cout << std::endl << "federation detruite" << std::endl;
      break;
    }
  }

  exit(0);
}
