//==================================================================================================
// S i m u l a t o r                                                                      Interface
// U r b a n _ b u s
// M o d e l
//                                                                                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 a simulation model for flows of customers in an urban bus network. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "simulator/urban_bus/model.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guSimulatorUrbanBusModel
#define guSimulatorUrbanBusModel

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph.hpp> /*INCLUDE*/
#include <bpp/simulation.hpp> /*INCLUDE*/
#include <bpp/statistics.hpp> /*INCLUDE*/

namespace bpp {

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

// Namespaces //------------------------------------------------------------------------------------
#define public_area  simulatorUrbanBusModel
#define private_area simulatorUrbanBusModel_private

namespace public_area {
 /*NAMESPACE*/ using namespace graph;
 /*NAMESPACE*/ using namespace simulation;
 /*NAMESPACE*/ using namespace statistics;
}

namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniSimulatorUrbanBusModel
has_initializer;

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

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 class clBus;
 class clCustomer;
 class clCustomerFactory;
 class clCustomerMove;
 class clCustomerTravel;
 class clModel;
 class clSpot;
 //-----------------------------------------------------------------------------------Constant Types
 typedef const clBus             ctBus;
 typedef const clCustomer        ctCustomer;
 typedef const clCustomerFactory ctCustomerFactory;
 typedef const clCustomerMove    ctCustomerMove;
 typedef const clCustomerTravel  ctCustomerTravel;
 typedef const clModel           ctModel;
 typedef const clSpot            ctSpot;
}

namespace private_area {}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 function clInStream &  operator >> (clInStream &,std_vector(clCommodityData) &);
 function clOutStream & operator << (clOutStream &,const std_vector(clCommodityData) &);
 function clOutStream & operator << (clOutStream & agStream,ctCustomerTravel &);
 function clOutStream & operator << (clOutStream &,const std_map(tyCardinal,clCustomerTravel *) &);
 function clOutStream & operator << (clOutStream &,const std_map(tyCardinal,clVarianceCollector) &);
}

namespace private_area {}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erInvalidBusLineNumber; /* The bus line number is invalid. */
 /*ERROR*/ extern_error erWrongBusLine; /* The customer is affected to a wrong bus line. */
}

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

namespace private_area {
 extern_static_constant(private,tcString,goBusLineFlag,?);
 extern_static_constant(private,tcString,goBusLinesEndFlag,?);
 extern_static_constant(private,tcString,goBusLinesStartFlag,?);
 extern_static_constant(private,tcString,goBusMeansFlag,?);
 extern_static_constant(private,tcString,goCommoditiesEndFlag,?);
 extern_static_constant(private,tcString,goCommoditiesStartFlag,?);
 extern_static_constant(private,tcString,goCommodityFlag,?);
 extern_static_constant(private,tcString,goCustomerFlag,?);
 extern_static_constant(private,tcString,goCustomersEndFlag,?);
 extern_static_constant(private,tcString,goCustomersStartFlag,?);
 extern_static_constant(private,tcString,goFeetMeansFlag,?);
 extern_static_constant(private,tcString,goWaitingTimeFlag,?);
 extern_static_constant(private,tcString,goWaitingTimesEndFlag,?);
 extern_static_constant(private,tcString,goWaitingTimesStartFlag,?);
}

// B u s  Interface //------------------------------------------------------------------------------
namespace public_area {
 /*CLASS clBus */ /* Represents a bus in an urban network. */
 class clBus : public clMobileObject {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clBus */ /* Type of the list of paths used by the bus. */
  public_property typedef std_vector(clPath *) clTravel;
  //-----------------------------------------------------------------------------------------Private
  private_property tyCardinal atPosition;

  private_property tyReal timeToTarget(tyCardinal,clStillObject *);
  private_property void   updateStatus(void);

  private_property constructor clBus(ctBus &);
  private_property clBus & operator = (ctBus &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clBus */
  /* Speed of the bus, i.e. the factor that is multiplied to the distance to get the
     time of travel of the bus. */
  read_write_attribute(tyReal,atSpeed,speed);

  /*ATTRIBUTE clBus */ /* List of paths used by the bus. */
  read_write_attribute(clTravel,atTravel,travel);

  /*ATTRIBUTE clBus */ /* Number of the line the bus is serving. */
  read_only_attribute(tyCardinal,atLineNo,lineNo);

  /*ATTRIBUTE clBus */ /* Size of the bus, i.e. maximum number of customers inside the bus. */
  read_only_attribute(tyCardinal,atSize,size);

  public_property constructor clBus(clSimulator &,clAbstractPool *,tyReal=1.0,tyCardinal=0,
                                    tyCardinal=cardinalMax(),tcString="");

  public_property destructor clBus(void);

  public_property void       arrive(clPhysicalObject *);
  public_property tyCardinal bestPosition(clStillObject *,clStillObject *);
  public_property tyReal     bestTravelTime(clStillObject *,clStillObject *);
  public_property clPath *   currentPath(void) const;
 };
}

// C u s t o m e r M o v e  Interface //------------------------------------------------------------
namespace public_area {
 /*CLASS clCustomerMove */
 /* Represents a move of a customer, i.e. which path and means it is using to move. */
 class clCustomerMove {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clCustomerMove */ /* Type of the means the customer can use. */
  public_property enumeration { feet, bus } tyMeans;

  /*TYPE clCustomerMove */
  /* Type of the spots that the customer can cross and/or stay on. */
  public_property typedef clStillObject * tySpot;

  /*TYPE clCustomerMove */ /* Type of the paths the customer can use. */
  public_property typedef clPath * tyPath;
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clCustomerMove */ /* Means used to move. */
  read_write_attribute(tyMeans,atMeans,means);

  /*ATTRIBUTE clCustomerMove */ /* If the means is a bus, the number of the line of this bus. */
  read_write_attribute(tyCardinal,atLineNo,lineNo);

  /*ATTRIBUTE clCustomerMove */
  /* If the means is a bus, the spot where the customer moves in the bus. */
  read_write_attribute(tySpot,atEntry,entry);

  /*ATTRIBUTE clCustomerMove */
  /* If the means is a bus, the number of the spot where the customer moves in the bus. */
  read_write_attribute(tyCardinal,atEntryNo,entryNo);

  /*ATTRIBUTE clCustomerMove */ /* If the means is a bus, the time of travel. */
  read_write_attribute(tyReal,atTravelTime,travelTime);

  /*ATTRIBUTE clCustomerMove */
  /* If the means is a bus, the spot where the customer moves out of the bus. */
  read_write_attribute(tySpot,atExit,exit);

  /*ATTRIBUTE clCustomerMove */
  /* If the means is a bus, the number of the spot where the customer moves out of the bus. */
  read_write_attribute(tyCardinal,atExitNo,exitNo);

  /*ATTRIBUTE clCustomerMove */ /* If the means is its feet, the path the customer must use. */
  read_write_attribute(tyPath,atPath,path);

  /*ATTRIBUTE clCustomerMove */
  /* If the means is its feet, the number of the path the customer must use. */
  read_write_attribute(tyCardinal,atPathNo,pathNo);

  public_property constructor clCustomerMove(void);
  public_property constructor clCustomerMove(ctCustomerMove &);
  public_property destructor  clCustomerMove(void);

  public_property clCustomerMove & operator = (ctCustomerMove &);
 };
}

// C u s t o m e r T r a v e l  Interface //--------------------------------------------------------
namespace public_area {
 /*CLASS clCustomerTravel */
 /* Represents a travel of a customer, i.e. a list of consecutive moves. */
 class clCustomerTravel {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clCustomerTravel */ /* Type of the list of moves. */
  public_property typedef std_vector(clCustomerMove) clMoveS;

  /*TYPE clCustomerTravel */ /* Type of the source spot of the travel. */
  public_property typedef clPhysicalObject * tySource;
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clCustomerTravel */ /* Spot where the customer starts the travel. */
  read_write_attribute(tySource,atSource,source);

