/*
 * AvroUtils.h
 *
 *  Created on: May 2, 2022
 *      Author: astrisw
 */

#ifndef INCLUDE_AVROUTILS_H_
#define INCLUDE_AVROUTILS_H_

#include <Encoder.hh>
#include <Packet.h>
#include <AvroPackets/S22Packet.h>
#include <AvroPackets/VAR102Packet.h>
#include <AvroPackets/VAR103Packet.h>
#include <Constants.h>

namespace AvroUtilis {
static void encodeToAvro(PacketLib::Packet & p,  avro::EncoderPtr & avroencoder , std::string packetID){

	// C11
	if(packetID.compare(ProcessorConstants::C11_ID)==0){
		// process
		return;
	}

	// C14
	if(packetID.compare(ProcessorConstants::C14_ID)==0){
		// process
		return;
	}
	// S22
	if(packetID.compare(ProcessorConstants::S22_ID)==0){
		// AVRO PACKET INIT
		S22::S22 s22;
		// PACKET HEADER
		s22.telescopeID  = (uint8_t) p.getPacketHeader()->getFieldValue(1);
		s22.type =  (uint8_t) p.getPacketHeader()->getFieldValue(2);
		s22.subType = (uint8_t) p.getPacketHeader()->getFieldValue(3);
		s22.ssc = p.getPacketHeader()->getFieldValue(4);


		// PACKET DATA FIELD HEADER
		s22.year = p.getPacketDataFieldHeader()->getFieldValue(0);

		s22.month = p.getPacketDataFieldHeader()->getFieldValue(1);
		s22.day = p.getPacketDataFieldHeader()->getFieldValue(2);
		// hour is composed by a 1 MSB and 4 LSB
		s22.hours = (p.getPacketDataFieldHeader()->getFieldValue(3) << 4) +
				p.getPacketDataFieldHeader()->getFieldValue(4);
		s22.minutes = p.getPacketDataFieldHeader()->getFieldValue(5);
		s22.seconds = p.getPacketDataFieldHeader()->getFieldValue(6);
		s22.validTime = p.getPacketDataFieldHeader()->getFieldValue(7);
		// nanosecond is composed by 15 bit MSB and 16 bit LSB
		s22.timeTagNanosec = (p.getPacketDataFieldHeader()->getFieldValue(8) << 16)+
				p.getPacketDataFieldHeader()->getFieldValue(9); // nanoseconds msb

		// PACKET DATA FIELD HEADER EXTENSION
		s22.pixelTriggerDiscriminatorThreshold_pe = p.getPacketDataFieldHeader()->getFieldValue(19);
		s22.pixelTriggerLowelDiscriminatorThreshold_pe = p.getPacketDataFieldHeader()->getFieldValue(20);
		if(p.getPacketDataFieldHeader()->getFieldValue(22) == 0)
			s22.triggerType = S22::TOPOLOGICO;
		else
			s22.triggerType = S22::MAJORITY;
		s22.triggerConfig = p.getPacketDataFieldHeader()->getFieldValue(23);

		// PACKET SOURCE DATA FIELD
		int nblocks = 37;                //Numero reale di event data blocks
		PacketLib::SourceDataField* packet_sdf = (PacketLib::SourceDataField*) p.getPacketSourceDataField();
		for (int pdmid = 0; pdmid < nblocks ; pdmid++){
			S22::PDMBlock pdmBlock;
			pdmBlock.pdmVal = packet_sdf->getBlock(pdmid, 0)->getFieldValue(0);
			pdmBlock.triggerEnabled = packet_sdf->getBlock(pdmid, 0)->getFieldValue(1);
			pdmBlock.triggered = packet_sdf->getBlock(pdmid, 0)->getFieldValue(2);
			pdmBlock.pdmID = packet_sdf->getBlock(pdmid, 0)->getFieldValue(4);
			// set high gain
			pdmBlock.highgains.resize(64);
			pdmBlock.lowgains.resize(64);
			int offset = 5;
			for (int j = offset; j< 69; j++){
				pdmBlock.highgains.at(j-offset) = (packet_sdf->getBlock(pdmid, 0)->getFieldValue( j ));
				pdmBlock.lowgains.at(j-offset) = (packet_sdf->getBlock(pdmid, 0)->getFieldValue( j + 64 ));
			}

			s22.PDMs.push_back(pdmBlock);
		}

		//	//AVRO ENCODING
		avro::encode(*avroencoder, s22);
		return;
	}

	// HK101
	if(packetID.compare(ProcessorConstants::HK101_ID)==0){
		// process
		return;
	}
	// VAR102
	if(packetID.compare(ProcessorConstants::VAR102_ID)==0){
		// AVRO PACKET INIT
		VAR102::VAR102 var102;
		// PACKET HEADER
		var102.telescopeID  = (uint8_t) p.getPacketHeader()->getFieldValue(1);
		var102.type =  (uint8_t) p.getPacketHeader()->getFieldValue(2);
		var102.subType = (uint8_t) p.getPacketHeader()->getFieldValue(3);
		var102.ssc = p.getPacketHeader()->getFieldValue(4);

		// PACKET DATA FIELD HEADER
		var102.year = p.getPacketDataFieldHeader()->getFieldValue(0);
		var102.month = p.getPacketDataFieldHeader()->getFieldValue(1);
		var102.day = p.getPacketDataFieldHeader()->getFieldValue(2);
		// hour is composed by a 1 MSB and 4 LSB
		var102.hours = (p.getPacketDataFieldHeader()->getFieldValue(3) << 4) +
				p.getPacketDataFieldHeader()->getFieldValue(4);
		var102.minutes = p.getPacketDataFieldHeader()->getFieldValue(5);
		var102.seconds = p.getPacketDataFieldHeader()->getFieldValue(6);
		var102.validTime = p.getPacketDataFieldHeader()->getFieldValue(7);
		// nanosecond is composed by 15 bit MSB and 16 bit LSB
		var102.timeTagNanosec = (p.getPacketDataFieldHeader()->getFieldValue(8) << 16)+
				p.getPacketDataFieldHeader()->getFieldValue(9); // nanoseconds msb

		// PACKET SOURCE DATA FIELD
		int nblocks = 37;                //Numero reale di event data blocks
		PacketLib::SourceDataField* packet_sdf = (PacketLib::SourceDataField*) p.getPacketSourceDataField();
		for (int pdmid = 0; pdmid < nblocks ; pdmid++){
			VAR102::PDMBlock pdmBlock;
			pdmBlock.pdmVal = packet_sdf->getBlock(pdmid, 0)->getFieldValue(0);
			pdmBlock.samplingPar = packet_sdf->getBlock(pdmid, 0)->getFieldValue(1);
			pdmBlock.pdmID = packet_sdf->getBlock(pdmid, 0)->getFieldValue(2);
			// set variances
			for (int j = 3; j< 67; j++){
				pdmBlock.variance.push_back(packet_sdf->getBlock(pdmid, 0)->getFieldValue( j ));
			}

			var102.PDMs.push_back(pdmBlock);
		}

		//	//AVRO ENCODING
		avro::encode(*avroencoder, var102);
		return;
	}
	// VAR103
	if(packetID.compare(ProcessorConstants::VAR103_ID)==0){
		// AVRO PACKET INIT
		VAR103::VAR103 var103;
		// PACKET HEADER
		var103.telescopeID  = (uint8_t) p.getPacketHeader()->getFieldValue(1);
		var103.type =  (uint8_t) p.getPacketHeader()->getFieldValue(2);
		var103.subType = (uint8_t) p.getPacketHeader()->getFieldValue(3);
		var103.ssc = p.getPacketHeader()->getFieldValue(4);

		// PACKET DATA FIELD HEADER
		var103.year = p.getPacketDataFieldHeader()->getFieldValue(0);
		var103.month = p.getPacketDataFieldHeader()->getFieldValue(1);
		var103.day = p.getPacketDataFieldHeader()->getFieldValue(2);
		// hour is composed by a 1 MSB and 4 LSB
		var103.hours = (p.getPacketDataFieldHeader()->getFieldValue(3) << 4) +
				p.getPacketDataFieldHeader()->getFieldValue(4);
		var103.minutes = p.getPacketDataFieldHeader()->getFieldValue(5);
		var103.seconds = p.getPacketDataFieldHeader()->getFieldValue(6);
		var103.validTime = p.getPacketDataFieldHeader()->getFieldValue(7);
		// nanosecond is composed by 15 bit MSB and 16 bit LSB
		var103.timeTagNanosec = (p.getPacketDataFieldHeader()->getFieldValue(8) << 16)+
				p.getPacketDataFieldHeader()->getFieldValue(9); // nanoseconds msb

		// PACKET SOURCE DATA FIELD
		int nblocks = 37;                //Numero reale di event data blocks
		PacketLib::SourceDataField* packet_sdf = (PacketLib::SourceDataField*) p.getPacketSourceDataField();
		for (int pdmid = 0; pdmid < nblocks ; pdmid++){
			VAR103::PDMBlock pdmBlock;
			pdmBlock.pdmVal = packet_sdf->getBlock(pdmid, 0)->getFieldValue(0);
			pdmBlock.samplingPar = packet_sdf->getBlock(pdmid, 0)->getFieldValue(1);
			pdmBlock.pdmID = packet_sdf->getBlock(pdmid, 0)->getFieldValue(2);
			// set variances
			for (int j = 3; j< 67; j++){
				pdmBlock.variance.push_back(packet_sdf->getBlock(pdmid, 0)->getFieldValue( j ));
			}

			var103.PDMs.push_back(pdmBlock);
		}

		//	//AVRO ENCODING
		avro::encode(*avroencoder, var103);
		return;
	}

	std::string err("Unrecognized Packet: ");
	err.append(packetID).append("\n");
	throw err;
}

}



#endif /* INCLUDE_AVROUTILS_H_ */
