//==================================================================================================
// S i m u l a t i o n                                                                    Interface
// S i m u l a t o r
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides classes to define the basic functionalities of a simulator. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "simulation/simulator.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guSimulationSimulator
#define guSimulationSimulator

// Headers //---------------------------------------------------------------------------------------
#include <bpp/simulation/event.hpp> /*INCLUDE*/
#include <jirk/bpp/simulation/simulatorframe.hpp> /*INCLUDE*/

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef SIMULATION_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  simulationSimulator
#define private_area simulationSimulator_private

namespace public_area  { /*NAMESPACE*/ using namespace simulationEvent; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniSimulationSimulator
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 class clScheduler;
 class clSimulator;
 //-----------------------------------------------------------------------------------Constant Types
 typedef const clScheduler ctScheduler;
 typedef const clSimulator ctSimulator;
}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erEmptySimulationScheduler; /* The simulation scheduler is empty. */
 /*ERROR*/ extern_error erInvalidSimulationDate; /* The simulation date is not valid. */
 /*ERROR*/ extern_error erSimulationNotRunning; /* The simulation is not running. */
 /*ERROR*/ extern_error erSimulationRunning; /* The simulation is running. */

 /*ERROR*/ extern_error erEndMeasureParameterMissing;
 /* The <CODE>end_measure</CODE> parameter is missing in the experiment file. */

 /*ERROR*/ extern_error erEndRunningParameterMissing;
 /* The <CODE>end_running</CODE> parameter is missing in the experiment file. */

 /*ERROR*/ extern_error erReplicationParameterMissing;
 /* The <CODE>replication</CODE> parameter is missing in the experiment file. */

 /*ERROR*/ extern_error erStartMeasureParameterMissing;
 /* The <CODE>start_measure</CODE> parameter is missing in the experiment file. */

 /*ERROR*/ extern_error erStartRunningParameterMissing;
 /* The <CODE>start_running</CODE> parameter is missing in the experiment file. */
}

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// S i m u l a t o r  Patterns //-------------------------------------------------------------------

 //----------------------------------------------------------------------------------------NewObject
 #define mpattern_newObject(X)                                                                     \
  /*METHOD clSimulator */                                                                          \
  /* Pattern to generate methods that build objects using constructors with <I>X</I> arguments. */ \
  public_property template <X(parameterize)> void newObject(prClass ** agPointer,X(signature)) {   \
   clAbstractPool * lcPool = atObjectPoolS[class_no(clObject,prClass)];                            \
                                                                                                   \
   if (lcPool==nil) *agPointer=new_object(prClass(*this,nil,X(argument1)));                        \
   else *agPointer=new_pool_object(*lcPool,prClass(*this,lcPool,X(argument1)));                    \
  }                                                                                                \

 //-----------------------------------------------------------------------------------------Schedule
 #define mpattern_schedule(X)                                                                   \
  /*METHOD clSimulator */                                                                       \
  /* Pattern to generate methods that schedule method call events (with <I>X</I> arguments). */ \
  public_property template <X(parameterize)>                                                    \
  inline void schedule(tyCardinal agDate,prClass * agObject,                                    \
                       void (prClass::*agMethod)(void),                                         \
                       tyCardinal agMethodNo,X(signature)) {                                    \
   typedef X(class)<X(instantiate)>          cpEvent;                                           \
   typedef typename cpEvent::tyMethodPointer cpMethod;                                          \
                                                                                                \
   clAbstractPool * lcPool     = atEventPoolS[class_no(clEvent,cpEvent)];                       \
   tyCardinal       lcPriority = atEventPriorityD[class_no(clObject,prClass)][agMethodNo];      \
                                                                                                \
   if (lcPool==nil) {                                                                           \
    lcPool=new_object(clPool<cpEvent>());                                                       \
    atEventPoolS[class_no(clEvent,cpEvent)]=lcPool;                                             \
   }                                                                                            \
                                                                                                \
   atScheduler->add(new_pool_object(*lcPool,cpEvent(*this,lcPool,agDate,lcPriority,agObject,    \
                                                    cpMethod(agMethod),X(argument1))));         \
  }                                                                                             \