  /*ATTRIBUTE clCustomerTravel */ /* List of moves that describes the travel. */
  read_write_attribute(clMoveS,atMoveS,moves);

  /*ATTRIBUTE clCustomerTravel */ /* Number of the travel. */
  read_write_attribute(tyCardinal,atNumber,number);

  /*ATTRIBUTE clCustomerTravel */
  /* Minimum time the customer can possibly take to make the whole travel. */
  read_write_attribute(tyReal,atMinimumTime,minimumTime);

  /*ATTRIBUTE clCustomerTravel */
  /* Maximum time the customer can possibly take to make the whole travel. */
  read_write_attribute(tyReal,atMaximumTime,maximumTime);

  /*ATTRIBUTE clCustomerTravel */
  /* Statistical collector for the effective time the customer takes to make the whole travel. */
  read_write_attribute(clVarianceCollector,atEffectiveTime,effectiveTime);

  public_property constructor clCustomerTravel(void);
  public_property constructor clCustomerTravel(ctCustomerTravel &);
  public_property destructor  clCustomerTravel(void);

  public_property clCustomerTravel & operator = (ctCustomerTravel &);
 };
}

// C u s t o m e r  Interface //--------------------------------------------------------------------
namespace public_area {
 /*CLASS clCustomer */ /* Represents a customer in an urban network. */
 class clCustomer : public clMobileObject {
  //-----------------------------------------------------------------------------------------Private
  private_property tyCardinal         atPosition;
  private_property clCustomerTravel * atTravel;

  private_property void updateStatus(void);

  private_property constructor clCustomer(ctCustomer &);
  private_property clCustomer & operator = (ctCustomer &);
  //------------------------------------------------------------------------------------------------
  /*ATTRIBUTE clCustomer */ /* Date of creation of the object. */
  read_only_attribute(tyCardinal,atCreationDate,creationDate);

  /*ATTRIBUTE clCustomer */
  /* Speed of the customer, i.e. the factor that is multiplied to the distance to get the
     time of travel of the customer. */
  read_write_attribute(tyReal,atSpeed,speed);

  public_property constructor clCustomer(clSimulator &,clAbstractPool *,clCustomerTravel *,
                                         tyReal=1.0,tcString="");

  public_property clCustomerTravel & travel(void) const;

  public_property void             arrive(clPhysicalObject *);
  public_property tyBoolean        arrived(void) const;
  public_property clCustomerMove & currentMove(void);
  public_property ctCustomerMove & currentMove(void) const;
 };
}

// C u s t o m e r F a c t o r y  Interface //------------------------------------------------------
namespace public_area {
 /*CLASS clCustomerFactory */
 /* Represents a factory of customers. According to an exponential distribution, it creates
    customers that follow a specific travel. */
 class clCustomerFactory : public clStillObject {
  //-----------------------------------------------------------------------------------------Private
  private_property tyReal                    atCustomerSpeed;
  private_property clExponentialDistribution atDistribution;
  private_property clCustomerTravel *        atTravel;

  private_property constructor clCustomerFactory(ctCustomerFactory &);
  private_property clCustomerFactory & operator = (ctCustomerFactory &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clCustomerFactory(clSimulator &,clAbstractPool *,clCustomerTravel *,
                                                tyReal,tyReal,tcString="");

  public_property destructor clCustomerFactory(void);

  public_property void next(void);
  //--------------------------------------------------------------------------------------Reflection
  add_method_slot(next);
 };
}

// S p o t  Interface //----------------------------------------------------------------------------
namespace public_area {
 /*CLASS clSpot */ /* Represents a spot in an urban network. */
 class clSpot : public clStillObject {
  //-----------------------------------------------------------------------------------------Friends
  friend class clBus;
  //-----------------------------------------------------------------------------------------Private
  private_property void updateStatus(void);

  private_property constructor clSpot(ctSpot &);
  private_property clSpot & operator = (ctSpot &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clSpot */ /* X coordinate of the spot. */
  read_only_attribute(tyReal,atPositionX,positionX);

  /*ATTRIBUTE clSpot */ /* Y coordinate of the spot. */
  read_only_attribute(tyReal,atPositionY,positionY);

  /*ATTRIBUTE clSpot */
  /* Statistical collector for the waiting time of the customers at the spot. */
  read_only_attribute(clVarianceCollector,atWaitingTime,waitingTime);

  public_property constructor clSpot(clSimulator &,clAbstractPool *,tcString="",tyReal=0.0,
                                     tyReal=0.0,tyReal=0.0,tyReal=0.0);

  public_property destructor clSpot(void);
 };
}

// M o d e l  Interface //--------------------------------------------------------------------------
namespace public_area {
 /*CLASS clModel */
 /* Represents a simulation model for flows of customers in an urban bus network. */
 class clModel : public clSimulator {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clModel */ /* Type of the graph that represents the streets of the urban network. */
  public_property typedef clGraph<clNoData,clLocationData> clStreetGraph;
  //-----------------------------------------------------------------------------------------Private
  private_property std_map(tyCardinal,clPath *)            atArcX;
  private_property std_multimap(tyCardinal,clBus *)        atBusX;
  private_property std_vector(clCommodityData)             atCommodityS;
  private_property std_map(tyCardinal,clCustomerTravel *)  atCurrentTravelX;
  private_property std_map(tyCardinal,clCustomerTravel *)  atFinalTravelX;
  private_property clStreetGraph                           atGraph;
  private_property std_map(tyCardinal,clSpot *)            atNodeX;
  private_property std_map(tyCardinal,clVarianceCollector) atWaitingTimeX;

