/* ======================================================================== *\
!
! *
! * This file is part of MARS, the MAGIC Analysis and Reconstruction
! * Software. It is distributed to you in the hope that it can be a useful
! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
! * It is distributed WITHOUT ANY WARRANTY.
! *
! * Permission to use, copy, modify and distribute this software and its
! * documentation for any purpose is hereby granted without fee,
! * provided that the above copyright notice appear in all copies and
! * that both that copyright notice and this permission notice appear
! * in supporting documentation. It is provided "as is" without express
! * or implied warranty.
! *
!
!
!   Author(s): Thomas Bretz  12/2000 <mailto:tbretz@uni-sw.gwdg.de>
!
!   Copyright: MAGIC Software Development, 2000-2001
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//
// MRawRunHeader
//
// Root storage container for the RUN HEADER information
//
////////////////////////////////////////////////////////////////////////////

#include "MRawRunHeader.h"

#include <fstream>
#include <iomanip>

#include "MLog.h"
#include "MLogManip.h"

#include "MArrayS.h"

ClassImp(MRawRunHeader);

using namespace std;

// --------------------------------------------------------------------------
//
// Default constructor. Creates array which stores the pixel assignment.
//
//
MRawRunHeader::MRawRunHeader(const char *name, const char *title) : fPixAssignment(NULL)
{
    fName  = name  ? name  : "MRawRunHeader";
    fTitle = title ? title : "Raw Run Header Information";

    fPixAssignment = new MArrayS(0);

    fFormatVersion=0;
    fSoftVersion=0;
    fRunType=0;
    fRunNumber=0;
    fProjectName[0]=0;
    fSourceName[0]=0;
    fSourceEpochChar[0]=0;
    fSourceEpochDate=0;
    fMJD=0;
    fDateYear=0;
    fDateMonth=0;
    fDateDay=0;
    fNumCrates=0;
    fNumPixInCrate=0;
    fNumSamplesLoGain=0;
    fNumSamplesHiGain=0;
    fNumEvents=0;
}

// --------------------------------------------------------------------------
//
// Destructor. Deletes the 'pixel-assignment-array'
//
MRawRunHeader::~MRawRunHeader()
{
    delete fPixAssignment;
}

// --------------------------------------------------------------------------
//
// Read in one run header from the binary file
//
void MRawRunHeader::ReadEvt(istream& fin)
{
    //
    // read one RUN HEADER from the input stream
    //
    fMagicNumber = 0;

    fin.read((char*)&fMagicNumber, 2);          // Total=2

    //
    // check whether the the file has the right file type or not
    //
    if (fMagicNumber != kMagicNumber && fMagicNumber != kMagicNumber+1)
    {
        *fLog << err << "Error: Wrong Magic Number (0x" << hex << fMagicNumber << "): Not a Magic File!" << endl;
        return;
    }

    if (fMagicNumber == kMagicNumber+1)
        *fLog << warn << "WARNING - This file maybe broken (0xc0c1) - DAQ didn't close it correctly!" << endl;

    Byte_t dummy[16];

    fin.read((char*)&fFormatVersion,    2);     // Total=4
    fin.read((char*)&fSoftVersion,      2);     // Total=6
    fin.read((char*)&fRunType,          2);     // Total=8
    fin.read((char*)&fRunNumber,        4);     // Total=12
    fin.read((char*)&fProjectName,     22);     // Total=34
    fin.read((char*)&fSourceName,      12);     // Total=46
    fin.read((char*)dummy,              4); // was RA  (moved to tracking system)
    fin.read((char*)dummy,              4); // was DEC (moved to tracking system)
    fin.read((char*)&fSourceEpochChar,  2);     // Total=56
    fin.read((char*)&fSourceEpochDate,  2);     // Total=58
    fin.read((char*)&fMJD,              4);     // Total=62
    fin.read((char*)&fDateYear,         2);     // Total=64
    fin.read((char*)&fDateMonth,        2);     // Total=66
    fin.read((char*)&fDateDay,          2);     // Total=68
    fin.read((char*)&fNumCrates,        2);     // Total=70
    fin.read((char*)&fNumPixInCrate,    2);     // Total=72
    fin.read((char*)&fNumSamplesLoGain, 2);     // Total=74
    fin.read((char*)&fNumSamplesHiGain, 2);     // Total=76
    fin.read((char*)&fNumEvents,        4);     // Total=80


    //
    // calculate size of array, create it and fill it
    //
    Int_t nPixel = fNumCrates*fNumPixInCrate;
    fPixAssignment->Set(nPixel);

    fin.read((char*)fPixAssignment->GetArray(), nPixel*2);
    fin.read((char*)&dummy, 16);
}

// --------------------------------------------------------------------------
//
// print run header information on *fLog
//
void MRawRunHeader::Print(Option_t *t) const
{
    *fLog << all << endl;
    *fLog << "MagicNumber:  0x" << hex << fMagicNumber << " - ";
    switch (fMagicNumber)
    {
    case kMagicNumber:   *fLog << "OK";               break;
    case kMagicNumber+1: *fLog << "File not closed!"; break;
    default:             *fLog << "Wrong!";           break;
    }
    *fLog << endl;
    *fLog << "Version:      " << dec << "Format=" << fFormatVersion << "  ";
    *fLog << "Software=" << fSoftVersion << endl;
    *fLog << "RunNumber:    " << fRunNumber << " (Type=";
    switch (fRunType)
    {
    case kRTData:
        *fLog << "Data";
        break;
    case kRTPedestal:
        *fLog << "Pedestal";
        break;
    case kRTCalibration:
        *fLog << "Calibration";
        break;
    case kRTMonteCarlo:
        *fLog << "Monte Carlo Data";
        break;
    }
    *fLog << ")" << endl;
    *fLog << "ProjectName: '" << fProjectName << "'" << endl;
    *fLog << "Source:      '" << fSourceName << "' " << "  ";
    *fLog << fSourceEpochChar << dec << fSourceEpochDate << endl;
    *fLog << "Date:         " << setprecision(1) << setiosflags(ios::fixed) << fMJD << " (MJD)  " << fDateYear << "/" << fDateMonth << "/" << fDateDay << endl;
    *fLog << "Crates:       " << fNumCrates << " x " << fNumPixInCrate << " Pixel/Crate = " << fNumCrates*fNumPixInCrate << " Pixel/Evt" << endl;
    *fLog << "Samples:      " << fNumSamplesLoGain << "/" << fNumSamplesHiGain << " (lo/hi) = " << (fNumSamplesLoGain+fNumSamplesHiGain) * fNumCrates * fNumPixInCrate /1024 << "kB/Evt" << endl;
    *fLog << "Evt Counter:  " << fNumEvents << endl;

    *fLog << inf << hex;
    for (int i=0; i<GetNumPixel(); i++)
        *fLog << setfill('0') << setw(3) << (*fPixAssignment)[i] << " ";
    *fLog << hex << endl;

    *fLog << endl;
}

// --------------------------------------------------------------------------
//
// Return the assigned pixel number for the given FADC channel
//
UShort_t MRawRunHeader::GetPixAssignment(UShort_t i) const
{
    // FIXME: Do we need a range check here?
    return (*fPixAssignment)[i];
}

UShort_t MRawRunHeader::GetNumConnectedPixels() const
{
    const Int_t num = fPixAssignment->GetSize();

    UShort_t rc = 0;
    for (int i=0; i<num; i++)
        if (GetPixAssignment(i)>0)
            rc++;
    return rc;
}

// --------------------------------------------------------------------------
//
// return the number of pixel in this event.
//
UShort_t MRawRunHeader::GetNumPixel() const
{
    return fPixAssignment->GetSize();
}

// --------------------------------------------------------------------------
//
// Returns absolute size in bytes of the run header as read from a raw file.
// This must be done _after_ the header is read, because the header doesn't
// have a fixed size (used in MRawSocketRead)
//
Int_t MRawRunHeader::GetNumTotalBytes() const
{
    return 80+fNumCrates*fNumPixInCrate*2+16;
}
