
/*!
\file
\brief Distributed Traffic light Control Scenario 
\author Vasek Smidl 

 */

#include "base/user_info.h"
#include "base/loggers.h"
#ifdef _WIN32
#include "aimsun_bdm/aimsun_ds.h"
#else 
#include "aimsun_bdm/aimsun_fake.h"
#endif
#include "traffic_agent.h"
#include "traffic_agent_offset.h"

using namespace bdm;

int main ( int argc, char* argv[] ) {
	const char *fname;
	int max_cycles=5; //max. number of sending/recieving during negotiation, changed to number from config file, if present (negotiation_cycles)

	if ( argc>1 ) {fname = argv[1];	}
	else { cout << "Missing configuration file.\n Usage: \n $> estimator config_file.cfg"<<endl; abort(); }
	UIFile Cfg ( fname );

	// SYSTEM TO CONTROL
	shared_ptr<AimsunDS> Ds=UI::build<AimsunDS>(Cfg.lookup("system"),UI::compulsory);

	// AGENTS
	Array<shared_ptr<Participant> > Ags;
	UI::get ( Ags,Cfg, "agents" );

	// LOGGER
	shared_ptr<logger> L = UI::build <logger>( Cfg, "logger" );
	if (!L) {
		L=new stdlog(); // DEFAULT LOGGER <== poor choice, use better ones
	} 



	Config MsgStore;
	MsgStore.setAutoConvert(true);
	Setting& Queue = MsgStore.getRoot().add("queue", Setting::TypeList);

	// REGISTER ACTIVE OBJECTS IN LOGGER
	Ds->log_register ( *L, "DS" );
	for ( int i=0; i<Ags.length(); i++ ) {
		Ags ( i )->log_register ( *L,Ags(i)->_name() ); // estimate
		Ags ( i )->ds_register(*Ds);            // allows agents to update their datalinks
	}
	L->init();

	vec glob_dt(Ds->_drv()._dsize() );
	vec glob_ut(Ds->_urv()._dsize() );

	// INITIALISATION OF UT
	glob_ut[ 0] = 80; // cycle time
	glob_ut[ 1] = 60; // offset 495
	glob_ut[ 2] = 30; // ut[2]+ut[3]+ut[4] has to sum up to ut[0]
	glob_ut[ 3] = 30;
	glob_ut[ 4] = 20;
    glob_ut[ 8] = 40; // offset 601
	glob_ut[ 9] = 30; // ut[9]+ut[10]+ut[11] has to sum up to ut[0]
	glob_ut[10] = 30;
	glob_ut[11] = 20;

	//LENGTH OF NEGOTIATION
	UI::get(max_cycles,Cfg,"negotiation_cycles");

	for ( int tK=0; tK < Ds->max_length(); tK++ ) {

		Ds->log_write ( ); // write stuff to 
		Ds->getdata(glob_dt);
		for ( int i=0; i<Ags.length(); i++ ) {
			Ags(i) -> adapt(glob_dt);
		}

		// NEGOTIATION CYCLE
		// ends when Queue is empty or after defined number of cycles
		int cycle=0;
		do {
			//DBG
			MsgStore.writeFile("msg");
			// parse message queue
			for ( int m=Queue.getLength()-1; m>=0; m-- ) { // go backwards - last mesages are discarded
				for ( int i=0; i<Ags.length(); i++ ) {
					Setting& msg=Queue[m];
					string m_to=msg["to"];
					if (m_to==Ags(i)->_name()) {
						Ags(i)->receive(msg);
						Queue.remove(m);
						break;
						// message delivered;
					}
				}
			}
			if (Queue.getLength()>0){bdm_error("undelivered messages - probably unknown neighbours");}

			for ( int i=0; i<Ags.length(); i++ ) {
				Ags(i) -> broadcast(Queue);
			}

			cycle++;
		} while ((Queue.getLength()>0) && (cycle<max_cycles));

		if (cycle==max_cycles) {
			bdm_warning("Reached maximum number of cycles");
		}

		for ( int i=0; i<Ags.length(); i++ ) {
			Ags(i) -> act(glob_ut);
		}

		L->step();
		Ds->write(glob_ut);
		Ds->step();							// simulator step

		for ( int i=0; i<Ags.length(); i++ ) {
			Ags(i) -> log_write();
			Ags(i) -> step();
		}
		
	}

	L->finalize();

	return 0;
}