// S c h e d u l e r  Interface //------------------------------------------------------------------
namespace public_area {
 /*CLASS clScheduler */
 /* Represents the scheduler of a simulator. It manages the time advance and the execution of the
    events in a simulation. */
 class clScheduler {
  //-----------------------------------------------------------------------------------------Private
  private_property typedef std_pair(tyCardinal,tyCardinal)    clPriority;
  private_property typedef std_multimap(clPriority,clEvent *) clEventX;

  private_property clSimulator & atSimulator;
  private_property clEventX      atEventX;
  //------------------------------------------------------------------------------------------Public
  public_property constructor clScheduler(clSimulator &);
  public_property destructor  clScheduler(void);

  public_property void      add(clEvent *);
  public_property tyBoolean empty(void) const;
  public_property void      nextEvent(void);
 };
}

// S i m u l a t o r  Interface //------------------------------------------------------------------
namespace public_area {
 /*CLASS clSimulator */
 /* Represents a simulator. It allows to perform a full simulation experiment. */
 class clSimulator : public clStillObject {
  //-----------------------------------------------------------------------------------------Friends
  friend class clPhysicalObject;
  friend class clScheduler;
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clSimulator */ /* Type of the parameters list read from the experiment file. */
  public_property typedef std_map(clString,clString) clParameterX;
  //-----------------------------------------------------------------------------------------Private
  private_property std_vector(clAbstractPool *)       atEventPoolS;
  private_property std_vector(std_vector(tyCardinal)) atEventPriorityD;
  private_property std_vector(clString)               atImageFileS;
  private_property std_vector(clAbstractPool *)       atObjectPoolS;
  private_property clScheduler *                      atScheduler;
  private_property tyCardinal                         atZombieCleaningFrequency;
  private_property tyCardinal                         atZombieCounter;
  private_property std_vector(clObject *)             atZombieS;

  private_property void      advanceTime(tyCardinal);
  private_property void      deleteEvent(clEvent *);
  private_property void      deleteZombies(void);
  private_property void      initialize(tcString);
  private_property tyPointer inspectedObject(void);

  private_property virtual void afterEvent(void);
  private_property virtual void beforeEvent(void);
  private_property virtual void endExperiment(void);
  private_property virtual void endReplication(void);
  private_property virtual void startExperiment(void);
  private_property virtual void startReplication(void);

