/*======================================================================== *\
!
! *
! * 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  10/2001 <mailto:tbretz@uni-sw.gwdg.de>
!
!   Copyright: MAGIC Software Development, 2000-2001
!
!
\* ======================================================================== */

#include "MGFadcDisp.h"

#include <stdlib.h>               // atoi
#include <iostream.h>             // cout for debugging

#include <TList.h>                // TList
#include <TCanvas.h>              // TCanvas
#include <TRootEmbeddedCanvas.h>  // TRootEmbeddedCanvas

#include <TGTab.h>                // TGTab
#include <TGLabel.h>              // TGLabel
#include <TGButton.h>             // TGPictureButton
#include <TGSlider.h>             // TGVSlider
#include <TGMsgBox.h>             // TGMsgBox
#include <TGListBox.h>            // TGListBox
#include <TGTextEntry.h>          // TGTextEntry

#include <TG3DLine.h>             // TGHorizontal3DLine
                                  // use TGSplitter instead for root<3.00
#include "MParList.h"
#include "MTaskList.h"
#include "MReadTree.h"
#include "MEvtLoop.h"
#include "MRawEvtData.h"
#include "MRawEvtPixelIter.h"

ClassImp(MGFadcDisp);

enum MGFadcDispCommand
{
    M_PREVPIXEL = 0x1000,
    M_NEXTPIXEL = 0x1001,

    M_PIXELLIST = 0x1002
};

// --------------------------------------------------------------------------
//
//  Add the missing GUI elements: These are the pixel number controls
//
void MGFadcDisp::AddSetupElements()
{
    fTab1->ChangeOptions(kHorizontalFrame);

    //
    // Create first gui element for tab1
    //
    fPixelList = new TGListBox(fTab1, M_PIXELLIST);
    fPixelList->Associate(this);
    fPixelList->Resize(80, 230);

    TGLayoutHints *layplist = new TGLayoutHints(kLHintsExpandY|kLHintsLeft, 5, 5, 5, 5);
    fTab1->AddFrame(fPixelList, layplist);

    TGVerticalFrame *fMidFrame = new TGVerticalFrame(fTab1, 300, 100);
    fList->Add(fMidFrame);

    TGLayoutHints *laytab = new TGLayoutHints(kLHintsRight|kLHintsExpandY, 5, 5, 5, 5);
    fList->Add(laytab);

    fTab1->AddFrame(fMidFrame, laytab);

    //
    // Create gui elements for vertical frame
    //
    TGTextButton *prevpix = new TGTextButton(fMidFrame, "<< Prev Pixel", M_PREVPIXEL);
    TGTextButton *nextpix = new TGTextButton(fMidFrame, "Next Pixel >>", M_NEXTPIXEL);
    prevpix->Associate(this);
    nextpix->Associate(this);

    TGVSlider *slider = new TGVSlider(fMidFrame, 200, kSlider1|kScaleBoth);
    slider->Associate(this);
    slider->SetRange(0, 576);

    //
    // Layout gui elements
    //
    TGLayoutHints *laybut    = new TGLayoutHints(kLHintsRight);
    TGLayoutHints *layslider = new TGLayoutHints(kLHintsCenterX|kLHintsExpandY);

    fMidFrame->AddFrame(prevpix, laybut);
    fMidFrame->AddFrame(slider,  layslider);
    fMidFrame->AddFrame(nextpix, laybut);
}

// --------------------------------------------------------------------------
//
//  Constructor
//
MGFadcDisp::MGFadcDisp(char *filename, char *treename,
                       const TGWindow *p, const TGWindow *main,
                       UInt_t w, UInt_t h)
    : MGEvtDisplay(filename, treename, p, main, w, h)
{
    //
    // Add the missing GUI elements (pixellist, pixel number controls)
    //
    AddSetupElements();

    //
    // preprocess eventloop and read in first event (process)
    //
    GetReader()->DisableAutoScheme();
    ReadFirstEvent();

    //
    // Map the window, set up the layout, etc.
    //
    MapSubwindows();

    Layout();

    SetWindowName("Fadc Event Display");
    SetIconName("Fadc");

    MapWindow();

}

// --------------------------------------------------------------------------
//
//  return pointer to event data
//
MRawEvtData *MGFadcDisp::GetEvent() const
{
    return (MRawEvtData*)GetParList()->FindObject("MRawEvtData");
}

// --------------------------------------------------------------------------
//
//   after a new event is read in one has to update
//   the list of pixels in the fPixelList (TGListBox)
//
void MGFadcDisp::DisplayPixel(Int_t lastsel, Bool_t update)
{
    MRawEvtData *data = GetEvent();

    if (!data)
        return;

    MRawEvtPixelIter pixel(data);

    if (update)
    {
        //
        //   put the selection of the last event in memory
        //
        while (pixel.Next())
        {
            char txt[100];
            sprintf(txt, "%d", pixel.GetPixelId());
            fPixelList->AddEntry(txt, pixel.GetPixelId());
        }

        fPixelList->MapSubwindows();
        fPixelList->Layout();
    }

    //
    // check if the pixel from last event also occurs in this event
    //
    fCanvas->Clear();
    fCanvas->cd();

    if (lastsel<0 || !pixel.Jump(lastsel))
    {
        pixel.Reset();
        lastsel=0; //pixel.GetPixelId();
    }

    char txt[100];
    sprintf(txt, "GRAPH%d", lastsel);
    data->Draw(txt);
    fPixelList->Select(lastsel, kTRUE);
    fPixelList->SetTopEntry(lastsel);

    fCanvas->Modified();
    fCanvas->Update();
}

// --------------------------------------------------------------------------
//
//  Update the contents of the canvas
//
void MGFadcDisp::UpdateDisplay()
{
    if (!IsInitOk())
        return;

    const Int_t lastsel = fPixelList->GetSelected();

    fPixelList->RemoveEntries(0, GetEvent()->GetNumPixels());

    DisplayPixel(lastsel);
}

// --------------------------------------------------------------------------
//
//    ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2)
//
// Processes information from all GUI items.
// Selecting an item usually generates an event with 4 parameters.
// The first two are packed into msg (first and second bytes).
// The other two are parm1 and parm2.
//
Bool_t MGFadcDisp::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2) 
{
    switch(GET_MSG(msg))
    {
    case kC_COMMAND:
        switch(GET_SUBMSG(msg))
        {
        case kCM_BUTTON:
            switch (parm1)
            {
            case M_PREVPIXEL:
                DisplayPixel(fPixelList->GetSelected()-1, kFALSE);
                return kTRUE;

            case M_NEXTPIXEL:
                DisplayPixel(fPixelList->GetSelected()+1, kFALSE);
                return kTRUE;
            }
            break;

        case kCM_LISTBOX:
            if (parm1 != M_PIXELLIST)
                break;

            DisplayPixel(fPixelList->GetSelected(), kFALSE);
            return kTRUE;
        }
        break;
    }

    return MGEvtDisplay::ProcessMessage(msg, parm1, parm2);
}
