/** @file
 * $Source: /home/cvsmanager/yoda/techmodel/physics/S4Reader.cpp,v $
 * $Id: S4Reader.cpp,v 3.0 2005/03/04 15:54:11 kusanagi Exp $
 * $Author: kusanagi $
 * 
 * Implementation of the S4Reader class.
 */

#include <string>
#include <log4cxx/logger.h>
#include "S4Reader.h"

using namespace pamela;
using namespace pamela::S4;

static log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(_T("pamela.techmodel.S4.S4Reader"));

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

/**
 * Get a string with the version info of the algorithm.
 */
std::string S4Reader::GetVersionInfo(void) const {
  return 
    "$Header: /home/cvsmanager/yoda/techmodel/physics/S4Reader.cpp,v 3.0 2005/03/04 15:54:11 kusanagi Exp $";
}

/**
 * Initialize the algorithm with a special run. This will initialize the
 * event reader routines for all packet types.
 */
void S4Reader::Init(PamelaRun *run) {
  logger->debug(_T("Initialize"));
  SetInputStream(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) {
   const int lenS4Data = 6;
   char *data = new char[length];
   int offset;
   int index = haveData(data, length);
   
   if (index > -1){
        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;
    }
    delete[] data;
}

/* 
 * 
 * @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 - -1 if S4 has not been found, otherwise it represent the
 *               index from the end of data[] from which S4 data starts
 */
int S4Reader::haveData(const char data[], long int length){
    int ret = -1;
    /* 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
     * 
     */
    int  index = 0;
    char dataByte;
    int subIndex = 0;
    const int subDataDepth = 20;
    int offset = length - subDataDepth;
    const int subSignDim = 3;
    const unsigned char subSign[subSignDim]={0xD8, 0x00, 0x03};
    while (index < subDataDepth){
        dataByte = data[offset + index++];
        if (dataByte == (char)(*(subSign+subIndex))){
            if (subIndex++ == (subSignDim-1)) {
                //If here i catch it!!!
                return subDataDepth - index + subSignDim + 2;
            } 
        } else {
            index = index - (subIndex);
            subIndex = 0;
        }
    }
    return ret;
}