  private_property void cleanBusLines(void);
  private_property void createBusLines(clInStream &);
  private_property void createCommodities(void);
  private_property void createCustomerFactories(clInStream &);
  private_property void createNetwork(void);
  private_property void endExperiment(void);
  private_property void endReplication(void);
  private_property void startReplication(void);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clModel(java::jyObject,tcString,tyBoolean=false);
  public_property destructor  clModel(void);
 };
}

// B u s  Inline //---------------------------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clBus */ /* Destructs the bus. */
 inline clBus::~clBus(void) {}
 //--------------------------------------------------------------------------------------CurrentPath
 /*METHOD clBus */ /* Returns the path that the bus is actually using. */
 inline clPath * clBus::currentPath(void) const { return (atTravel[atPosition]); }
}

// C u s t o m e r M o v e  Inline //---------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCustomerMove */ /* Builds a default customer move (by feet, using no path). */
 inline clCustomerMove::clCustomerMove(void)
 : atMeans(feet),atLineNo(0),atEntry(nil),atEntryNo(0),atTravelTime(0.0),atExit(nil),
   atExitNo(0),atPath(nil),atPathNo(0) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCustomerMove */ /* Builds a customer move by copying another one. */
 inline clCustomerMove::clCustomerMove(ctCustomerMove & agMove)
 : atMeans(agMove.atMeans),atLineNo(agMove.atLineNo),atEntry(agMove.atEntry),
   atEntryNo(agMove.atEntryNo),atTravelTime(agMove.atTravelTime),atExit(agMove.atExit),
   atExitNo(agMove.atExitNo),atPath(agMove.atPath),atPathNo(agMove.atPathNo) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clCustomerMove */ /* Destructs the customer move. */
 inline clCustomerMove::~clCustomerMove(void) {}
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clCustomerMove */ /* Copies a customer move. */
 inline clCustomerMove & clCustomerMove::operator = (ctCustomerMove & agMove) {
  atMeans=agMove.atMeans;
  atLineNo=agMove.atLineNo;
  atEntry=agMove.atEntry;
  atEntryNo=agMove.atEntryNo;
  atTravelTime=agMove.atTravelTime;
  atExit=agMove.atExit;
  atExitNo=agMove.atExitNo;
  atPath=agMove.atPath;
  atPathNo=agMove.atPathNo;

  return (*this);
 }
}

// C u s t o m e r T r a v e l  Inline //-----------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCustomerTravel */ /* Builds an empty customer travel. */
 inline clCustomerTravel::clCustomerTravel(void)
 : atSource(nil),atMoveS(),atNumber(0),atMinimumTime(0.0),atMaximumTime(0.0),atEffectiveTime() {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCustomerTravel */ /* Builds a customer travel by copying another one. */
 inline clCustomerTravel::clCustomerTravel(ctCustomerTravel & agTravel)
 : atSource(agTravel.atSource),atMoveS(agTravel.atMoveS),atNumber(agTravel.atNumber),
   atMinimumTime(agTravel.atMinimumTime),atMaximumTime(agTravel.atMaximumTime),
   atEffectiveTime(agTravel.atEffectiveTime) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clCustomerTravel */ /* Destructs the customer travel. */
 inline clCustomerTravel::~clCustomerTravel(void) {}
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clCustomerTravel */ /* Copies a customer travel. */
 inline clCustomerTravel & clCustomerTravel::operator = (ctCustomerTravel & agTravel) {
  atSource=agTravel.atSource;
  atMoveS=agTravel.atMoveS;
  atNumber=agTravel.atNumber;
  atMinimumTime=agTravel.atMinimumTime;
  atMaximumTime=agTravel.atMaximumTime;
  atEffectiveTime=agTravel.atEffectiveTime;

  return (*this);
 }
}

// C u s t o m e r  Inline //-----------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------------------Travel
 /*METHOD clCustomer */ /* Returns the travel of the customer. */
 inline clCustomerTravel & clCustomer::travel(void) const { return (*atTravel); }
 //------------------------------------------------------------------------------------------Arrived
 /*METHOD clCustomer */ /* Indicates if the customer is arrived at its destination. */
 inline tyBoolean clCustomer::arrived(void) const
 { return (atPosition==atTravel->moves().size()); }
 //--------------------------------------------------------------------------------------CurrentMove
 /*METHOD clCustomer */ /* Returns the actual move of the customer. Read-write version. */
 inline clCustomerMove & clCustomer::currentMove(void) { return (atTravel->moves()[atPosition]); }
 //--------------------------------------------------------------------------------------CurrentMove
 /*METHOD clCustomer */ /* Returns the actual move of the customer. Read-only version. */
 inline ctCustomerMove & clCustomer::currentMove(void) const
 { return (atTravel->moves()[atPosition]); }
}

// C u s t o m e r F a c t o r y  Inline //---------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clCustomerFactory */ /* Destructs the factory. */
 inline clCustomerFactory::~clCustomerFactory(void) {}
}

// S p o t  Inline //-------------------------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSpot */ /* Destructs the spot. */
 inline clSpot::~clSpot(void) {}
}

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

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// S i m u l a t o r                                                                 Implementation
// U r b a n _ b u s
// M o d e l
//                                                                                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__ "simulator/urban_bus/model.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define SIMULATOR_URBAN_BUS_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/simulator/urban_bus/model.hpp> /*INTERFACE*/
#include <jirk/bpp/graphic/arrowcomponent.hpp> /*NEED*/
#include <jirk/bpp/graphic/imagecomponent.hpp> /*NEED*/
#include <jirk/java/awt/color.hpp> /*NEED*/
#include <jirk/java/lang/string.hpp> /*NEED*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  simulatorUrbanBusModel
#define private_area simulatorUrbanBusModel_private
#define dll_export   DLL_EXPORT

namespace public_area {
 using namespace jirk::bpp::graphic;
 using namespace jirk::bpp::simulation;
 using namespace jirk::java::awt;
 using namespace jirk::java::lang;
}

namespace private_area {}

static_module_name("Simulator/Urban_bus/Model");

// Initialization //--------------------------------------------------------------------------------
#undef iniSimulatorUrbanBusModel
static_constant(clInitializer,goInitializer);

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erInvalidBusLineNumber;
 static_error erWrongBusLine;
}

// Constants & Variables //-------------------------------------------------------------------------
static_constant(tcString,goBusLineFlag);
static_constant(tcString,goBusLinesEndFlag);
static_constant(tcString,goBusLinesStartFlag);
static_constant(tcString,goBusMeansFlag);
static_constant(tcString,goCommoditiesEndFlag);
static_constant(tcString,goCommoditiesStartFlag);
static_constant(tcString,goCommodityFlag);
static_constant(tcString,goCustomerFlag);
static_constant(tcString,goCustomersEndFlag);
static_constant(tcString,goCustomersStartFlag);
static_constant(tcString,goFeetMeansFlag);
static_constant(tcString,goWaitingTimeFlag);
static_constant(tcString,goWaitingTimesEndFlag);
static_constant(tcString,goWaitingTimesStartFlag);

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

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------Vector<CommodityData> Operator >>
 /*FUNCTION*/ /* Reads a list of commodities from a stream. */
 function clInStream & operator >> (clInStream & agStream,
                                    std_vector(clCommodityData) & agCommodityS) {
  method_name("std_vector(commodityData)::operator >>");

  clString lcString;

  agCommodityS.erase(agCommodityS.begin(),agCommodityS.end());
  agStream >> lcString;
  if (lcString!=private_area::goCommoditiesStartFlag) send_error(erStreamReading);
  agStream >> lcString;

  while (lcString==private_area::goCommodityFlag) {
   agStream >> lcString >> lcString;
   agCommodityS.push_back(clCommodityData(agStream));
   agStream >> lcString;
  }

  if (agStream.fail()) send_error(erStreamReading);
  return (agStream);
 }
 //----------------------------------------------------------------Vector<CommodityData> Operator <<
 /*FUNCTION*/ /* Writes a list of commodities into a stream. */
 function clOutStream & operator << (clOutStream & agStream,
                                     const std_vector(clCommodityData) & agCommodityS) {
  method_name("std_vector(commodityData)::operator <<");

  tyCardinal lcCounter = 0;

  agStream << private_area::goCommoditiesStartFlag << end_line;

  while (lcCounter<agCommodityS.size()) {
   agStream << private_area::goCommodityFlag << (lcCounter+1) << " = ";
   agCommodityS[lcCounter].out(agStream);
   agStream << end_line;
   ++lcCounter;
  }

  agStream << private_area::goCommoditiesEndFlag << end_line;

  if (agStream.fail()) send_error(erStreamWriting);
  return (agStream);
 }
 //-----------------------------------------------------------------------CustomerTravel Operator <<
 /*FUNCTION*/ /* Writes a customer travel into a stream. */
 function clOutStream & operator << (clOutStream & agStream,ctCustomerTravel & agTravel) {
  method_name("customerTravel::operator <<");

  tyCardinal lcCounter = 0;
  tyBoolean  lcBus     = false;
  tyBoolean  lcFeet    = false;

  while (lcCounter<agTravel.moves().size()) {
   if (agTravel.moves()[lcCounter].means()==clCustomerMove::feet) {
    if (not lcFeet) {
     if (lcBus) agStream << " ; ";
     agStream << private_area::goFeetMeansFlag << " : " << agTravel.moves()[lcCounter].pathNo();
     lcFeet=true;
    }
    else agStream << " , " << agTravel.moves()[lcCounter].pathNo();

    lcBus=false;
   }
   else {
    if (lcFeet or lcBus) agStream << " ; ";
    agStream << private_area::goBusMeansFlag << " " << agTravel.moves()[lcCounter].lineNo();
    agStream << " : " << agTravel.moves()[lcCounter].entryNo() << " , ";
    agStream << agTravel.moves()[lcCounter].exitNo();
    lcBus=true;
    lcFeet=false;
   }

   ++lcCounter;
  }

  agStream << " ; " << agTravel.minimumTime();
  agStream << " , " << agTravel.maximumTime();
  agStream << " , " << agTravel.effectiveTime().mean();

  if (agStream.fail()) send_error(erStreamWriting);
  return (agStream);
 }
 //---------------------------------------------------------Map<Cardinal,CustomerTravel> Operator <<
 /*FUNCTION*/ /* Writes a list of customer travels into a stream. */
 function clOutStream & operator << (clOutStream & agStream,
                                     const std_map(tyCardinal,clCustomerTravel *) & agTravelX) {
  method_name("std_map(cardinal,customerTravel)::operator <<");

  typedef std_map(tyCardinal,clCustomerTravel *)::const_iterator clIterator;

  clIterator lcCurrentTravel = agTravelX.begin();
  clIterator lcLastTravel    = agTravelX.end();

  agStream << private_area::goCustomersStartFlag << end_line;

  while (lcCurrentTravel!=lcLastTravel) {
   agStream << private_area::goCustomerFlag << " " << (*lcCurrentTravel).first << " = ";
   agStream << (*((*lcCurrentTravel).second)) << end_line;
   ++lcCurrentTravel;
  }

  agStream << private_area::goCustomersEndFlag << end_line;

  if (agStream.fail()) send_error(erStreamWriting);
  return (agStream);
 }
 //------------------------------------------------------Map<Cardinal,VarianceCollector> Operator <<
 /*FUNCTION*/ /* Writes a list of waiting times into a stream. */
 function clOutStream & operator <<
 (clOutStream & agStream,const std_map(tyCardinal,clVarianceCollector) & agCollectorX) {
  method_name("std_map(cardinal,varianceCollector)::operator <<");

  typedef std_map(tyCardinal,clVarianceCollector)::const_iterator clIterator;

  clIterator lcCurrentCollector = agCollectorX.begin();
  clIterator lcLastCollector    = agCollectorX.end();

  agStream << private_area::goWaitingTimesStartFlag << end_line;

  while (lcCurrentCollector!=lcLastCollector) {
   agStream << private_area::goWaitingTimeFlag << " " << (*lcCurrentCollector).first << " = ";
   agStream << (*lcCurrentCollector).second.mean() << end_line;
   ++lcCurrentCollector;
  }

  agStream << private_area::goWaitingTimesEndFlag << end_line;

  if (agStream.fail()) send_error(erStreamWriting);
  return (agStream);
 }
}

