/* ======================================================================== *\
!
! *
! * 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/2003 <mailto:tbretz@astro.uni-wuerzburg.de>
!
!   Copyright: MAGIC Software Development, 2000-2003
!
!
\* ======================================================================== */

//////////////////////////////////////////////////////////////////////////////
//
//  MReportCC
//
// This is the class interpreting and storing the CC-REPORT information.
//
// From here maily weather station data is decoded such as
// temperature, humidity, wind-speed and solar radiation
//
// Class Version 2:
// ----------------
//  +  Float_t fUPSStatus; // arbitrary units (still not properly defined)
//  +  Float_t fDifRubGPS; // [us] Difference between the Rubidium clock time and the time provided by the GPS receiver
//
//
//////////////////////////////////////////////////////////////////////////////
#include "MReportCC.h"

#include "MLogManip.h"

#include "MParList.h"

#include "MCameraTH.h"
#include "MCameraTD.h"
#include "MCameraRecTemp.h"

ClassImp(MReportCC);

using namespace std;

// --------------------------------------------------------------------------
//
// Default construtor. Initialize identifier to "CC-REPORT" Report
// is expected to have no 'subsystem' time.
//
MReportCC::MReportCC() : MReport("CC-REPORT", kFALSE)
{
    fName  = "MReportCC";
    fTitle = "Class for CC-REPORT information";
}

// --------------------------------------------------------------------------
//
// FindCreate the following objects:
//  - MCameraTH
//
Bool_t MReportCC::SetupReading(MParList &plist)
{
    fTH = (MCameraTH*)plist.FindCreateObj("MCameraTH");
    if (!fTH)
        return kFALSE;

    fTD = (MCameraTD*)plist.FindCreateObj("MCameraTD");
    if (!fTD)
        return kFALSE;

    fRecTemp = (MCameraRecTemp*)plist.FindCreateObj("MCameraRecTemp");
    if (!fRecTemp)
        return kFALSE;

    return MReport::SetupReading(plist);
}

// --------------------------------------------------------------------------
//
// Check whether the given TString begins with the given tag. Remove
// the tag from the string.
//
Bool_t MReportCC::CheckTag(TString &str, const char *tag) const
{
    if (!str.BeginsWith(tag))
    {
        *fLog << warn << "WARNING - '" << tag << "' tag not found." << endl;
        return kFALSE;
    }
    str.Remove(0, strlen(tag)); // Remove Tag
    return kTRUE;
}