  private_property constructor clSimulator(ctSimulator &);
  private_property clSimulator & operator = (ctSimulator &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clSimulator */ /* Indicates if the simulator must display information. */
  read_only_attribute(tyBoolean,atInformationDisplayed,informationDisplayed);

  /*ATTRIBUTE clSimulator */ /* Indicates if the simulator must provide a graphical animation. */
  read_only_attribute(tyBoolean,atGraphic,graphic);

  /*ATTRIBUTE clSimulator */ /* Java frame where the simulation is animated. */
  read_only_attribute(jirk::bpp::simulation::jaSimulatorFrame,atFrame,frame);

  /*ATTRIBUTE clSimulator */ /* Location of the data files used by the simulation. */
  read_only_attribute(clString,atDataLocation,dataLocation);

  /*ATTRIBUTE clSimulator */ /* Parameters read from the experiment file. */
  read_only_attribute(clParameterX,atParameterX,parameters);

  /*ATTRIBUTE clSimulator */ /* Random generator used for the simulation. */
  read_write_attribute(clRandomGenerator,atRandomGenerator,randomGenerator);

  /*ATTRIBUTE clSimulator */ /* Indicates if the simulator is running. */
  read_only_attribute(tyBoolean,atRunning,running);

  /*ATTRIBUTE clSimulator */ /* Start date of the simulation running. */
  read_only_attribute(tyCardinal,atStartRunningDate,startRunningDate);

  /*ATTRIBUTE clSimulator */ /* End date of the simulation running. */
  read_only_attribute(tyCardinal,atEndRunningDate,endRunningDate);

  /*ATTRIBUTE clSimulator */ /* Start date of the statistical measures in the simulation. */
  read_only_attribute(tyCardinal,atStartMeasureDate,startMeasureDate);

  /*ATTRIBUTE clSimulator */ /* End date of the statistical measures in the simulation. */
  read_only_attribute(tyCardinal,atEndMeasureDate,endMeasureDate);

  /*ATTRIBUTE clSimulator */ /* Number of replications of the simulation experiment. */
  read_only_attribute(tyCardinal,atNbReplication,nbReplication);

  /*ATTRIBUTE clSimulator */
  /* Current date of the simulation. Only relevant when the simulator is running. */
  read_only_attribute(tyCardinal,atDate,date);

  /*ATTRIBUTE clSimulator */
  /* Current replication of the simulation experiment. Only relevant when the simulator
     is running. */
  read_only_attribute(tyCardinal,atReplication,replication);

  public_property constructor clSimulator(java::jyObject,tcString,tyBoolean=false);
  public_property virtual destructor clSimulator(void);

  public_property void run(void);
  public_property void setMeasureRange(tyCardinal=0,tyCardinal=0);
  public_property void setNbReplication(tyCardinal=1);
  public_property void setRunningRange(tyCardinal=0,tyCardinal=0);

  public_property tyBoolean measuring(void) const;
  public_property tyBoolean paused(void) const;
  public_property tyBoolean stopped(void) const;

  public_property clString  imageFile(tyCardinal) const;
  public_property tcString  parameter(tcString) const;
  public_property tyBoolean parameterExists(tcString) const;

  public_property void deleteObject(clObject *);

  //---------------------------------------------------------------------------------------NewObject
  /*METHOD clSimulator */ /* Builds a new simulation object using the default constructor. */
  public_property template <class prClass> void newObject(prClass ** agPointer) {
   clAbstractPool * lcPool = atObjectPoolS[class_no(clObject,prClass)];

   if (lcPool==nil) *agPointer=new_object(prClass(*this,nil));
   else *agPointer=new_pool_object(*lcPool,prClass(*this,lcPool));
  }

  one_to_n(newObject);

  //----------------------------------------------------------------------------------------Schedule
  /*METHOD clSimulator */
  /* Schedules a method call event in the simulator. The method has no argument. */
  public_property template <class prClass>
  inline void schedule(tyCardinal agDate,prClass * agObject,void (prClass::*agMethod)(void),
                       tyCardinal agMethodNo) {
   typedef clMethodEvent<prClass>            cpEvent;
   typedef typename cpEvent::tyMethodPointer cpMethod;

   clAbstractPool * lcPool     = atEventPoolS[class_no(clEvent,cpEvent)];
   tyCardinal       lcPriority = atEventPriorityD[class_no(clObject,prClass)][agMethodNo];

   if (lcPool==nil) {
    lcPool=new_object(clPool<cpEvent>());
    atEventPoolS[class_no(clEvent,cpEvent)]=lcPool;
   }

   atScheduler->add(new_pool_object(*lcPool,cpEvent(*this,lcPool,agDate,lcPriority,agObject,
                                                    cpMethod(agMethod))));
  }

  one_to_n(schedule);
 };
}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// S i m u l a t o r  Inline //---------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------AdvanceTime
 inline void clSimulator::advanceTime(tyCardinal agDate) { atDate=agDate; }
 //--------------------------------------------------------------------------------------DeleteEvent
 inline void clSimulator::deleteEvent(clEvent * agEvent) {
  if (agEvent->pool()==nil) delete_object(agEvent);
  else delete_pool_object(*(agEvent->pool()),agEvent);
 }
 //----------------------------------------------------------------------------------SetMeasureRange
 /*METHOD clSimulator */
 /* Sets the measure range of a simulation, it indicates the date the statistical measures will
    start and the date it will end. If the end date is set to 0, that means the measures are
    collected until the end of the simulation. */
 inline void clSimulator::setMeasureRange(tyCardinal agStartDate,tyCardinal agEndDate) {
  if (running()) send_inline_error(erSimulationRunning,"simulator::setMeasureRange");
  atStartMeasureDate=agStartDate;
  atEndMeasureDate=(agEndDate==0 ? cardinalMax() : agEndDate);
 }
 //---------------------------------------------------------------------------------SetNbReplication
 /*METHOD clSimulator */
 /* Sets the number of replications of the simulation experiment. */
 inline void clSimulator::setNbReplication(tyCardinal agNbReplication) {
  if (running()) send_inline_error(erSimulationRunning,"simulator::setSetNbReplication");
  atNbReplication=agNbReplication;
 }
 //----------------------------------------------------------------------------------SetRunningRange
 /*METHOD clSimulator */
 /* Sets the running range of a simulation, it indicates the date the simulation will start and the
    date it will end. If the end date is set to 0, that means the simulation will stop when no
    event is scheduled anymore. */
 inline void clSimulator::setRunningRange(tyCardinal agStartDate,tyCardinal agEndDate) {
  if (running()) send_inline_error(erSimulationRunning,"simulator::setRunningRange");
  atStartRunningDate=agStartDate;
  atEndRunningDate=(agEndDate==0 ? cardinalMax() : agEndDate);
 }
 //----------------------------------------------------------------------------------------Measuring
 /*METHOD clSimulator */ /* Indicates if the date of the simulation is in the measure range. */
 inline tyBoolean clSimulator::measuring(void) const
 { return (date()>=startMeasureDate() and date()<=endMeasureDate()); }
 //-------------------------------------------------------------------------------------------Paused
 /*METHOD clSimulator */ /* Indicates if the simulation is paused. */
 inline tyBoolean clSimulator::paused(void) const
 { return (graphic() ? atFrame.j_paused()==java_true : false); }
 //------------------------------------------------------------------------------------------Stopped
 /*METHOD clSimulator */ /* Indicates if the simulation has been stopped. */
 inline tyBoolean clSimulator::stopped(void) const
 { return (graphic() ? atFrame.j_stopped()==java_true : false); }
 //----------------------------------------------------------------------------------------ImageFile
 /*METHOD clSimulator */
 /* Returns the location of the file containing the image that represents a given class of
    simulation objects. */
 inline clString clSimulator::imageFile(tyCardinal agClassNo) const
 { return (atImageFileS[agClassNo]); }
 //----------------------------------------------------------------------------------------Parameter
 /*METHOD clSimulator */
 /* Returns the value, read from the experiment file, of a given parameter. */
 inline tcString clSimulator::parameter(tcString agParameter) const
 { return (((clParameterX &)atParameterX)[clString(agParameter)].data()); }
 //----------------------------------------------------------------------------------ParameterExists
 /*METHOD clSimulator */
 /* Indicates if a given parameter can be read from the experiment file. */
 inline tyBoolean clSimulator::parameterExists(tcString agParameter) const
 { return (atParameterX.count(clString(agParameter))!=0); }
 //-------------------------------------------------------------------------------------DeleteObject
 /*METHOD clSimulator */ /* Destructs a simulation object. */
 inline void clSimulator::deleteObject(clObject * agObject) { atZombieS.push_back(agObject); }
}

