#include "MLog.h"

#include <fstream.h>
#include <TGListBox.h>

#include "MLogManip.h"

ClassImp(MLog)

//
// This is the definition of the global log facility
//
MLog gLog;

void MLog::Init()
{
    //
    // this strange usage of an unbufferd buffer is a workaround
    // to make it work on Alpha and Linux!
    //
    setp(&fBuffer, &fBuffer+1);
    *this << '\0';
}

MLog::MLog(int i) : ostream(this), fPPtr(fBase), fEPtr(fBase+bsz), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(i), fout(NULL), fOutAllocated(kFALSE), fgui(NULL)
{
    Init();
}

MLog::MLog(ofstream &out) : ostream(this), fPPtr(fBase), fEPtr(fBase+bsz), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(eFile), fout(&out), fOutAllocated(kFALSE), fgui(NULL)
{
    Init();
}

MLog::MLog(TGListBox &out) : ostream(this), fPPtr(fBase), fEPtr(fBase+bsz), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(eGui), fout(NULL), fOutAllocated(kFALSE), fgui(&out)
{
    Init();
}

MLog::MLog(const char *fname, int flag) : ostream(this), fPPtr(fBase), fEPtr(fBase+bsz), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(eFile), fgui(NULL)
{
    Init();

    AllocateFile(fname);
    CheckFlag(eFile, flag);
}

void MLog::WriteBuffer()
{
    const int len = fPPtr - fBase;

    if (fDevice&eStdout)
        cout.write(fBase, len);

    if (fDevice&eStderr)
        cerr.write(fBase, len);

    if (fDevice&eFile && fout)
        fout->write(fBase, len);

    if (fDevice&eGui && fgui)
    {
        char dummy[bsz+1];
        memcpy(dummy, fBase, bsz);
        *(dummy+bsz)='\0';
        fgui->AddEntry(dummy, -1);
    }

    //
    // restart writing to the buffer at its first char
    //
    fPPtr = fBase;
}

int MLog::sync()
{
//    cout << "*sync*";
    WriteBuffer();

    if (fDevice&eStdout)
        cout.flush();

    if (fDevice&eStderr)
        cerr.flush();

    if (fDevice&eFile && fout)
        fout->flush();

    return 0;
}

int MLog::overflow(int i) // i=EOF means not a real overflow
{
    //
    // This function comes from streambuf and should
    // output the buffer to the device (flush, endl)
    // or handle a buffer overflow (too many chars)
    // If a real overflow happens i contains the next
    // chars which doesn't fit into the buffer anymore.
    // If the buffer is not really filled i is EOF(-1).
    //
    if (fOutputLevel >= fDebugLevel)
        return 0;

    *fPPtr++ = (char)i;

    if (fPPtr == fEPtr)
        WriteBuffer();

    return 0;
}

void MLog::AllocateFile(const char *fname)
{
    //
    // Create a new instance of an file output stream
    // an set the corresponding flag
    //
    fout = new ofstream(fname);
    fOutAllocated = kTRUE;
}

void MLog::DeallocateFile()
{
    //
    // if fout was allocated by this instance of MLooging
    // delete it.
    //
    if (fOutAllocated)
        delete fout;
}

void MLog::ReallocateFile(const char *fname)
{
    //
    // if necessary delete the old in stance of the file
    // output stream and create a new one
    //
    DeallocateFile();
    AllocateFile(fname);
}

void MLog::CheckFlag(Flags_t chk, int flag)
{
    if (flag==-1)
        return;

    flag ? EnableOutputDevice(chk) : DisableOutputDevice(chk);
}