namespace private_area {}

// B u s  Implementation //-------------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------------TimeToTarget
 property tyReal clBus::timeToTarget(tyCardinal agPosition,clStillObject * agTarget) {
  tyBoolean lcFound;
  clPath *  lcPath;
  clSpot *  lcSource;
  clSpot *  lcTarget;
  tyReal    lcX;
  tyReal    lcY;

  tyReal     lcDistance = 0.0;
  tyCardinal lcPosition = agPosition;

  do {
   lcPath=atTravel[lcPosition];
   lcSource=static_cast<clSpot *>(lcPath->source());
   lcTarget=static_cast<clSpot *>(lcPath->target());
   lcX=lcTarget->positionX()-lcSource->positionX();
   lcY=lcTarget->positionY()-lcSource->positionY();
   lcDistance+=std::sqrt(lcX*lcX+lcY*lcY)*speed();
   lcFound=(lcTarget==agTarget);
   lcPosition=(lcPosition+1)%atTravel.size();
  }
  while (lcPosition!=agPosition and not lcFound);

  return (lcFound ? lcDistance : realMax());
 }
 //-------------------------------------------------------------------------------------UpdateStatus
 property void clBus::updateStatus(void) {
  clMobileObject::updateStatus();
  atStatus+="\nline = "+string(atLineNo);
  atStatus+="\nspeed = "+string(atSpeed);
  atStatus+="\nsize = "+(atSize==cardinalMax() ? clString("infinite") : string(atSize));
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clBus */
 /* Builds a bus object. Its speed (default is <I>1.0</I>), its line number (default is <I>0</I>),
    its size (default is infinite), and its name (default is an empty string) can be provided. */
 property clBus::clBus(clSimulator & agSimulator,clAbstractPool * agPool,tyReal agSpeed,
                       tyCardinal agLineNo,tyCardinal agSize,tcString agName)
 : clMobileObject(agSimulator,agPool,false,agName),atPosition(0),atSpeed(agSpeed),atTravel(),
   atLineNo(agLineNo),atSize(agSize) {
  clString lcFileName;

  if (simulator().graphic()) {
   view()=jaVisualComponent::j_new(simulator().frame());
   lcFileName=simulator().imageFile(class_no(simulation::clObject,clBus));

   if (lcFileName!="") {
    jaString         lcFile  = jaString::j_new(lcFileName.data());
    jaImageComponent lcImage = jaImageComponent::j_new(lcFile);

    view().j_setOutside(lcImage);
    view().j_setLayer(4);
   }
  }
 }
 //-------------------------------------------------------------------------------------------Arrive
 /*METHOD clBus */ /* Manages the arrival of the bus on a spot. */
 property void clBus::arrive(clPhysicalObject * agObject) {
  typedef clMobileChildS::const_iterator                        clChildIterator;
  typedef std_multimap(tyCardinal,clCustomer *)::const_iterator clCustomerIterator;

  tyCardinal lcCounter;
  tyReal     lcTravelTime;
  tyReal     lcX;
  tyReal     lcY;

  clChildIterator                       lcCurrentChild;
  clCustomerIterator                    lcCurrentCustomer;
  clCustomer *                          lcCustomer;
  std_multimap(tyCardinal,clCustomer *) lcInCustomerX;
  clChildIterator                       lcLastChild;
  clCustomerIterator                    lcLastCustomer;
  std_vector(clCustomer *)              lcOutCustomerS;
  tyCardinal                            lcPosition;

  clPath * lcPath   = currentPath();
  clSpot * lcSource = static_cast<clSpot *>(lcPath->source());
  clSpot * lcSpot   = dynamic_cast<clSpot *>(agObject);
  clSpot * lcTarget = static_cast<clSpot *>(lcPath->target());

  // Bus Arrival //
  clMobileObject::arrive(agObject);

  // Bus Departure //
  lcX=lcTarget->positionX()-lcSource->positionX();
  lcY=lcTarget->positionY()-lcSource->positionY();
  lcTravelTime=std::sqrt(lcX*lcX+lcY*lcY)*speed(); // *clExponentialDistribution(1/speed()).next();
  move(lcPath,tyCardinal(lcTravelTime));
  lcPosition=atPosition;
  atPosition=(atPosition+1)%travel().size();

  // Incoming Customers List //
  lcCurrentChild=agObject->mobileChildren().begin();
  lcLastChild=agObject->mobileChildren().end();

  while (lcCurrentChild!=lcLastChild) {
   lcCustomer=dynamic_cast<clCustomer *>(*lcCurrentChild);

   if (lcCustomer!=nil) {
    ctCustomerMove & lcMove = lcCustomer->currentMove();

    if (lcMove.means()==clCustomerMove::bus and lcMove.entry()==agObject
        and lcMove.lineNo()==lineNo()
        and isEqual(lcMove.travelTime(),timeToTarget(lcPosition,lcMove.exit())))
     lcInCustomerX.insert(std_make_pair(lcCustomer->arrivalDate(),lcCustomer));
   }

   ++lcCurrentChild;
  }

  // Outgoing Customers List //
  lcCurrentChild=mobileChildren().begin();
  lcLastChild=mobileChildren().end();

  while (lcCurrentChild!=lcLastChild) {
   lcCustomer=dynamic_cast<clCustomer *>(*lcCurrentChild);

   if (lcCustomer!=nil) {
    ctCustomerMove & lcMove = lcCustomer->currentMove();

    if (lcMove.means()==clCustomerMove::bus and lcMove.exit()==agObject)
     lcOutCustomerS.push_back(lcCustomer);
   }

   ++lcCurrentChild;
  }

  // Customers Leaving The Bus //
  lcCounter=0;

  while (lcCounter<lcOutCustomerS.size()) {
   lcCustomer=lcOutCustomerS[lcCounter];
   removeChild(lcCustomer);
   lcCustomer->arrive(agObject);
   ++lcCounter;
  }

  // Customers Arriving In The Bus //
  lcCurrentCustomer=lcInCustomerX.begin();
  lcLastCustomer=lcInCustomerX.end();

  while (lcCurrentCustomer!=lcLastCustomer and atMobileChildS.size()<size()) {
   lcCustomer=(*lcCurrentCustomer).second;

   if (lcSpot!=nil and simulator().measuring())
    lcSpot->atWaitingTime.add(simulator().date()-lcCustomer->arrivalDate());

   agObject->removeChild(lcCustomer);
   addChild(lcCustomer);
   ++lcCurrentCustomer;
  }
 }
 //-------------------------------------------------------------------------------------BestPosition
 /*METHOD clBus */
 /* Returns the position of the bus in its route (i.e. which arc it will use) so,
    when leaving a given source spot to move to a given target spot, the travel time is the best
    that the bus route can offer. */
 property tyCardinal clBus::bestPosition(clStillObject * agSource,clStillObject * agTarget) {
  clSpot * lcSource;
  tyReal   lcTime;

  tyReal     lcBestTime     = realMax();
  tyCardinal lcBestPosition = cardinalMax();
  tyCardinal lcPosition     = 0;

  while (lcPosition<atTravel.size()) {
   lcSource=static_cast<clSpot *>(atTravel[lcPosition]->source());

   if (lcSource==agSource) {
    lcTime=timeToTarget(lcPosition,agTarget);

    if (lcTime!=realMax() and lcTime<lcBestTime) {
     lcBestTime=lcTime;
     lcBestPosition=lcPosition;
    }
   }

   ++lcPosition;
  }

  return (lcBestPosition);
 }
 //-----------------------------------------------------------------------------------BestTravelTime
 /*METHOD clBus */ /* Returns the best travel time between two spots, using this bus. */
 property tyReal clBus::bestTravelTime(clStillObject * agSource,clStillObject * agTarget) {
  clSpot * lcSource;
  tyReal   lcTime;

  tyReal     lcBestTime = realMax();
  tyCardinal lcPosition = 0;

  while (lcPosition<atTravel.size()) {
   lcSource=static_cast<clSpot *>(atTravel[lcPosition]->source());

   if (lcSource==agSource) {
    lcTime=timeToTarget(lcPosition,agTarget);
    if (lcTime!=realMax() and lcTime<lcBestTime) lcBestTime=lcTime;
   }

   ++lcPosition;
  }

  return (lcBestTime);
 }
}