// S c h e d u l e r  Inline //---------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clScheduler */
 /* Builds a scheduler. The simulator that will use this scheduler must be provided. */
 inline clScheduler::clScheduler(clSimulator & agSimulator)
 : atSimulator(agSimulator),atEventX() {}
 //----------------------------------------------------------------------------------------------Add
 /*METHOD clScheduler */ /* Adds an event into the scheduler. */
 inline void clScheduler::add(clEvent * agEvent) {
  atEventX.insert(std_make_pair(standard::make_pair(agEvent->date(),agEvent->priority()),agEvent));
 }
 //--------------------------------------------------------------------------------------------Empty
 /*METHOD clScheduler */ /* Indicates if the scheduler is empty. */
 inline tyBoolean clScheduler::empty(void) const { return (atEventX.begin()==atEventX.end()); }
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef mpattern_newObject
#undef mpattern_schedule
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// S i m u l a t i o n                                                               Implementation
// S i m u l a t o r
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "simulation/simulator.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define SIMULATION_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/simulation/simulator.hpp> /*INTERFACE*/
#include <jirk/java/lang/thread.hpp> /*NEED*/
#include <jirk/java/lang/string.hpp> /*NEED*/
#include <jirk/java/lang/system.hpp> /*NEED*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  simulationSimulator
#define private_area simulationSimulator_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Simulation/Simulator");

