/** @file
 * $Source: /repository/PamOffLineSW/physics/S4Reader.cpp,v $
 * $Id: S4Reader.cpp,v 1.5 2008-03-05 11:37:37 messineo Exp $
 * $Author: messineo $
 * 
 * Implementation of the S4Reader class.
 */

#include <string>
#include "S4Reader.h"

using namespace pamela;
using namespace pamela::S4;


/**
 * Constructor. 
 */
S4Reader::S4Reader(void): 
  TechmodelAlgorithm(PacketType::Physics, "TechmodelS4Reader") { 
  s4 = new S4Event();
}

/**
 * Get a string with the version info of the algorithm.
 */
std::string S4Reader::GetVersionInfo(void) const {
  return 
    "$Header: /repository/PamOffLineSW/physics/S4Reader.cpp,v 1.5 2008-03-05 11:37:37 messineo Exp $";
}

/**
 * Initialize the algorithm with a special run. This will initialize the
 * event reader routines for all packet types.
 */
void S4Reader::Init(PamelaRun *run) {
  run->WriteSubPacket(this, &s4, s4->Class());
}

/**
 * Unpack the S4 event from an input file.
 */
void S4Reader::RunEvent(int EventNumber) {
  
}

/**
 * Unpack the S4 data event from the physical packet.
 * Unfortunately the only definition available for S4 is "Rigth before the Neutron detector data"
 * consequently supposing the Neutron data (12 Bytes) always present S4 start 18 Bytes before the end of the packet
 */
void S4Reader::RunEvent(int EventNumber, const char subData[], long int length) {
   int offset;
   int index = haveData(&*subData, length);
   
   if (index > 0){
        int offset = length - index; 
        s4->S4_REG_STATUS        = (((UINT8)subData[offset])&0xF0);
        s4->S4_DATA              = ((((UINT16)subData[offset]<<8)&0x0FFF) + (((UINT16)subData[offset+1])&0x00FF));
        s4->S4_CMD_NUM           = (((UINT8)subData[offset+2])&0xFF);
        s4->S4_RESP_LENGHT       = ((((UINT16)subData[offset+3]<<8)&0xFF00) + (((UINT16)subData[offset+4])&0x00FF));
        s4->S4_OVERALL_CHKCODE   = (((UINT8)subData[offset+5])&0xFF);
        s4->unpackError          = 0;
    } else {
        s4->unpackError = 1;
        //marco: scrivo in log file ...
        std::stringstream oss;  
        string msg;
        oss << "S4: " << "no data found ";
        msg=oss.str();
        PamOffLineSW::mainLogUtil->logAll(msg);	            
    }
}

/* 
 * 
 * @return int
 * It return the index, starting from the end of data[] parameter, which
 * is the starting byte of the S4 data. 
 *
*/
/**
 * Check if S4Data are present.
 * @param const char data[] - Physics data
 * @param long int lenght - Lenght of data[]
 * @return int represent the index from the end of data[] 
 *             from which S4 data starts
 */
int S4Reader::haveData(const char data[], long int length){
    int ret = 0;
    /* I start 20 bytes from the end because we have three cases:
     *
     * 1) S4 (4bytes) + NeutronDetector (12bytes) //END PACKET
     * 2) S4 (4bytes) //END PACKET
     * 3) //END PACKET
     * 
     * so in anycase I expect to find the data into the last 20 bytes
     * Anyway, it will be a MUST to implements also the check of the CRC
     * on the S4 data to have a better confidence on the data; the crc algorithm 
     * sholud be the same of the Tracker
     * 
     */
        
    //Check the existence of NeutronDetector data
    if (((UINT8)data[length - 1] == 0x0F)&&((UINT8)data[length - 5] == 0x0F)&&((UINT8)data[length - 9] == 0x0F)) {
        //Chech the existance of S4 data before NeutronDetector
        if (((UINT8)data[length - 14] == 0x03) &&
            ((UINT8)data[length - 15] == 0x00) &&
            ((UINT8)data[length - 16] == 0xD8)) ret = 18;
      //NeutronDetector data does not exists     
    } else {
        //Chech the existance of S4 data at the end of the Physics packet
        if ( ((UINT8)data[length - 2] == 0x03) && 
             ((UINT8)data[length - 3] == 0x00) && 
             ((UINT8)data[length - 4] == 0xD8)) ret = 6;
    } 
    return ret;
}
