#include "ObjectFactory.h"

#include <config/OBSWConfig.h>
#include <config/objects/systemObjectList.h>
#include <config/tmtc/apid.h>
#include <config/tmtc/pusIds.h>

#include <mission/utility/TmFunnel.h>

#include <fsfw/health/HealthTable.h>
#include <fsfw/storagemanager/PoolManager.h>
#include <fsfw/events/EventManager.h>
#include <fsfw/timemanager/TimeStamper.h>
#include <fsfw/internalError/InternalErrorReporter.h>
#include <fsfw/monitoring/MonitoringMessageContent.h>
#include <fsfw/tcdistribution/CCSDSDistributor.h>
#include <fsfw/tcdistribution/PUSDistributor.h>
#include <fsfw/pus/Service1TelecommandVerification.h>
#include <fsfw/pus/Service2DeviceAccess.h>
#include <fsfw/pus/Service5EventReporting.h>
#include <fsfw/pus/Service8FunctionManagement.h>
#include <fsfw/pus/Service9TimeManagement.h>
#include <fsfw/pus/Service17Test.h>
#include <fsfw/pus/CService200ModeCommanding.h>
#include "../../fsfw/devicehandlers/CookieIF.h"
#include "../../hosted/comIF/ArduinoComIF.h"
#ifdef LINUX
#include <fsfw/osal/linux/TcUnixUdpPollingTask.h>
#include <fsfw/osal/linux/TmTcUnixUdpBridge.h>
#elif WIN32
#include <fsfw/osal/windows/TcWinUdpPollingTask.h>
#include <fsfw/osal/windows/TmTcWinUdpBridge.h>
#endif
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>


#if ADD_TEST_CODE == 1
//#include <test/TestCookie.h>
//#include <test/TestDeviceHandler.h>
#include <test/testtasks/TestTask.h>
//#include <test/TestEchoComIF.h>
#endif

void Factory::setStaticFrameworkObjectIds(){
	PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR;
	PusServiceBase::packetDestination = objects::TM_FUNNEL;

	CommandingServiceBase::defaultPacketSource = objects::PUS_PACKET_DISTRIBUTOR;
	CommandingServiceBase::defaultPacketDestination = objects::TM_FUNNEL;

	TmFunnel::downlinkDestination = objects::UDP_BRIDGE;
	// No storage object for now.
	TmFunnel::storageDestination = objects::NO_OBJECT;

	VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION;
	TmPacketStored::timeStamperId = objects::TIME_STAMPER;
}



void ObjectFactory::produce(){
	Factory::setStaticFrameworkObjectIds();

	/* Framework objects */
	new EventManager(objects::EVENT_MANAGER);
	new HealthTable(objects::HEALTH_TABLE);
	new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 0, 0, 0);
	new TimeStamper(objects::TIME_STAMPER);

	{
		static constexpr uint8_t NUMBER_OF_POOLS = 5;
		const uint16_t element_sizes[NUMBER_OF_POOLS] = {16, 32, 64, 128, 1024};
		const uint16_t n_elements[NUMBER_OF_POOLS] = {100, 50, 25, 15, 5};
		new PoolManager<NUMBER_OF_POOLS>(objects::TC_STORE, element_sizes,
				n_elements);
	}

	{
		static constexpr uint8_t NUMBER_OF_POOLS = 5;
		const uint16_t element_sizes[NUMBER_OF_POOLS] = {16, 32, 64, 128, 1024};
		const uint16_t n_elements[NUMBER_OF_POOLS] = {100, 50, 25, 15, 5};
		new PoolManager<NUMBER_OF_POOLS>(objects::TM_STORE, element_sizes,
				n_elements);
	}

	{
		static constexpr uint8_t NUMBER_OF_POOLS = 6;
		const uint16_t element_sizes[NUMBER_OF_POOLS] = {32, 64, 512,
				1024, 2048, 4096};
		const uint16_t n_elements[NUMBER_OF_POOLS] = {200, 100, 50, 25, 15, 5};
		new PoolManager<NUMBER_OF_POOLS>(objects::IPC_STORE, element_sizes,
				n_elements);
	}

	new CCSDSDistributor(apid::EIVE_OBSW, objects::CCSDS_PACKET_DISTRIBUTOR);
	new PUSDistributor(apid::EIVE_OBSW, objects::PUS_PACKET_DISTRIBUTOR,
			objects::CCSDS_PACKET_DISTRIBUTOR);


	/* TMTC Reception via UDP socket */
	new TmFunnel(objects::TM_FUNNEL);
#ifdef LINUX
	new TmTcUnixUdpBridge(objects::UDP_BRIDGE,
			objects::CCSDS_PACKET_DISTRIBUTOR,
			objects::TM_STORE, objects::TC_STORE);
	new TcUnixUdpPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE);
#elif WIN32
    new TmTcWinUdpBridge(objects::UDP_BRIDGE,
            objects::CCSDS_PACKET_DISTRIBUTOR, objects::TM_STORE,
            objects::TC_STORE);
    new TcWinUdpPollingTask(objects::UDP_POLLING_TASK,
            objects::UDP_BRIDGE);
#endif


	/* PUS stack */
	new Service1TelecommandVerification(objects::PUS_SERVICE_1_VERIFICATION,
			apid::EIVE_OBSW, pus::PUS_SERVICE_1, objects::TM_FUNNEL);
	new Service2DeviceAccess(objects::PUS_SERVICE_2_DEVICE_ACCESS,
			apid::EIVE_OBSW, pus::PUS_SERVICE_2, 3, 10);
	new Service5EventReporting(objects::PUS_SERVICE_5_EVENT_REPORTING,
			apid::EIVE_OBSW, pus::PUS_SERVICE_5, 50);
	new Service8FunctionManagement(objects::PUS_SERVICE_8_FUNCTION_MGMT,
			apid::EIVE_OBSW, pus::PUS_SERVICE_8, 3, 10);
	new Service9TimeManagement(objects::PUS_SERVICE_9_TIME_MGMT,
			apid::EIVE_OBSW, pus::PUS_SERVICE_9);
	new Service17Test(objects::PUS_SERVICE_17_TEST, apid::EIVE_OBSW,
			pus::PUS_SERVICE_17);
	new CService200ModeCommanding(objects::PUS_SERVICE_200_MODE_MGMT,
			apid::EIVE_OBSW, pus::PUS_SERVICE_200);

	/* Test Device Handler */
#if ADD_TEST_CODE == 1
	new TestTask(objects::TEST_TASK);
//	CookieIF* testCookie = new TestCookie(0);
//	new TestEchoComIF(objects::TEST_ECHO_COM_IF);
//	new TestDevice(objects::TEST_DEVICE_HANDLER, objects::TEST_ECHO_COM_IF,
//			testCookie, true);
	new ArduinoComIF(objects::ARDUINO_COM_IF, true, nullptr);
#endif
}