#include <log4cxx/logger.h>
#include <fstream>

extern "C" {

    //Struct per il passaggio di dati da e verso la chiamata fortran
    extern struct {
        int   iev;
        int   cstwerr[4];
        float cperror[4];
        float calped[4][11][96];
        float calgood[4][11][96];
        float calthr[4][11][6];
        float calrms[4][11][96];
        float calbase[4][11][6];
        float calvar[4][11][6];
        float calpuls[4][11][96];
    } calib_; 
    //external declaration of the Fortran function 
    void calpedestal_(char*, long int*, int*);
}

#include "ReaderAlgorithms.h"
#include "event/CalibCalPedEvent.h"

using namespace pamela;
using namespace pamela::techmodel;

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

/**
 * Constructor. 
 */
CalibCalPedReader::CalibCalPedReader(void): 
  TechmodelAlgorithm(PacketType::Log, "TechmodelCalibCalPedReader") { 
  logger->debug(_T("Constructor"));
  calibCalPed = new CalibCalPedEvent();
}

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

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

/**
 * Unpack the CalibCalPed event from an input file.
 */
void CalibCalPedReader::RunEvent(int EventNumber, long int dataLength) throw (Exception){
    stringstream oss;       
    int         ERROR;
    char packetData[dataLength];
    InputFile->read(packetData, sizeof(packetData));

    calpedestal_((char*)packetData, &dataLength, &ERROR);

    calibCalPed->unpackError = ERROR;
    if (ERROR != 0) {
        char *errmsg;
        switch (ERROR){
            case 1: errmsg = "CALORIMETER NOT FOUND";
        }
        oss.str("");
        oss << "Fortran77 function calpedestal error code = " << ERROR
            <<  " " << errmsg;
        logger->warn(oss.str().c_str());
    } else {
      //Store the unpacked data
        calibCalPed->iev = calib_.iev;
        memcpy(calibCalPed->cstwerr, calib_.cstwerr, sizeof(calibCalPed->cstwerr));
        memcpy(calibCalPed->cperror, calib_.cperror, sizeof(calibCalPed->cperror));
    //--------have to invert array because of FORTRAN <-> C different management of the indexes
        float tempCalped[96][11][4];
        float tempCalgood[96][11][4];
        float tempCalthr[6][11][4];
        float tempCalrms[96][11][4];
        float tempCalbase[6][11][4];
        float tempCalvar[6][11][4];
        float tempCalpuls[96][11][4];

        memcpy(tempCalped,  calib_.calped,  sizeof(tempCalped));
        memcpy(tempCalgood, calib_.calgood, sizeof(tempCalgood));
        memcpy(tempCalthr,  calib_.calthr,  sizeof(tempCalthr));
        memcpy(tempCalrms,  calib_.calrms,  sizeof(tempCalrms));
        memcpy(tempCalbase, calib_.calbase, sizeof(tempCalbase));
        memcpy(tempCalvar,  calib_.calvar,  sizeof(tempCalvar));
        memcpy(tempCalpuls, calib_.calpuls, sizeof(tempCalpuls));

        for (int i = 0; i < 4; i++){
            for (int j = 0; j <11; j++){
                for (int z = 0; z < 96; z++){
                    calibCalPed->calped[i][j][z]    = tempCalped[z][j][i];
                    calibCalPed->calgood[i][j][z]   = tempCalgood[z][j][i];
                    calibCalPed->calrms[i][j][z]    = tempCalrms[z][j][i];
                    calibCalPed->calpuls[i][j][z]   = tempCalpuls[z][j][i];
                }
            }
        }

        for (int i = 0; i < 4; i++){
            for (int j = 0; j <11; j++){
                for (int z = 0; z < 6; z++){
                    calibCalPed->calthr[i][j][z]    = tempCalthr[z][j][i];
                    calibCalPed->calbase[i][j][z]   = tempCalbase[z][j][i];
                    calibCalPed->calvar[i][j][z]    = tempCalvar[z][j][i];
                }
            }
        }
    //-----------------------------------------------------------------------------------------
    }
}