// Initialization //--------------------------------------------------------------------------------
#undef iniSimulationSimulator
static_constant(private_area::clInitializer,goInitializer);

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erEmptySimulationScheduler;
 static_error erInvalidSimulationDate;
 static_error erSimulationNotRunning;
 static_error erSimulationRunning;

 static_error erEndMeasureParameterMissing;
 static_error erEndRunningParameterMissing;
 static_error erReplicationParameterMissing;
 static_error erStartMeasureParameterMissing;
 static_error erStartRunningParameterMissing;
}

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// S i m u l a t o r  Implementation //-------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------DeleteZombies
 property void clSimulator::deleteZombies(void) {
  clPhysicalObject * lcObject;
  clAbstractPool *   lcPool;
  clObject *         lcZombie;

  tyBoolean           lcClean          = false;
  clVisualComponent * lcDummyContainer = nil;
  tyPointer           lcInspected      = inspectedObject();

  // Dummy Container Creation //
  if (graphic()) lcDummyContainer=new_object(clVisualComponent(clVisualComponent::j_new(atFrame)));

  // Zombie Objects Destruction //
  while (atZombieS.size()!=0) {
   lcZombie=atZombieS.back();
   atZombieS.pop_back();
   lcPool=lcZombie->pool();

   // Zombie Move To Dummy Container //
   if (lcDummyContainer!=nil) {
    lcObject=dynamic_cast<clPhysicalObject *>(lcZombie);

    if (lcObject!=nil and lcObject->view()!=java_nil) {
     lcObject->view().j_hide();
     lcDummyContainer->j_addInside(lcObject->view());
    }
   }

   // Zombie Destruction //
   if (lcPool==nil) delete_object(lcZombie);
   else delete_pool_object(*lcPool,lcZombie);

   // Zombie Counting & Garbage Collection Cleaning //
   ++atZombieCounter;

   if (atZombieCounter==atZombieCleaningFrequency) {
    atZombieCounter=0;
    lcClean=true;
   }

   // Inspector Update //
   if (lcInspected!=nil and lcZombie==lcInspected) {
    atFrame.j_setInspectedComponent(java_nil);
    lcInspected=nil;
   }
  }

  // Dummy Container Destruction //
  if (lcDummyContainer!=nil) {
   delete_object(lcDummyContainer);
   if (lcClean) jirk::java::lang::jaSystem::j_gc();
  }
 }
 //---------------------------------------------------------------------------------------Initialize
 property void clSimulator::initialize(tcString agExperimentFile) {
  method_name("simulator::initialize");

  clInFile lcFile;
  clString lcSeparator;
  clString lcValue;
  clString lcVariable;

  if (informationDisplayed()) {
   environment::out("Reading '",false,true);
   environment::out(agExperimentFile);
   environment::out("' Experiment File...",true);
  }

  // Experiment File Reading //
  lcFile.open(agExperimentFile,ios::in);
  lcFile >> lcVariable;

  while (not lcFile.fail() and lcVariable!="<end>" and lcVariable!="") {
   lcFile >> lcSeparator >> lcValue;
   atParameterX.insert(std_make_pair(lcVariable,lcValue));
   lcFile >> lcVariable;
  }

  lcFile.close();
  if (lcFile.fail()) send_error(erStreamReading);

  // Parameters Reading //
  if (not parameterExists("data_location")) send_error(erDataLocationParameterMissing);
  if (not parameterExists("end_measure")) send_error(erEndMeasureParameterMissing);
  if (not parameterExists("end_running")) send_error(erEndRunningParameterMissing);
  if (not parameterExists("replication")) send_error(erReplicationParameterMissing);
  if (not parameterExists("start_measure")) send_error(erStartMeasureParameterMissing);
  if (not parameterExists("start_running")) send_error(erStartRunningParameterMissing);

  setRunningRange(cardinal(parameter("start_running")),cardinal(parameter("end_running")));
  setMeasureRange(cardinal(parameter("start_measure")),cardinal(parameter("end_measure")));
  setNbReplication(cardinal(parameter("replication")));
  atDataLocation=parameter("data_location");

  if (parameterExists("zombie_cleaning_frequency"))
   atZombieCleaningFrequency=cardinal(parameter("zombie_cleaning_frequency"));

  // Graphical Update //
  if (graphic()) {
   atFrame.j_setRunningRange(startRunningDate(),endRunningDate());
   atFrame.j_setMeasureRange(startMeasureDate(),endMeasureDate());
   atFrame.j_setNbReplication(nbReplication());
   atFrame.j_setReplication(replication());

   if (parameterExists("text_size")) atFrame.j_setTextSize(cardinal(parameter("text_size")));
   if (parameterExists("speed")) atFrame.j_setSpeed(cardinal(parameter("speed")));
  }
 }
 //----------------------------------------------------------------------------------InspectedObject
 property tyPointer clSimulator::inspectedObject(void) {
  typedef jirk::java::lang::jaString jaString;

  tyPointer lcPointer = nil;

  if (graphic()) {
   clVisualComponent lcObject(simulator().frame().j_inspectedComponent());
   jaString          lcString;

   if (lcObject!=java_nil) {
    lcString=lcObject.j_nativePointer();
    lcPointer=pointer(lcString.native().data());
   }
  }

  return (lcPointer);
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSimulator */
 /* Builds a simulator that can provide a graphical animation in a Java frame of class
    <CODE>SimulatorFrame</CODE> (<CODE>nil</CODE> means there is no graphical animation). The file
    describing the simulation experiment must be provided. Detailed information can be displayed
    concerning the running of the experiment (default is not). */
 property clSimulator::clSimulator(java::jyObject agFrame,tcString agExperimentFile,
                                   tyBoolean agInformationDisplayed)
 :
   #ifdef VISUAL_9
    #pragma warning(disable : 4355)
   #endif

   clStillObject(*this,nil,true,0.0,0.0,"Simulator"),

   #ifdef VISUAL_9
    #pragma warning(default : 4355)
   #endif

   atEventPoolS(),atEventPriorityD(),atImageFileS(),atObjectPoolS(),atScheduler(nil),
   atZombieCleaningFrequency(100),atZombieCounter(0),atZombieS(),

   atInformationDisplayed(agInformationDisplayed),atGraphic(agFrame!=nil),atFrame(),
   atDataLocation(""),atParameterX(),atRandomGenerator(randomCardinal(cardinalMax())),
   atRunning(false),

   atStartRunningDate(0),atEndRunningDate(cardinalMax()),atStartMeasureDate(0),
   atEndMeasureDate(cardinalMax()),atNbReplication(1),atDate(0),atReplication(0) {

  tyCardinal lcCounter;
  tyCardinal lcNbMethod;

  if (informationDisplayed()) {
   environment::nextLine();
   environment::inform("Initializing Simulator...");
  }

  if (graphic()) atFrame=agFrame;

  // Image Files Initialization //
  atImageFileS.resize(clObject::classIndexer().nbClass(),clString("")); // By default, no image.

  // Object Pools Initialization //
  atObjectPoolS.resize(clObject::classIndexer().nbClass(),nil); // By default, no pool.

  // Event Priorities Initialization //
  atEventPriorityD.resize(clObject::classIndexer().nbClass(),std_vector(tyCardinal)());
  lcCounter=0;

  while (lcCounter<clObject::classIndexer().nbClass()) {
   lcNbMethod=clObject::classIndexer().nbMethod(lcCounter);
   atEventPriorityD[lcCounter].resize(lcNbMethod,100); // By default, the priority is 100.

   // Registered Simulation Classes Display //
   if (agInformationDisplayed) {
    environment::out("Object ",false,true);
    environment::out(lcCounter);
    environment::out(": ");
    environment::out(demangleType(clObject::classIndexer().className(lcCounter)));

    switch (lcNbMethod) {
     case 0:
      environment::nextLine();
      break;
     case 1:
      environment::out(" (1 Slot)",true);
      break;
     default:
      environment::out(" (");
      environment::out(lcNbMethod);
      environment::out(" Slots)",true);
    }
   }

   ++lcCounter;
  }

  // Event Pools Initialization //
  atEventPoolS.resize(clEvent::classIndexer().nbClass(),nil); // Created when needed.

  // Registered Simulation Events Display //
  if (agInformationDisplayed) {
   lcCounter=0;

   while (lcCounter<clEvent::classIndexer().nbClass()) {
    environment::out("Event ",false,true);
    environment::out(lcCounter);
    environment::out(": ");
    environment::out(demangleType(clEvent::classIndexer().className(lcCounter)),true);
    ++lcCounter;
   }
  }

  // Experiment Initialization //
  initialize(agExperimentFile);
 }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSimulator */ /* Destructs the simulator. */
 property clSimulator::~clSimulator(void) {
  tyCardinal lcCounter = atEventPoolS.size();

  while (lcCounter>0) {
   --lcCounter;
   if (atEventPoolS[lcCounter]!=nil) delete_object(atEventPoolS[lcCounter]);
  }

  lcCounter=atObjectPoolS.size();

  while (lcCounter>0) {
   --lcCounter;
   if (atObjectPoolS[lcCounter]!=nil) delete_object(atObjectPoolS[lcCounter]);
  }
 }
 //---------------------------------------------------------------------------------------AfterEvent
 /*METHOD clSimulator */
 /* Is called after each time advance. It can be overloaded, but the overload version must call
    this method after the execution of its own instructions. Protected method. */
 property void clSimulator::afterEvent(void) {
  if (graphic()) updateView();
  deleteZombies();
 }
 //--------------------------------------------------------------------------------------BeforeEvent
 /*METHOD clSimulator */
 /* Is called before each time advance. It can be overloaded, but the overload version must call
    this method before executing anything else. Protected method. */
 property void clSimulator::beforeEvent(void) {
  typedef jirk::java::lang::jaString jaString;
  typedef jirk::java::lang::jaThread jaThread;

  tyBoolean lcPaused = false;

  if (graphic()) {
   lcPaused=paused();

   if (lcPaused) atFrame.j_setStatus(jaString::j_new("Paused..."));
   else atFrame.j_setStatus(jaString::j_new("Running..."));

   atFrame.j_setClock(date());
  }

  if (lcPaused) while (paused() and not stopped()) jaThread::j_sleep(100);
  else if (graphic()) jaThread::j_sleep(30*(100-tyCardinal(atFrame.j_speed())));
 }
 //------------------------------------------------------------------------------------EndExperiment
 /*METHOD clSimulator */
 /* Is called at the end of the simulation experiment. It can be overloaded, but the overload
    version must call this method after the execution of its own instructions.
    Protected method. */
 property void clSimulator::endExperiment(void) {
  atRunning=false;

  if (graphic() and not stopped())
   atFrame.j_setStatus(jirk::java::lang::jaString::j_new("Finished..."));

  if (informationDisplayed()) environment::nextLine();
  environment::inform("Experiment Finished.");
 }
 //----------------------------------------------------------------------------------StartExperiment
 /*METHOD clSimulator */
 /* Is called at the start of the simulation experiment. It can be overloaded, but the overload
    version must call this method before executing anything else. Protected method. */
 property void clSimulator::startExperiment(void) {
  environment::nextLine();
  environment::inform("Starting Experiment...");

  atRunning=true;
  atReplication=1;

  if (graphic()) {
   atFrame.j_setPaused(java_true);
   atFrame.j_setStopped(java_false);
  }
 }
 //-----------------------------------------------------------------------------------EndReplication
 /*METHOD clSimulator */
 /* Is called at the end of a replication of the simulation experiment. It can be overloaded,
    but the overload version must call this method after the execution of its own instructions.
    Protected method. */
 property void clSimulator::endReplication(void) {
  deleteZombies();
  if (atScheduler!=nil) delete_object(atScheduler);
  atScheduler=nil;
  clear();
  deleteZombies();
  if (graphic()) jirk::java::lang::jaSystem::j_gc();
 }
 //---------------------------------------------------------------------------------StartReplication
 /*METHOD clSimulator */
 /* Is called at the start of a new replication of the simulation experiment. It can be overloaded,
    but the overload version must call this method before executing anything else.
    Protected method. */
 property void clSimulator::startReplication(void) {
  if (informationDisplayed()) environment::nextLine();
  environment::out("[>] Replication ");
  environment::out(atReplication);
  environment::out("...",true);

  if (graphic()) atFrame.j_setReplication(atReplication);
  if (atScheduler!=nil) delete_object(atScheduler);
  atScheduler=new_object(clScheduler(*this));
  atDate=startRunningDate();
  atZombieCounter=0;
 }
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSimulator */ /* Runs the simulation experiment. */
 property void clSimulator::run(void) {
  typedef jirk::java::lang::jaString jaString;

  startExperiment();

  while (replication()<=nbReplication() and not stopped()) {
   startReplication();
   if (graphic()) updateView();
   if (informationDisplayed()) environment::out("Running...",true,true);

   while (not atScheduler->empty() and not stopped() and date()<=endRunningDate())
    atScheduler->nextEvent();

   if (graphic()) {
    if (stopped()) atFrame.j_setStatus(jaString::j_new("Stopped..."));
    else atFrame.j_setStatus(jaString::j_new("Finished..."));
   }

   if (informationDisplayed()) environment::out("Stopped.",true,true);
   endReplication();
   ++atReplication;
  }

  endExperiment();
 }
}

