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

//////////////////////////////////////////////////////////////////////////////
//
//  MReportCamera
//
// This is the class interpreting and storing the CAMERA-REPORT information.
//
// Most of the information is redirected to the classes MCamera* and stored
// there.
//
//////////////////////////////////////////////////////////////////////////////
#include "MReportCamera.h"

#include "MLogManip.h"

#include "MAstro.h"
#include "MParList.h"

#include "MCameraCalibration.h"
#include "MCameraCooling.h"
#include "MCameraHV.h"
#include "MCameraLV.h"
#include "MCameraAUX.h"
#include "MCameraLids.h"

ClassImp(MReportCamera);

using namespace std;

// --------------------------------------------------------------------------
//
// Default construtor. Initialize identifier to "CAMERA-REPORT"
//
MReportCamera::MReportCamera() : MReport("CAMERA-REPORT")
{
    fName = "MReportCamera";
    fTitle = "Class for CAMERA-REPORT information";
}

// --------------------------------------------------------------------------
//
// FindCreate the following objects:
//  - MCameraCooling
//  - MCameraLids
//  - MCameraAUX
//  - MCameraHV
//  - MCameraLV
//  - MCameraCalibration
//
Bool_t MReportCamera::SetupReading(MParList &plist)
{
    fCooling = (MCameraCooling*)plist.FindCreateObj("MCameraCooling");
    if (!fCooling)
        return kFALSE;

    fLids = (MCameraLids*)plist.FindCreateObj("MCameraLids");
    if (!fLids)
        return kFALSE;

    fAUX = (MCameraAUX*)plist.FindCreateObj("MCameraAUX");
    if (!fAUX)
        return kFALSE;

    fHV = (MCameraHV*)plist.FindCreateObj("MCameraHV");
    if (!fHV)
        return kFALSE;

    fLV = (MCameraLV*)plist.FindCreateObj("MCameraLV");
    if (!fLV)
        return kFALSE;

    fCalibration = (MCameraCalibration*)plist.FindCreateObj("MCameraCalibration");
    if (!fCalibration)
        return kFALSE;

    return MReport::SetupReading(plist);
}

// --------------------------------------------------------------------------
//
// Check whether the given TString begins with the given tag. Remove
// the tag from the string.
//
Bool_t MReportCamera::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 DC currents
    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Interprete the DC* part of the report