// --------------------------------------------------------------------------
//
// Interprete the body of the CC-REPORT string
//
Bool_t MReportCC::InterpreteCC(TString &str, Int_t ver)
{
    const Int_t skip = ver<200407270 ? 30 : 31;

    // Remove the 30/31 tokens of the subsystem status
    //  table 12.1 p59
    for (int i=0; i<skip; i++)
        str.Remove(0, str.First(' ')+1);

    Int_t len;
    const Int_t n=sscanf(str.Data(),
                         "%*f %*f %*f %*f %f %f %f %f %f %f %n",
                         &fTemperature, &fSolarRadiation, &fWindSpeed,
                         &fHumidity, &fUPSStatus, &fDifRubGPS, &len);
    if (n!=6)
    {
        *fLog << warn << "WARNING - Wrong number of arguments." << endl;
        return kFALSE;
    }

    str.Remove(0, len);

    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Interprete the TH (discriminator thresholds) part of the report
//
Bool_t MReportCC::InterpreteTH(TString &str, Int_t ver)
{
    if (!CheckTag(str, "TH "))
        return kFALSE;

    // Skip the TH (discriminator thresholds) part of the report (for old
    // CC files with wrong or nonsense number of TH-Bytes)
    if (ver<200507190)
    {
        Ssiz_t pr = str.First(' ');
        if (pr<0)
        {
            *fLog << warn << "WARNING - No TH information found at all." << endl;
            return kFALSE;
        }
        if (pr!=1154)
        {
            fTD->Invalidate();

            str.Remove(0, pr);
            str=str.Strip(TString::kLeading);
            return kTRUE;
        }
    }

    const char *pos = str.Data();
    const char *end = str.Data()+577*2;

    Int_t i=0;
    while (pos<end)
    {
        const Char_t hex[2] = { pos[0], pos[1] };
        pos += 2;

        const Int_t n=sscanf(hex, "%2hhx", &fTH->fTH[i++]);
        if (n==1)
            continue;

        *fLog << warn << "WARNING - Reading hexadecimal TH information." << endl;
        return kFALSE;
    }

    fTH->SetValid();

    str.Remove(0, end-str.Data()); // Remove TH
    str=str.Strip(TString::kLeading);
    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Interprete the TD (discriminator delays) part of the report
//
Bool_t MReportCC::InterpreteTD(TString &str, Int_t ver)
{
    if (!CheckTag(str, "TD "))
        return kFALSE;

    // Skip the TD (discriminator delays) part of the report (for old
    // CC files with wrong or nonsense number of TD-Bytes)
    if (ver<200412210)
    {
        Ssiz_t pr = str.First(' ');
        if (pr<0)
        {
            *fLog << warn << "WARNING - No TD information found at all." << endl;
            return kFALSE;
        }
        if (pr!=1000)
        {
            fTD->Invalidate();

            str.Remove(0, pr);
            str=str.Strip(TString::kLeading);
            return kTRUE;
        }
    }

    // Older files have less bytes (pixels) stored
    const Int_t numpix = ver<200510250 ? 500 : 577;

    const char *pos = str.Data();
    const char *end = str.Data()+numpix*2;

    Int_t i=0;
    while (pos<end)
    {
        const Char_t hex[3] = { pos[0], pos[1], 0 };
        pos += 2;

        const Int_t n=sscanf(hex, "%2hhx", &fTD->fTD[i++]);
        if (n==1)
            continue;

        *fLog << warn << "WARNING - Reading hexadecimal TD information." << endl;
        return kFALSE;
    }

    fTD->SetValid();

    str.Remove(0, end-str.Data()); // Remove TD
    str=str.Strip(TString::kLeading);

    return kTRUE;
}


// --------------------------------------------------------------------------
//
// Interprete the receiver board temperature part of the report
//
Bool_t MReportCC::InterpreteRecTemp(TString &str)
{
    if (!CheckTag(str, "RECTEMP "))
        return kFALSE;

    Int_t len;
    for (Int_t i=0; i<76; i++)
    {
        const Int_t n=sscanf(str.Data(), "%f %n", &fRecTemp->fRecTemp[i], &len);
        str.Remove(0, len);

        if (n==1)
            continue;

        if (n==0 && i==0)
        {
            *fLog << inf << "Receiver Board Temperatures empty." << endl;
            fRecTemp->Invalidate();
            break;
        }

        *fLog << warn << "WARNING - Reading Receiver Board Temperature information." << endl;
        return kFALSE;
    }

    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Interprete the body of the CC-REPORT string
//
Int_t MReportCC::InterpreteBody(TString &str, Int_t ver)
{
    if (ver<200404070)
    {
        *fLog << err << "ERROR - MReportCC::InterpreteBody not prepared for ";
        *fLog << " report-files with version<200404070" << endl;
        return kFALSE;
    }

    if (!InterpreteCC(str, ver))
        return kCONTINUE;

    if (str.BeginsWith("RECEIVERS-COM-ERROR"))
    {
        *fLog << inf << "Receiver Com-error... threshold setting and receiver board temp. invalid." << endl;
        fTD->Invalidate();
        fTH->Invalidate();
        fRecTemp->Invalidate();
        str.Remove(0, 19);
    }
    else
    {
        if (!InterpreteTH(str, ver))
            return kCONTINUE;

        if (!InterpreteTD(str, ver))
            return kCONTINUE;

        if (ver>=200510250)
            if (!InterpreteRecTemp(str))
                return kCONTINUE;
    }

    if (str.Strip(TString::kBoth)!=(TString)"OVER")
    {
        *fLog << warn << "WARNING - 'OVER' tag not found." << endl;
        return kCONTINUE;
    }

    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Print contents of report
//
void MReportCC::Print(Option_t *opt) const
{
    *fLog << all << GetDescriptor() << ":  Status=" << (int)GetState();
    *fLog << "   Hum=" << Form("%3.0f", fHumidity);
    *fLog << "%  Temp=" << Form("%+3.0f", fTemperature);
    *fLog << "°C  Wind=" << Form("%3.0f", fWindSpeed);
    *fLog << "km/h  SolarRad=" << Form("%4.0f", fSolarRadiation) << "W/m^2" << endl;
}