// C u s t o m e r  Implementation //---------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------------UpdateStatus
 property void clCustomer::updateStatus(void) {
  clMobileObject::updateStatus();
  atStatus+="\ncreation date = "+string(atCreationDate);
  atStatus+="\nspeed = "+string(atSpeed);
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCustomer */
 /* Builds a customer. Its travel must be provided. Its speed (default is <I>1.0</I>) and name
    (default is an empty string) can also be given. */
 property clCustomer::clCustomer(clSimulator & agSimulator,clAbstractPool * agPool,
                                 clCustomerTravel * agTravel,tyReal agSpeed,tcString agName)
 : clMobileObject(agSimulator,agPool,false,agName),atPosition(0),atTravel(agTravel),
   atCreationDate(agSimulator.date()),atSpeed(clExponentialDistribution(1/agSpeed).next()) {
  clString lcFileName;

  if (simulator().graphic()) {
   view()=jaVisualComponent::j_new(simulator().frame());
   lcFileName=simulator().imageFile(class_no(simulation::clObject,clCustomer));

   if (lcFileName!="") {
    jaString         lcFile  = jaString::j_new(lcFileName.data());
    jaImageComponent lcImage = jaImageComponent::j_new(lcFile);

    view().j_setOutside(lcImage);
    view().j_setLayer(5);
   }
  }
 }
 //-------------------------------------------------------------------------------------------Arrive
 /*METHOD clCustomer */ /* Manages the arrival of the object on a spot. */
 property void clCustomer::arrive(clPhysicalObject * agObject) {
  ctCustomerMove * lcMove;
  tyReal           lcTravelTime;
  tyReal           lcX;
  tyReal           lcY;

  clMobileObject::arrive(agObject);

  // Customer Is Arrived At Its Destination //
  if (arrived()) {
   if (simulator().measuring()) travel().effectiveTime().add(simulator().date()-creationDate());
   simulator().deleteObject(this);
  }

  // Customer Keeps Moving //
  else {
   lcMove=&(travel().moves()[atPosition]);

   // Customer Must Leave The Bus //
   if (lcMove->means()==clCustomerMove::bus and lcMove->exit()==agObject) {
    ++atPosition;

    // Customer Is Arrived At Its Destination //
    if (arrived()) {
     if (simulator().measuring()) travel().effectiveTime().add(simulator().date()-creationDate());
     simulator().deleteObject(this);
    }
    else lcMove=&(travel().moves()[atPosition]);
   }

   // Customer Is Walking //
   if (lcMove->means()==clCustomerMove::feet) {
    clPath * lcPath   = lcMove->path();
    clSpot * lcSource = static_cast<clSpot *>(lcPath->source());
    clSpot * lcTarget = static_cast<clSpot *>(lcPath->target());

    lcX=lcTarget->positionX()-lcSource->positionX();
    lcY=lcTarget->positionY()-lcSource->positionY();
    lcTravelTime=std::sqrt(lcX*lcX+lcY*lcY)*speed();
    move(lcPath,tyCardinal(lcTravelTime));
    ++atPosition;
   }
  }
 }
}

// C u s t o m e r F a c t o r y  Implementation //-------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clCustomerFactory */
 /* Builds a customer factory with a given yield. The travel the customers must follow and their
    speed are also provided. */
 property clCustomerFactory::clCustomerFactory(clSimulator & agSimulator,clAbstractPool * agPool,
                                               clCustomerTravel * agTravel,tyReal agCustomerSpeed,
                                               tyReal agYield,tcString agName)
 : clStillObject(agSimulator,agPool,false,0.0,0.0,agName),atCustomerSpeed(agCustomerSpeed),
   atDistribution(agSimulator.randomGenerator(),1/agYield),atTravel(agTravel) {
  tyCardinal lcDate = simulator().date()+tyCardinal(atDistribution.next());

  simulator().addChild(this);
  simulator().schedule(lcDate,this,method_id(clCustomerFactory,next));
 }
 //---------------------------------------------------------------------------------------------Next
 /*METHOD clCustomerFactory */ /* Produces the next customer. */
 void clCustomerFactory::next(void) {
  clCustomer * lcCustomer;
  tyCardinal   lcDate;

  simulator().newObject(&lcCustomer,atTravel,atCustomerSpeed,"Customer");
  lcCustomer->arrive(atTravel->source());
  lcDate=simulator().date()+tyCardinal(atDistribution.next());
  simulator().schedule(lcDate,this,method_id(clCustomerFactory,next));
 }
}

// S p o t  Implementation //-----------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------------UpdateStatus
 property void clSpot::updateStatus(void) {
  clStillObject::updateStatus();

  atStatus+="\nwaiting time = "+string(atWaitingTime.mean());
  atStatus+="\ncustomers = "+string(atWaitingTime.length());
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSpot */
 /* Builds a spot. The relative position of the object in the layout can be provided (default is
    <I>(0;0)</I>). The real position of the object (used for instance to compute Euclidean
    distances) can also be provided (default is <I>(0;0)</I>). */
 property clSpot::clSpot(clSimulator & agSimulator,clAbstractPool * agPool,tcString agName,
                         tyReal agRelativeX,tyReal agRelativeY,tyReal agPositionX,
                         tyReal agPositionY)
 : clStillObject(agSimulator,agPool,false,agRelativeX,agRelativeY,agName),atPositionX(agPositionX),
   atPositionY(agPositionY) {
  clString lcFileName;

  if (simulator().graphic()) {
   view()=jaVisualComponent::j_new(simulator().frame());
   lcFileName=simulator().imageFile(class_no(simulation::clObject,clSpot));

   if (lcFileName!="") {
    jaString         lcFile  = jaString::j_new(lcFileName.data());
    jaImageComponent lcImage = jaImageComponent::j_new(lcFile);

    view().j_setOutside(lcImage);
    view().j_setLayer(3);
   }
  }
 }
}