// S c h e d u l e r  Implementation //-------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clScheduler */ /* Destructs the scheduler. The remaining events are destroyed. */
 property clScheduler::~clScheduler(void) {
  clEventX::const_iterator lcCurrentEvent = atEventX.begin();
  clEventX::const_iterator lcLastEvent    = atEventX.end();

  while (lcCurrentEvent!=lcLastEvent) {
   atSimulator.deleteEvent((*lcCurrentEvent).second);
   ++lcCurrentEvent;
  }
 }
 //----------------------------------------------------------------------------------------NextEvent
 /*METHOD clScheduler */ /* Executes the next event in the scheduler. */
 property void clScheduler::nextEvent(void) {
  method_name("scheduler::nextEvent");

  clEvent *          lcEvent;
  clEventX::iterator lcFirst;

  // Event Extraction //
  lcFirst=atEventX.begin();
  if (lcFirst==atEventX.end()) send_error(erEmptySimulationScheduler);
  lcEvent=(*lcFirst).second;

  if (lcEvent->date()!=atSimulator.date()) {
   atSimulator.afterEvent();
   atSimulator.beforeEvent();
  }

  atEventX.erase(lcFirst);

  // Event Execution //
  if (lcEvent->date()<atSimulator.date()) send_error(erInvalidSimulationDate);
  atSimulator.advanceTime(lcEvent->date());
  lcEvent->action();
  atSimulator.deleteEvent(lcEvent);
 }
}

// I n i t i a l i z e r  Implementation //---------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Start
 property void clInitializer::start(void) {
  if (atCounter++ == 0) {
   try {
    #include <bpp/modules.hpp> /*NEED*/
    registerStop(this);
    environment::informInitialization(goModuleName);

    erEmptySimulationScheduler.create("Simulation - The simulation scheduler is empty.");
    erInvalidSimulationDate.create("Simulation - The simulation date isn't valid.");
    erSimulationNotRunning.create("Simulation - The simulation is not running.");
    erSimulationRunning.create("Simulation - The simulation is running.");

    erEndMeasureParameterMissing.create("Simulation - The 'end_measure' parameter is missing.");
    erEndRunningParameterMissing.create("Simulation - The 'end_running' parameter is missing.");
    erReplicationParameterMissing.create("Simulation - The 'replication' parameter is missing.");
    erStartMeasureParameterMissing.create("Simulation - The 'start_measure' parameter is missing.");
    erStartRunningParameterMissing.create("Simulation - The 'start_running' parameter is missing.");
   }

   initializer_catch;
  }
 }
 //---------------------------------------------------------------------------------------------Stop
 property void clInitializer::stop(void) { environment::informTermination(goModuleName); }
}

// End //-------------------------------------------------------------------------------------------
}