//============================================================================
// $Id: PacketSemanticAnalyzer.cpp,v 1.5 2009/07/30 08:16:20 mocchiut Exp $ 
// Description : 
//============================================================================
#include "PacketSemanticAnalyzer.h"

namespace PamOffLineSW
{

extern unsigned long int step_pkt_number;
extern 	unsigned long int step_pkt_obt; 
extern 	unsigned long int  max_pkt_number; 
extern 	unsigned long int  max_pkt_obt; 
extern bool is_new_route;
extern bool do_cont_check;

extern LogUtil* mainLogUtil;
extern long int iNumCadres; //cadre's number  
extern unsigned long long int iByte_tot;// how many bytes I have read till now	

PacketSemanticAnalyzer PacketSemanticAnalyzer::instance;

PacketSemanticAnalyzer::PacketSemanticAnalyzer()
{
	//set current values and last values to zero
	setCurrentValues(0,0);
	setLastValue();
	pkt_type=0;
	pktType=NULL;	                 	
}                 

PacketSemanticAnalyzer::~PacketSemanticAnalyzer()
{
}

//unused, the values are set in PamOffLineSW_Main.cpp
void PacketSemanticAnalyzer::setStepValue(unsigned long int dpn, unsigned long int dpo )
{
	step_pkt_number=dpn;
	step_pkt_obt=dpo;
}

void PacketSemanticAnalyzer::setLastValue()
{
	last_pkt_number=pkt_number;
	last_pkt_obt=pkt_obt;	
}

void PacketSemanticAnalyzer::setCurrentValues(unsigned long int ex_pkt_number, unsigned long int ex_pkt_obt)
{
	pkt_number=ex_pkt_number;
	pkt_obt=ex_pkt_obt;
}


void PacketSemanticAnalyzer::extractValuesfromPKT(char * hpamPkt)
{
	
/**/
	//all the check can also be done using	pamela::techmodel::EventReader* reader;	
	//PacketUser::getInstance().reader->PKT_UnpackPscuHeader(hpamPkt);		
	//std::cout<<PacketUser::getInstance().reader->Header->GetPscuHeader()->Print()<<std::endl;
  //reader->Header->GetCounter()->PrintCounters();
	//const PacketType* type = 	reader->Header->GetPscuHeader()->GetPacketType();
	//int len= reader->Header->GetPscuHeader()->GetPacketLenght();
	//if(reader){delete reader; reader = NULL;}
	 
/**/	
	unsigned long  int ex_pkt_number=(unsigned long int)(unsigned char)(hpamPkt[7])+
			   		      256*(unsigned long int)(unsigned char)(hpamPkt[6])+
			   		  256*256*(unsigned long int)(unsigned char)(hpamPkt[5]);
	//unsigned int  Counter   = (((UINT32)buff[5]<<16)&0x00FF0000) + (((UINT32)buff[6]<<8)&0x0000FF00) + (((UINT32)buff[7])&0x000000FF);
		       
	unsigned long  int ex_pkt_obt=(unsigned long int)(unsigned char)(hpamPkt[11])+
	            	      256*(unsigned long int)(unsigned char)(hpamPkt[10])+
	                   256*256*(unsigned long int)(unsigned char)(hpamPkt[9])+
	               256*256*256*(unsigned long int)(unsigned char)(hpamPkt[8]);
	
	//unsigned int  OrbitalTime  = (((UINT32)buff[8]<<24)&0xFF000000) + (((UINT32)buff[9]<<16)&0x00FF0000) +  (((UINT32)buff[10]<<8)&0x0000FF00) + (((UINT32)buff[11])&0x000000FF);

	setCurrentValues(ex_pkt_number,ex_pkt_obt);
	
	//if hpamPkt[3] != hpamPkt[4]  the pkt is not good, it was discarded in R3
	pkt_type=(unsigned char)(hpamPkt[3]);
	pktType = GetPacketType(pkt_type);	
}

// PacketSemanticAnalyzer: 
// return false if there is a DISCONTINUITY
// packet counter has priority on obt.
bool PacketSemanticAnalyzer::analysePKT()
{
	
	if(!pktType){
		stringstream oss;
		oss.str()="";
		oss<<"PacketType "<<(int)pkt_type <<" not recognised. Packed skipped. The end of this packet is at byte: "<<iByte_tot<<" in cadre "<<iNumCadres;
		string msg = oss.str();
		mainLogUtil->logError(msg);
		// the packet will not be used in the next module.
		//I don't call setLastValue(), I can't trust on this packet			
		return true;
	}
	
	//IF I FOUND A NEW DOWNLOAD IN THE INPUT FILE, discontinuity
	if(is_new_route){
		setLastValue();	
		return false;		
	}

	if(!do_cont_check){
		setLastValue();//maybe I don't need it	
		return true;
	}
	
	long int delta_pc;		
	long int delta_pt;
	bool cons=true;
	
	//TODO check here ... 
	//USE ONLY PKT_NUMBER and not the OBT ... 
	//correct value is step_pkt_number = 5 and step_pkt_obt =0
	delta_pc = pkt_number-last_pkt_number;	

	if((step_pkt_number==0)||
	   ((delta_pc>0)&&(delta_pc<=(long long int)step_pkt_number)) ||
	   ((delta_pc<0)&&(-delta_pc>=(long long int)(max_pkt_number-step_pkt_number)))//delta_pc < 0 et pkt_number small and last_pkt_number big
	)			
	{
		//cons=true;
		delta_pt=pkt_obt-last_pkt_obt;		
	
		//delta_pt=0 is OK
		if((step_pkt_obt==0)||
		   ((delta_pt>=0)&&(delta_pt<=(long long int)step_pkt_obt)) ||
		   ((delta_pt<0)&&(-delta_pt>=(long long int)(max_pkt_obt-step_pkt_obt)))//delta_pt < 0 et pkt_obt small and last_pkt_obt big
		)
		{
			cons=true;
		}
		else
		{
			cons=false;
		}	
	}
	else
	{
		cons=false;
	}
	
	setLastValue();	
	return cons;
}

//here headerPkt is the header (16 bytes) pamPKT is the rest of the packet of lenght = length
void PacketSemanticAnalyzer::managePKT(char*& headerPkt, char*& pamPkt, long int length,  bool isPKTGood)
{		
	bool isCons = true;	
	//here we retrieve the informations mostly from the header
	extractValuesfromPKT(headerPkt);	
	//here I use the information retrieved to decide if the current packet is continuos 
	isCons=analysePKT();
		
	//The quality of the packet isPKTGood and the information about "CONTINUITY" 
	//are sent to the "user module" where I will save/use it.
	PacketUser::getInstance().usePKT(headerPkt, pamPkt, length, isCons, isPKTGood,
			pktType, pkt_number, pkt_obt);
	
	//just to be sure ...
	if(pamPkt){ delete[] pamPkt; pamPkt = NULL;}
	if(headerPkt){ delete[] headerPkt; headerPkt = NULL;}		
}

/**
 * Get the packet type, this function is analogous to the one in  ../event/PacketType.h
 */
const PacketType* PacketSemanticAnalyzer::GetPacketType(unsigned char pkt_type)  {
switch (pkt_type) {
    case 0x07: return PacketType::PhysEndRun;//warning nel computo CRC
    case 0x08: return PacketType::CalibCalPulse1;
    case 0x09: return PacketType::CalibCalPulse2;
  	case 0x10: return PacketType::Physics;
    case 0x11: return PacketType::CalibTrkBoth;
    case 0x12: return PacketType::CalibTrk1;
    case 0x13: return PacketType::CalibTrk2;
    case 0x16: return PacketType::CalibTof;
    case 0x17: return PacketType::CalibS4;
    case 0x18: return PacketType::CalibCalPed;
    case 0x19: return PacketType::Calib1_Ac1;
    case 0x1A: return PacketType::Calib2_Ac1;
    case 0x1B: return PacketType::Calib1_Ac2;
    case 0x1C: return PacketType::Calib2_Ac2;
    case 0x1D: return PacketType::CalibCal;
    case 0x20: return PacketType::RunHeader;
    case 0x21: return PacketType::RunTrailer; 
    case 0x22: return PacketType::CalibHeader;
    case 0x23: return PacketType::CalibTrailer;
    case 0x24: return PacketType::InitHeader;
    case 0x25: return PacketType::InitTrailer;
    case 0x30: return PacketType::EventTrk;
    case 0x50: return PacketType::Log;
    case 0x51: return PacketType::VarDump;
    case 0x52: return PacketType::ArrDump;
    case 0x53: return PacketType::TabDump;
    case 0x54: return PacketType::Tmtc;
    case 0x55: return PacketType::Mcmd;
    case 0x60: return PacketType::ForcedFECmd;
    case 0x70: return PacketType::Ac1Init;
    case 0x71: return PacketType::CalInit;
    case 0x72: return PacketType::TrkInit;
    case 0x73: return PacketType::TofInit;
    case 0x74: return PacketType::TrgInit;
    case 0x75: return PacketType::NdInit;
    case 0x76: return PacketType::S4Init;
    case 0x77: return PacketType::Ac2Init;
    case 0x81: return PacketType::CalAlarm;
    case 0x82: return PacketType::Ac1Alarm;
    case 0x83: return PacketType::TrkAlarm;
    case 0x84: return PacketType::TrgAlarm;
    case 0x85: return PacketType::TofAlarm;
    case 0x86: return PacketType::S4Alarm;
    case 0x89: return PacketType::Ac2Alarm;
    case 0xA1: return PacketType::TsbT; 
    case 0xAB: return PacketType::TsbB; 
	default: {
	   return NULL;
	  }
  }

}


PacketSemanticAnalyzer& PacketSemanticAnalyzer::getInstance()
{
	return instance;
}


}

