
#ifndef SIMULATION_H
#define SIMULATION_H

#include <iostream>
#include "gmnet.h"
#include "task.h"
#include "sockio.h"
#include "EventList.h"
#include "DateTime.h"
#include "MainClass.h"
#include "RandomWrapper.h"
#include <fstream>
#include <ctime>

class DefaultGM;
class Binding;
class NetClass;
class Server;

class Simulation
{
 public:
   static const int SUCCESSFUL=0;
   static const int SECMAX_TIMEOUT=1;
   static const int ENDTIME_TIMEOUT=2;
   
   static const bool TRANSIENT=false;
   static const bool STATIONARY=true;
   
   static const bool DATEFORMAT=false;
   static const bool NUMBERFORMAT=true;
   
   static const bool PER_RULE=true;
   static const int EPS_MAX=5;
   static const int INT_LENGTH=50;
   int no_sampling;      
   int statOutput;
      
   Simulation(NetClass* net, 
	   const std::string& netname, 
	   const std::string& resultaddress, 
	   const DateTime& from, 
	   const DateTime& to, 
	   int no_sampling, 
	   bool sim_mode, 
	   bool dateTime_format,
	   bool percent_rule, 
	   double eps_max, 
	   double interval_length,
	   unsigned int secmax);
   virtual ~Simulation();
   
   void displayOut(DefaultGM* object, double value);
   
   inline const DateTime& getCurrentSimulationTime() const { return current_time; };
   static Simulation *getSimulation() {return sim;}

   /** Fills the event list with all enabled transitions and timeguard events */
   virtual void init();
   void initMeasureList( bool first_running );
   void initTransitions();
   
   inline virtual bool isSingleStep() const { return false; };

   void measureOut(DefaultGM* object, double value);
   void measureOut(DefaultGM* object, MeasureObj *m_object);
   
   void resetCurrentTime();
   virtual Binding* resolve_conflicts(BindingList& events);
   virtual void run_transient( double &alphat_def );
   virtual void run_stationary( double &alphat_def );
   
   /** writes end results of all measures to a file */
   virtual void shutdown();

protected:
   time_t seconds;
   double alphat_def;
   bool sim_mode, dateTime_format, percent_rule, no_endtime, firstValue;
   double eps_max;
   double interval_length;
   fstream simlog; //file for data-output
	
   unsigned int secmax;
   static string printEventList(BindingList& bindings);

   void getFirstBindingsOfAllTransitions(BindingList* bindings, bool disregardTime);
   void executeEvent(Binding* binding);

   void updateSimulationTime(const DateTime &eventTime);
   void updateAllMeasures( Binding *fireBinding, bool accumulate, bool slt_et );
   bool updateSamplingPoints( bool analysis );
   
   inline bool hasMeasureSocket() const { return (measureSocket != NULL); };
   inline socket_t* getMeasureSocket() { return measureSocket; };

   virtual void initMeasureSocket();
   
   NetClass* net;
   std::string netname;
   std::string resultaddress;
   //ecvent_time is the time of the next event
   //current_time is the current simulation time
   //sampling_time is the time of the next sampling point
   DateTime current_time, sampling_time, event_time;
   const DateTime& start_time, end_time;
   std::string lastFiredName;
   bool initialized;
   socket_t* measureSocket;

   RandomWrapper randGen;

   static Simulation *sim;

};

#endif