// M o d e l  Implementation //---------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clModel */
 /* Builds an urban bus simulation model. The experiment file must be provided. Detailed
    information can be displayed concerning the running of the experiment (default is not). */
 property clModel::clModel(java::jyObject agFrame,tcString agExperimentFile,tyBoolean agDisplayed)
 : clSimulator(agFrame,agExperimentFile,agDisplayed),atArcX(),atBusX(),atCommodityS(),
   atCurrentTravelX(),atFinalTravelX(),atGraph(),atNodeX(),atWaitingTimeX() {
  atObjectPoolS[class_no(simulation::clObject,clCustomer)]=new_object(clPool<clCustomer>());
  atObjectPoolS[class_no(simulation::clObject,clSpot)]=new_object(clPool<clSpot>());
  atObjectPoolS[class_no(simulation::clObject,clPath)]=new_object(clPool<clPath>());
 }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clModel */ /* Destructs the simulation model. */
 property clModel::~clModel(void) {}
 //---------------------------------------------------------------------------------StartReplication
 property void clModel::startReplication(void) {
  clInFile         lcFile;
  clString         lcFileName;
  jaImageComponent lcImage;

  // Replication Initialization //
  if (graphic()) atFrame.j_setStatus(jaString::j_new("Initializing Replication..."));
  clSimulator::startReplication();

  // City Component Creation //
  name()="City Map";

  if (graphic()) {
   view()=jaVisualComponent::j_new(atFrame);

   if (parameterExists("map_image")) {
    lcFileName=dataLocation()+fileNameSeparator()+parameter("map_image");
    lcImage=jaImageComponent::j_new(jaString::j_new(lcFileName.data()));
    view().j_addInside(lcImage,0);
    atFrame.j_setSelectedComponent(view());
   }
  }

  // Network Creation //
  if (informationDisplayed()) environment::out("Creating Network...",true,true);

  if (parameterExists("graph_file")) {
   lcFileName=dataLocation()+fileNameSeparator()+parameter("graph_file");
   open(lcFile,lcFileName.data(),ios::in);
   lcFile >> atGraph;
   close(lcFile);
   createNetwork();
  }

  // Commodities Creation //
  if (informationDisplayed()) environment::out("Creating Demands...",true,true);

  if (parameterExists("demand_file")) {
   lcFileName=dataLocation()+fileNameSeparator()+parameter("demand_file");
   open(lcFile,lcFileName.data(),ios::in);
   lcFile >> atCommodityS;
   close(lcFile);
   createCommodities();
  }

  // Mobile Objects Creation //
  if (informationDisplayed()) environment::out("Creating Mobile Objects...",true,true);

  if (parameterExists("path_file")) {
   lcFileName=dataLocation()+fileNameSeparator()+parameter("path_file");
   open(lcFile,lcFileName.data(),ios::in);
   if (informationDisplayed()) environment::out("Creating Bus Lines...",true,true);
   createBusLines(lcFile);
   if (informationDisplayed()) environment::out("Creating Customer Factories...",true,true);
   createCustomerFactories(lcFile);
   cleanBusLines();
   close(lcFile);
  }
 }
 //------------------------------------------------------------------------------------CreateNetwork
 property void clModel::createNetwork(void) {
  typedef clStreetGraph::cpArcX::const_iterator  clArcIterator;
  typedef clStreetGraph::cpNodeX::const_iterator clNodeIterator;

  clStreetGraph::cpArc *  lcArc;
  clPath *                lcArcComponent;
  clArcIterator           lcCurrentArc;
  clNodeIterator          lcCurrentNode;
  clArcIterator           lcLastArc;
  clNodeIterator          lcLastNode;
  clString                lcName;
  clStreetGraph::cpNode * lcNode;
  clSpot *                lcNodeComponent;
  clStillObject *         lcSource;
  clStillObject *         lcTarget;

  tyReal lcOffsetX = 0.0;
  tyReal lcOffsetY = 0.0;
  tyReal lcZoom    = 1.0;

  // Node Components Creation //
  if (parameterExists("nodes_offset_x")) lcOffsetX=real(parameter("nodes_offset_x"));
  if (parameterExists("nodes_offset_y")) lcOffsetY=real(parameter("nodes_offset_y"));
  if (parameterExists("nodes_zoom")) lcZoom=real(parameter("nodes_zoom"));

  if (parameterExists("node_image"))
   atImageFileS[class_no(simulation::clObject,clSpot)]=dataLocation()+fileNameSeparator()
                                                       +parameter("node_image");

  if (informationDisplayed()) environment::out("Creating Nodes...",true,true);
  lcCurrentNode=atGraph.nodes().begin();
  lcLastNode=atGraph.nodes().end();

  while (lcCurrentNode!=lcLastNode) {
   lcNode=(*lcCurrentNode).second;
   lcName=clString("Node ")+string(lcNode->key());

   newObject(&lcNodeComponent,lcName.data(),lcOffsetX+lcNode->data().x()*lcZoom,
             lcOffsetY+lcNode->data().y()*lcZoom,lcNode->data().x(),lcNode->data().y());

   atNodeX.insert(std_make_pair(lcNode->key(),lcNodeComponent));

   addChild(lcNodeComponent);
   ++lcCurrentNode;
  }

  // Arc Components Creation //
  if (informationDisplayed()) environment::out("Creating Arcs...",true,true);
  lcCurrentArc=atGraph.arcs().begin();
  lcLastArc=atGraph.arcs().end();

  while (lcCurrentArc!=lcLastArc) {
   lcArc=(*lcCurrentArc).second;
   lcSource=atNodeX[lcArc->sourceNode()->key()];
   lcTarget=atNodeX[lcArc->targetNode()->key()];

   lcName=clString("Arc ")+string(lcArc->key())+" ("+string(lcArc->sourceNode()->key())+" -> "
          +string(lcArc->targetNode()->key())+")";

   newObject(&lcArcComponent,lcSource,lcTarget,lcName.data());
   atArcX.insert(std_make_pair(lcArc->key(),lcArcComponent));

   if (graphic()) {
    jaArrowComponent lcArrow = jaArrowComponent::j_new(jyInteger(lcSource->relativeX()),
                                                       jyInteger(lcSource->relativeY()),
                                                       jyInteger(lcTarget->relativeX()),
                                                       jyInteger(lcTarget->relativeY()));

    lcArcComponent->view()=jaVisualComponent::j_new(atFrame);
    lcArcComponent->view().j_setOutside(lcArrow);
    lcArcComponent->view().j_setCentered(java_false);
    lcArcComponent->view().j_setLayer(1);
   }

   addChild(lcArcComponent);
   ++lcCurrentArc;
  }
 }
 //--------------------------------------------------------------------------------CreateCommodities
 property void clModel::createCommodities(void) {
  clString        lcFileName;
  clStillObject * lcSource;
  clStillObject * lcTarget;

  tyCardinal lcCounter = 0;

  if (parameterExists("demand_image"))
   lcFileName=dataLocation()+fileNameSeparator()+parameter("demand_image");

  while (lcCounter<atCommodityS.size()) {
   lcSource=atNodeX[atCommodityS[lcCounter].source()];
   lcTarget=atNodeX[atCommodityS[lcCounter].target()];
   ++lcCounter;

   if (graphic() and lcFileName!="") {
    jaString         lcFile          = jaString::j_new(lcFileName.data());
    jaImageComponent lcSourceImage   = jaImageComponent::j_new(lcFile);
    jaImageComponent lcTargetImage   = jaImageComponent::j_new(lcFile);
    clString         lcSourceMessage = clString("source of commodity ")+string(lcCounter);
    clString         lcTargetMessage = clString("target of commodity ")+string(lcCounter);

    removeChild(lcSource);
    lcSource->view().j_setOutside(lcSourceImage);
    lcSource->view().j_addProperty(jaString::j_new(lcSourceMessage.data()));
    addChild(lcSource);

    removeChild(lcTarget);
    lcTarget->view().j_setOutside(lcTargetImage);
    lcTarget->view().j_addProperty(jaString::j_new(lcTargetMessage.data()));
    addChild(lcTarget);
   }
  }
 }
 //-----------------------------------------------------------------------------------EndReplication
 property void clModel::endReplication(void) {
  typedef std_map(tyCardinal,clSpot *)::iterator           clNodeIterator;
  typedef std_map(tyCardinal,clCustomerTravel *)::iterator clTravelIterator;

  tyReal             lcTime;
  clCustomerTravel * lcTravel;

  clNodeIterator   lcCurrentNode   = atNodeX.begin();
  clTravelIterator lcCurrentTravel = atCurrentTravelX.begin();
  clNodeIterator   lcLastNode      = atNodeX.end();
  clTravelIterator lcLastTravel    = atCurrentTravelX.end();

  if (graphic()) atFrame.j_setStatus(jaString::j_new("Terminating Replication..."));

  // Travel Times Collection & Travel Objects Destruction //
  while (lcCurrentTravel!=lcLastTravel) {
   lcTravel=(*lcCurrentTravel).second;
   lcTime=lcTravel->effectiveTime().mean();
   lcTravel->effectiveTime().reset();

   if (atReplication==1) {
    lcTravel->effectiveTime().add(lcTime);
    atFinalTravelX.insert(std_make_pair(lcTravel->number(),lcTravel));
   }
   else {
    atFinalTravelX[lcTravel->number()]->effectiveTime().add(lcTime);
    delete_object(lcTravel);
   }

   ++lcCurrentTravel;
  }

  // Waiting Times Collection //
  while (lcCurrentNode!=lcLastNode) {
   atWaitingTimeX[(*lcCurrentNode).first].add((*lcCurrentNode).second->waitingTime().mean());
   ++lcCurrentNode;
  }

  // Data Structures Cleaning //
  atCurrentTravelX.erase(atCurrentTravelX.begin(),atCurrentTravelX.end());
  atBusX.erase(atBusX.begin(),atBusX.end());
  atCommodityS.erase(atCommodityS.begin(),atCommodityS.end());
  atArcX.erase(atArcX.begin(),atArcX.end());
  atNodeX.erase(atNodeX.begin(),atNodeX.end());
  atGraph.clear();

  clSimulator::endReplication();
 }
 //------------------------------------------------------------------------------------EndExperiment
 property void clModel::endExperiment(void) {
  typedef std_map(tyCardinal,clCustomerTravel *)::iterator clTravelIterator;

  clOutFile lcFile;
  clString  lcFileName;

  clTravelIterator lcCurrentTravel = atFinalTravelX.begin();
  clTravelIterator lcLastTravel    = atFinalTravelX.end();

  if (graphic()) atFrame.j_setStatus(jaString::j_new("Terminating Experiment..."));

  // Travel Times Saving //
  if (parameterExists("travel_file")) {
   lcFileName=dataLocation()+fileNameSeparator()+parameter("travel_file");
   open(lcFile,lcFileName.data(),ios::out);
   lcFile << atFinalTravelX;
   close(lcFile);
  }

  // Travel Objects Destruction //
  while (lcCurrentTravel!=lcLastTravel) {
   delete_object((*lcCurrentTravel).second);
   ++lcCurrentTravel;
  }

  atFinalTravelX.erase(atFinalTravelX.begin(),atFinalTravelX.end());

  // Waiting Times Saving //
  if (parameterExists("waiting_file")) {
   lcFileName=dataLocation()+fileNameSeparator()+parameter("waiting_file");
   open(lcFile,lcFileName.data(),ios::out);
   lcFile << atWaitingTimeX;
   close(lcFile);
  }

  atWaitingTimeX.erase(atWaitingTimeX.begin(),atWaitingTimeX.end());

  clSimulator::endExperiment();
 }
 //--------------------------------------------------------------------------CreateCustomerFactories
 property void clModel::createCustomerFactories(clInStream & agStream) {
  method_name("model::createCustomerFactories");

  std_multimap(tyCardinal,clBus *)::iterator lcBus;
  clCommodityData                            lcCommodity;
  clSpot *                                   lcEntry;
  clSpot *                                   lcExit;
  clCustomerFactory *                        lcFactory;
  clPhysicalObject *                         lcSource;
  clString                                   lcString;
  clCustomerTravel *                         lcTravel;

  tyReal lcCustomerInterarrival = 100.0;
  tyReal lcCustomerSpeed        = 1.0;

  if (parameterExists("customer_speed")) lcCustomerSpeed=real(parameter("customer_speed"));

  if (parameterExists("customer_interarrival"))
   lcCustomerInterarrival=real(parameter("customer_interarrival"));

  if (parameterExists("customer_image"))
   atImageFileS[class_no(simulation::clObject,clCustomer)]=dataLocation()+fileNameSeparator()
                                                           +parameter("customer_image");

  agStream >> lcString;
  if (lcString!=private_area::goCustomersStartFlag) send_error(erStreamReading);
  agStream >> lcString;

  while (lcString==private_area::goCustomerFlag) {
   lcSource=nil;
   agStream >> lcString;
   lcTravel=new_object(clCustomerTravel());
   lcTravel->number()=cardinal(lcString.data());
   atCurrentTravelX.insert(std_make_pair(lcTravel->number(),lcTravel));
   lcCommodity=atCommodityS[lcTravel->number()-1];
   agStream >> lcString >> lcString;

   while (lcString==private_area::goFeetMeansFlag or lcString==private_area::goBusMeansFlag) {
    if (lcString==private_area::goFeetMeansFlag) {
     agStream >> lcString;

     while (lcString!=";") {
      agStream >> lcString;
      lcTravel->moves().push_back(clCustomerMove());
      lcTravel->moves().back().means()=clCustomerMove::feet;
      lcTravel->moves().back().pathNo()=cardinal(lcString.data());
      lcTravel->moves().back().path()=atArcX[cardinal(lcString.data())];
      if (lcSource==nil) lcSource=lcTravel->moves().back().path()->source();
      agStream >> lcString;
     }
    }
    else {
     agStream >> lcString;
     lcTravel->moves().push_back(clCustomerMove());
     lcTravel->moves().back().means()=clCustomerMove::bus;
     lcTravel->moves().back().lineNo()=cardinal(lcString.data());
     agStream >> lcString >> lcString;
     lcTravel->moves().back().entryNo()=cardinal(lcString.data());
     lcEntry=atNodeX[cardinal(lcString.data())];
     lcTravel->moves().back().entry()=lcEntry;
     agStream >> lcString >> lcString;
     lcTravel->moves().back().exitNo()=cardinal(lcString.data());
     lcExit=atNodeX[cardinal(lcString.data())];
     lcTravel->moves().back().exit()=lcExit;
     lcBus=atBusX.find(lcTravel->moves().back().lineNo());
     if (lcBus==atBusX.end()) send_error(erInvalidBusLineNumber);
     lcTravel->moves().back().travelTime()=(*lcBus).second->bestTravelTime(lcEntry,lcExit);
     if (lcTravel->moves().back().travelTime()==realMax()) send_error(erWrongBusLine);
     if (lcSource==nil) lcSource=lcTravel->moves().back().entry();
     agStream >> lcString;
    }

    agStream >> lcString;
   }

   lcTravel->minimumTime()=cardinal(lcString.data());
   agStream >> lcString >> lcTravel->maximumTime();
   agStream >> lcString >> lcString >> lcString;
   lcTravel->source()=lcSource;

   newObject(&lcFactory,lcTravel,lcCustomerSpeed,lcCustomerInterarrival/lcCommodity.quantity(),
             "Customer Factory");
  }

  if (agStream.fail()) send_error(erStreamReading);
 }
 //-----------------------------------------------------------------------------------CreateBusLines
 property void clModel::createBusLines(clInStream & agStream) {
  method_name("model::createBusLines");

  clPath *           lcArc;
  clBus *            lcBus;
  clString           lcName;
  clPhysicalObject * lcSource;
  clString           lcString;

  tyCardinal lcCounter  = 0;
  tyReal     lcBusSpeed = 0.33;
  tyCardinal lcBusSize  = cardinalMax();

  if (parameterExists("bus_speed")) lcBusSpeed=real(parameter("bus_speed"));

  if (parameterExists("bus_image"))
   atImageFileS[class_no(simulation::clObject,clBus)]=dataLocation()+fileNameSeparator()
                                                      +parameter("bus_image");

  if (parameterExists("bus_size")) lcBusSize=cardinal(parameter("bus_size"));

  agStream >> lcString;
  if (lcString!=private_area::goBusLinesStartFlag) send_error(erStreamReading);
  agStream >> lcString;

  while (lcString==private_area::goBusLineFlag) {
   agStream >> lcString;
   lcName=clString("Bus ")+string(++lcCounter);
   newObject(&lcBus,lcBusSpeed,cardinal(lcString.data()),lcBusSize,lcName.data());
   atBusX.insert(std_make_pair(lcBus->lineNo(),lcBus));
   agStream >> lcString;
   lcSource=nil;

   while (lcString!=";") {
    agStream >> lcString;
    lcArc=atArcX[cardinal(lcString.data())];
    if (lcSource==nil) lcSource=lcArc->source();
    lcBus->travel().push_back(lcArc);

    if (graphic() and lcArc->view()!=java_nil) {
     jaArrowComponent(lcArc->view().j_outside()).j_setColor(jaColor::j_blue());
     lcArc->view().j_setLayer(2);
    }

    agStream >> lcString;
   }

   agStream >> lcString;
  }

  if (agStream.fail()) send_error(erStreamReading);
 }
 //------------------------------------------------------------------------------------CleanBusLines
 property void clModel::cleanBusLines(void) {
  typedef std_multimap(tyCardinal,clBus *)::iterator       clBusIterator;
  typedef std_vector(clCustomerMove)::iterator             clMoveIterator;
  typedef std_map(tyCardinal,clCustomerTravel *)::iterator clTravelIterator;

  clBus *                             lcBus;
  tyCardinal                          lcCounter;
  clMoveIterator                      lcCurrentMove;
  clTravelIterator                    lcCurrentTravel;
  tyCardinal                          lcEndPosition;
  tyBoolean                           lcFound;
  clMoveIterator                      lcLastMove;
  clTravelIterator                    lcLastTravel;
  tyCardinal                          lcPosition;
  tyCardinal                          lcSource;
  tyCardinal                          lcStartPosition;
  tyCardinal                          lcTarget;
  clCustomerTravel *                  lcTravel;
  std_vector(tyCardinal)              lcVisitedS;
  std_map(clStillObject *,tyCardinal) lcVisitedX;

  clBusIterator lcCurrentBus = atBusX.begin();
  clBusIterator lcLastBus    = atBusX.end();
  clPath *      lcPath       = nil;

  // Buses Analysis //
  while (lcCurrentBus!=lcLastBus) {
   lcBus=(*lcCurrentBus).second;
   lcVisitedS.erase(lcVisitedS.begin(),lcVisitedS.end());
   lcVisitedS.resize(lcBus->travel().size(),false);
   lcCurrentTravel=atCurrentTravelX.begin();
   lcLastTravel=atCurrentTravelX.end();

   // Customer Travels Analysis //
   while (lcCurrentTravel!=lcLastTravel) {
    lcTravel=(*lcCurrentTravel).second;
    lcCurrentMove=lcTravel->moves().begin();
    lcLastMove=lcTravel->moves().end();

    while (lcCurrentMove!=lcLastMove) {
     clCustomerMove & lcMove = *lcCurrentMove;

     // Each Move Using The Bus Is Marked //
     if (lcMove.means()==clCustomerMove::bus and lcMove.lineNo()==lcBus->lineNo()) {
      lcPosition=lcBus->bestPosition(lcMove.entry(),lcMove.exit());
      lcCounter=lcPosition;

      do {
       lcPath=lcBus->travel()[lcCounter];
       lcVisitedS[lcCounter]=true;
       lcCounter=(lcCounter+1)%lcBus->travel().size();
      }
      while (lcCounter!=lcPosition and lcPath->target()!=lcMove.exit());
     }

     ++lcCurrentMove;
    }

    ++lcCurrentTravel;
   }

   // Unused Loops Detection //
   lcCounter=0;

   while (lcCounter<lcBus->travel().size()) {
    lcFound=false;

    // Loop Search //
    if (not lcVisitedS[lcCounter]) {
     lcVisitedX.erase(lcVisitedX.begin(),lcVisitedX.end());
     lcPosition=lcCounter;

     while (not lcVisitedS[lcPosition] and not lcFound) {
      lcPath=lcBus->travel()[lcPosition];
      lcVisitedX[lcPath->source()]=lcPosition;

      if (lcVisitedX.find(lcPath->target())!=lcVisitedX.end()) lcFound=true;
      else {
       lcPosition=(lcPosition+1)%lcBus->travel().size();
       lcCounter=maxi(lcPosition,lcCounter);
      }
     }
    }

    // Loop Removal //
    if (lcFound) {
     lcStartPosition=lcVisitedX[lcPath->target()];
     lcEndPosition=lcPosition;

     environment::out(clString("Unused Loop In ")+lcBus->name()+": ",false,true);
     environment::out(lcBus->travel()[lcStartPosition]->name()+" -> ");
     environment::out(lcBus->travel()[lcEndPosition]->name(),true);

     if (lcStartPosition>lcEndPosition) lcVisitedS.resize(lcStartPosition);
     lcTarget=(lcStartPosition<=lcEndPosition ? lcStartPosition : 0);
     lcSource=lcEndPosition+1;

     while (lcSource<lcVisitedS.size()) {
      lcVisitedS[lcTarget]=lcVisitedS[lcSource];
      lcBus->travel()[lcTarget]=lcBus->travel()[lcSource];
      ++lcTarget;
      ++lcSource;
     }

     if (lcStartPosition<=lcEndPosition)
      lcVisitedS.resize(lcVisitedS.size()-(lcEndPosition+1-lcStartPosition));
     else lcVisitedS.resize(lcVisitedS.size()-(lcEndPosition+1));

     lcBus->travel().resize(lcVisitedS.size());
     lcCounter=0;
    }
    else ++lcCounter;
   }

   if (lcBus->travel().size()>0) lcBus->arrive(lcBus->travel()[0]->source());
   ++lcCurrentBus;
  }
 }
}

// 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);

    erInvalidBusLineNumber.create("Urban Bus - The bus line number is invalid.");
    erWrongBusLine.create("Urban Bus - The customer is affected to a wrong bus line.");

    goBusLineFlag           = "line";
    goBusLinesEndFlag       = "<lines_end>";
    goBusLinesStartFlag     = "<lines_start>";
    goBusMeansFlag          = "b";
    goCommoditiesEndFlag    = "<demands_end>";
    goCommoditiesStartFlag  = "<demands_start>";
    goCommodityFlag         = "demand";
    goCustomerFlag          = "customer";
    goCustomersEndFlag      = "<customers_end>";
    goCustomersStartFlag    = "<customers_start>";
    goFeetMeansFlag         = "f";
    goWaitingTimeFlag       = "time";
    goWaitingTimesEndFlag   = "<waiting_times_end>";
    goWaitingTimesStartFlag = "<waiting_times_start>";
   }

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

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