//
Bool_t MReportCamera::InterpreteDC(TString &str)
{
    if (!CheckTag(str, "DC "))
        return kFALSE;

    str.Remove(0, 577*4); // Remove DC currents
    str=str.Strip(TString::kLeading);
    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Interprete the HV* part of the report
//
Bool_t MReportCamera::InterpreteHV(TString &str)
{
    if (!CheckTag(str, "HV "))
        return kFALSE;

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

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

        const Int_t n=sscanf(hex, "%3hx", &fHV->fHV[i++]);
        if (n==1)
            continue;

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

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

// --------------------------------------------------------------------------
//
// Interprete the COOL* part of the report
//
Bool_t MReportCamera::InterpreteCOOL(TString &str)
{
    if (!CheckTag(str, "COOL "))
        return kFALSE;

    Int_t len;

    Int_t wall, opt, center, water;
    Short_t hwall, hcenter, hip, lop, pump, ref, valv, res, fans;
    const Int_t n=sscanf(str.Data(), "%d %d %d %d %hu %hu %hu %hu %hu %hu %hu %hu %hu %n",
                         &wall, &opt, &center, &water, &hwall, &hcenter,
                         &hip,  &lop, &pump, &ref, &valv, &res, &fans, &len);
    if (n!=13)
    {
        *fLog << warn << "WARNING - Reading information of 'COOL' section." << endl;
        return kFALSE;
    }

    fCooling->fTempWall            = 0.1*wall;
    fCooling->fTempOptLink         = 0.1*opt;
    fCooling->fTempCenter          = 0.1*center;
    fCooling->fTempWater           = 0.1*water;
    fCooling->fHumWall             = (Byte_t)hwall;
    fCooling->fHumCenter           = (Byte_t)hcenter;
    fCooling->fStatusPressureHi    = (Bool_t)hip;
    fCooling->fStatusPressureLo    = (Bool_t)lop;
    fCooling->fStatusPump          = (Bool_t)pump;
    fCooling->fStatusRefrigrerator = (Bool_t)ref;
    fCooling->fStatusValve         = (Bool_t)valv;
    fCooling->fStatusResistor      = (Bool_t)res;
    fCooling->fStatusFans          = (Bool_t)fans;

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

// --------------------------------------------------------------------------
//
// Interprete the LID* part of the report
//
Bool_t MReportCamera::InterpreteLID(TString &str)
{
    if (!CheckTag(str, "LID "))
        return kFALSE;

    Int_t len;
    Short_t limao, limac, limbo, limbc;
    Short_t slimao, slimac, slimbo, slimbc;
    Short_t slida, slidb, mlida, mlidb;
    const Int_t n=sscanf(str.Data(), "%hu %hu %hu %hu %hu %hu %hu %hu %hu %hu %hu %hu %n",
                         &limao, &limac, &limbo, &limbc,
                         &slimao, &slimac, &slimbo, &slimbc,
                         &slida, &slidb, &mlida, &mlidb,
                         &len);
    if (n!=12)
    {
        *fLog << warn << "WARNING - Reading information of 'LID' section." << endl;
        return kFALSE;
    }

    fLids->fLidA.fLimitOpen       = (Bool_t)limao;
    fLids->fLidA.fLimitClose      = (Bool_t)limac;
    fLids->fLidA.fSafetyLimitOpen = (Bool_t)slimao;
    fLids->fLidA.fSafetyLimitClose= (Bool_t)slimac;
    fLids->fLidA.fStatusLid       = (Byte_t)slida;
    fLids->fLidA.fStatusMotor     = (Byte_t)mlida;

    fLids->fLidB.fLimitOpen       = (Bool_t)limbo;
    fLids->fLidB.fLimitClose      = (Bool_t)limbc;
    fLids->fLidB.fSafetyLimitOpen = (Bool_t)slimbo;
    fLids->fLidB.fSafetyLimitClose= (Bool_t)slimbc;
    fLids->fLidB.fStatusLid       = (Byte_t)slidb;
    fLids->fLidB.fStatusMotor     = (Byte_t)mlidb;

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

// --------------------------------------------------------------------------
//
// Interprete the HVPS* part of the report
//
Bool_t MReportCamera::InterpreteHVPS(TString &str)
{
    if (!CheckTag(str, "HVPS "))
        return kFALSE;

    Int_t len;
    Short_t c1, c2;
    const Int_t n=sscanf(str.Data(), "%hd %hd %hd %hd %n",
                         &fHV->fVoltageA, &fHV->fVoltageB, &c1, &c2, &len);
    if (n!=4)
    {
        *fLog << warn << "WARNING - Reading information of 'HVPS' section." << endl;
        return kFALSE;
    }

    fHV->fCurrentA = (Byte_t)c1;
    fHV->fCurrentB = (Byte_t)c2;

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

// --------------------------------------------------------------------------
//
// Interprete the LV* part of the report
//
Bool_t MReportCamera::InterpreteLV(TString &str)
{
    if (!CheckTag(str, "LV "))
        return kFALSE;

    Int_t len;
    Short_t vap5, vap12, van12, vbp5, vbp12, vbn12;
    Short_t valp12, vblp12, cap5, cap12, can12, cbp5, cbp12;
    Short_t cbn12, calp12, cblp12, lvps, temp, hum;
    const Int_t n=sscanf(str.Data(), "%hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %n",
                         &vap5, &vap12, &van12, &vbp5, &vbp12, &vbn12,
                         &valp12, &vblp12, &cap5, &cap12, &can12, &cbp5, &cbp12,
                         &cbn12, &calp12, &cblp12, &lvps, &temp, &hum, &len);
    if (n!=19)
    {
        *fLog << warn << "WARNING - Reading information of 'LV' section." << endl;
        return kFALSE;
    }

    fLV->fRequestPowerSupply = (Bool_t)lvps;
    fLV->fTemp = 0.1*temp;
    fLV->fHumidity = (Byte_t)hum;

    fLV->fPowerSupplyA.fVoltagePos5V         = 0.01*vap5;
    fLV->fPowerSupplyA.fVoltagePos12V        = 0.01*vap12;
    fLV->fPowerSupplyA.fVoltageNeg12V        = 0.01*van12;
    fLV->fPowerSupplyA.fVoltageOptLinkPos12V = 0.01*valp12;
    fLV->fPowerSupplyA.fCurrentPos5V         = 0.001*cap5;
    fLV->fPowerSupplyA.fCurrentPos12V        = 0.001*cap12;
    fLV->fPowerSupplyA.fCurrentNeg12V        = 0.001*can12;
    fLV->fPowerSupplyA.fCurrentOptLinkPos12V = 0.001*calp12;

    fLV->fPowerSupplyB.fVoltagePos5V         = 0.01*vbp5;
    fLV->fPowerSupplyB.fVoltagePos12V        = 0.01*vbp12;
    fLV->fPowerSupplyB.fVoltageNeg12V        = 0.01*vbn12;
    fLV->fPowerSupplyB.fVoltageOptLinkPos12V = 0.01*vblp12;
    fLV->fPowerSupplyB.fCurrentPos5V         = 0.001*cbp5;
    fLV->fPowerSupplyB.fCurrentPos12V        = 0.001*cbp12;
    fLV->fPowerSupplyB.fCurrentNeg12V        = 0.001*cbn12;
    fLV->fPowerSupplyB.fCurrentOptLinkPos12V = 0.001*cblp12;

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

// --------------------------------------------------------------------------
//
// Interprete the AUX* part of the report
//
Bool_t MReportCamera::InterpreteAUX(TString &str)
{
    if (!CheckTag(str, "AUX "))
        return kFALSE;

    Int_t len;
    Short_t led, fan;
    const Int_t n=sscanf(str.Data(), "%hd %hd %n", &led, &fan, &len);
    if (n!=2)
    {
        *fLog << warn << "WARNING - Reading information of 'AUX' section." << endl;
        return kFALSE;
    }

    fAUX->fRequestCaosLEDs=(Bool_t)led;
    fAUX->fRequestFansFADC=(Bool_t)fan;

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

// --------------------------------------------------------------------------
//
// Interprete the CAL* part of the report
//
Bool_t MReportCamera::InterpreteCAL(TString &str)
{
    if (!CheckTag(str, "CAL "))
        return kFALSE;

    Int_t len;
    Short_t hv, lv, cont, pin;

    const Int_t n=sscanf(str.Data(), "%hd %hd %hd %hd %n", &hv, &lv, &cont, &pin, &len);
    if (n!=4)
    {
        *fLog << warn << "WARNING - Reading information of 'CAL' section." << endl;
        return kFALSE;
    }

    fCalibration->fRequestHiVoltage = (Bool_t)hv;
    fCalibration->fRequestLoVoltage = (Bool_t)lv;
    fCalibration->fRequestContLight = (Bool_t)cont;
    fCalibration->fRequestPinDiode  = (Bool_t)pin;

    str.Remove(0, len);
    str=str.Strip(TString::kBoth);
    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Interprete the CAMERA-REPORT part
//
Bool_t MReportCamera::InterpreteCamera(TString &str)
{
    //
    // I have tried to do it with pure pointer arithmentics, but most of the time is spent
    // to do the sscanf. So we gain less than 5% not using TString like it is done here.
    Int_t len;
    Short_t cal, stat, hvps, lid, lv, cool, hv, dc, led, fan, can, io, clv;
    Int_t n=sscanf(str.Data(), " %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %n",
                   &cal, &stat, &hvps, &lid, &lv, &cool, &hv,
                   &dc, &led, &fan, &can, &io, &clv, &len);
    if (n!=13)
    {
        *fLog << warn << "WARNING - Cannot interprete status' of subsystems." << endl;
        return kFALSE;
    }
    str.Remove(0, len);
    str=str.Strip(TString::kLeading);

    fHV->fStatus                   = (Byte_t)hvps;
    fLids->fStatus                 = (Byte_t)lid;
    fLV->fStatus                   = (Byte_t)lv;
    fCooling->fStatus              = (Byte_t)cool;
    fHV->fStatusRamping            = (Byte_t)hv;
    fAUX->fStatusCaosLEDs          = (Bool_t)led;
    fAUX->fStatusFansFADC          = (Bool_t)fan;
    fCalibration->fStatus          = (Bool_t)cal;
    fCalibration->fStatusCANbus    = (Bool_t)can;
    fCalibration->fStatusIO        = (Bool_t)io;
    fCalibration->fStatusLoVoltage = (Bool_t)clv;
    fStatus                        = (Byte_t)stat;
    fStatusDC                      = (Byte_t)dc;

    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Interprete the body of the CAMERA-REPORT string
//
Int_t MReportCamera::InterpreteBody(TString &str)
{
    if (!InterpreteCamera(str))
        return kCONTINUE;

    if (!InterpreteDC(str))
        return kCONTINUE;

    if (!InterpreteHV(str))
        return kCONTINUE;

    if (!InterpreteCOOL(str))
        return kCONTINUE;

    if (!InterpreteLID(str))
        return kCONTINUE;

    if (!InterpreteHVPS(str))
        return kCONTINUE;

    if (!InterpreteLV(str))
        return kCONTINUE;

    if (!InterpreteAUX(str))
        return kCONTINUE;

    if (!InterpreteCAL(str))
        return kCONTINUE;

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

    return kTRUE;
}
