/* ======================================================================== *\
!
! *
! * 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): Harald Kornmayer 1/2001 (harald@mppmu.mpg.de)
!   Author(s): Thomas Bretz  12/2000 (tbretz@uni-sw.gwdg.de)
!
!   Copyright: MAGIC Software Development, 2000-2001
!
!
\* ======================================================================== */

#include "MBrowser.h"

#include <TSystem.h>        // gSystem

#include <TGTab.h>          // TGTab
#include <TGMenu.h>         // TGPopupMenu
#include <TGButton.h>       // TGTextButton
#include <TGMsgBox.h>       // TGMsgBox
#include <TGListBox.h>      // TGListBox
#include <TGComboBox.h>     // TGComboBox
#include <TGFSContainer.h>  // TGFileContainer

#include <TG3DLine.h>       // TGHorizontal3DLine
                            // use TGSplitter.h for root<3.00

#include <sys/stat.h>       // S_ISDIR

#include <iostream.h>

ClassImp(MBrowser);

enum {
    M_FILE_CLOSE          = 0x1000,
    M_PBUTTON_CDIR_UP     = 0x1001,
    M_PBUTTON_LIST_MODE   = 0x1002,
    M_PBUTTON_DETAIL_MODE = 0x1003,
    M_DIRBOX              = 0x1004
};

void MBrowser::CreateMenuBar()
{
    //
    //  crate the menu bar
    //
    TGPopupMenu *filemenu = new TGPopupMenu(gClient->GetRoot());
    filemenu->AddEntry("Close", M_FILE_CLOSE);
    //filemenu->Associate(this);
    fList->Add(filemenu);

    //
    //  the button messages are handled by main frame (this)
    //
    TGLayoutHints *laymenubar  = new TGLayoutHints(kLHintsTop|kLHintsLeft|kLHintsExpandX, 2, 2, 2, 2);
    TGLayoutHints *laymenuitem = new TGLayoutHints(kLHintsTop|kLHintsLeft, 0, 4, 0, 0);

    fList->Add(laymenubar);
    fList->Add(laymenuitem);

    TGMenuBar *menubar = new TGMenuBar(this, 1, 1, kHorizontalFrame);
    menubar->AddPopup("File", filemenu, laymenuitem);
    AddFrame(menubar, laymenubar);
    fList->Add(menubar);
}

void MBrowser::CreateUpperFrame(TGCompositeFrame *frametop)
{

    //
    // *********** Create Contents of frame top (upper part) **********
    //
    fTop1 = new TGHorizontalFrame(frametop, 300, 100);
    fTop2 = new TGHorizontalFrame(frametop, 300, 100);
    fTop3 = new TGHorizontalFrame(frametop, 300, 100);

    frametop->AddFrame(fTop1);
    frametop->AddFrame(fTop2);
    frametop->AddFrame(fTop3);

    fList->Add(fTop1);
    fList->Add(fTop2);
    fList->Add(fTop3);
}

void MBrowser::CreateDirListMenu(TGCompositeFrame *frame)
{
    //
    // Create Dir-Listbox and buttons in first frame
    //
    fDir = new TGComboBox(frame, M_DIRBOX);
    fDir->Resize(350, 20);

    //
    // Get the three picturs from the system (must be deleted by FreePicture)
    //
    fPic1 = fClient->GetPicture("tb_uplevel.xpm");
    fPic2 = fClient->GetPicture("tb_list.xpm");
    fPic3 = fClient->GetPicture("tb_details.xpm");

    //
    // Create the corresponding picture buttons
    //
    fCdup     = new TGPictureButton(frame, fPic1, M_PBUTTON_CDIR_UP);
    fListMode = new TGPictureButton(frame, fPic2, M_PBUTTON_LIST_MODE);
    fDetail   = new TGPictureButton(frame, fPic3, M_PBUTTON_DETAIL_MODE);

    //
    // setup the buttons
    //
    fCdup    ->SetToolTipText("One Level up!");
    fListMode->SetToolTipText("List Mode");
    fDetail  ->SetToolTipText("Details Mode");

    fListMode->SetState(kButtonUp);
    fDetail  ->SetState(kButtonEngaged);

    fListMode->AllowStayDown(kTRUE);
    fDetail  ->AllowStayDown(kTRUE);

    //
    // send messages to 'this' object
    //
    fDir     ->Associate(this);
    fCdup    ->Associate(this);
    fDetail  ->Associate(this);
    fListMode->Associate(this);

    //
    // Add to list for 'automatic' deletion
    //
    fList->Add(fDir);
    fList->Add(fCdup);
    fList->Add(fListMode);
    fList->Add(fDetail);

    //
    // Layout Dir-Listbox and buttons in one row (frame)
    //
    //  - layout:
    //    alignment: top, left
    //    padding:   5, 5, 5, 5
    //
    TGLayoutHints *layout = new TGLayoutHints(kLHintsNormal, 5, 5, 5, 5);
    fList->Add(layout);

    frame->AddFrame(fDir,      layout);
    frame->AddFrame(fCdup,     layout);
    frame->AddFrame(fListMode, layout);
    frame->AddFrame(fDetail,   layout);
}

void MBrowser::CreateDirListBox(TGCompositeFrame *frame)
{
    //
    // Create file viewer (browser)
    //
    fFileView = new TGListView(frame, 540, 380);
    fList->Add(fFileView);

    TGViewPort *port = fFileView->GetViewPort();
    port->SetBackgroundColor(fgWhitePixel);

    fFileCont = new TGFileContainer(port, 100, 100, kVerticalFrame, fgWhitePixel);
    fList->Add(fFileCont);

    fFileView->SetContainer(fFileCont);
    fFileView->SetViewMode(kLVDetails);

    fFileCont->SetFilter("*");
    fFileCont->Associate(this);
    fFileCont->Sort(kSortByName);

    TGLayoutHints *layview = new TGLayoutHints(kLHintsTop|kLHintsExpandX|kLHintsExpandY, 5, 5, 5, 5);
    fList->Add(layview);

    frame->AddFrame(fFileView, layview);
}

void MBrowser::CreateTab1()
{
    TGCompositeFrame *frame = CreateNewTab("Input File");

    //
    // Create three frames for the first tab
    //
    TGCompositeFrame *tab1  = new TGCompositeFrame(frame, 100, 100, kHorizontalFrame);
    TGCompositeFrame *tab1a = new TGCompositeFrame(frame, 100, 100, kHorizontalFrame);
    TGCompositeFrame *tab1b = new TGCompositeFrame(frame, 100, 100, kVerticalFrame);

    TGLayoutHints *laytab1b = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY, 5, 5, 5, 5);
    TGLayoutHints *laytab1  = new TGLayoutHints(kLHintsExpandX, 5, 5, 5, 5);

    fList->Add(laytab1b);
    fList->Add(laytab1);

    frame->AddFrame(tab1a);
    frame->AddFrame(tab1b, laytab1b);
    frame->AddFrame(tab1,  laytab1);

    fList->Add(tab1);
    fList->Add(tab1a);
    fList->Add(tab1b);

    CreateDirListMenu(tab1a);
    CreateDirListBox(tab1b);
}

TGCompositeFrame *MBrowser::CreateNewTab(const char *name)
{
    return fTabs->AddTab(name);
}

void MBrowser::CreateLowerFrame(TGCompositeFrame *framelow)
{
    //
    // *********** Create Contents of frame low (downer part) **********
    //

    //
    // ----- Create Object holding the Tabs -----
    //
    fTabs = new TGTab(framelow, 400, 400);
    fList->Add(fTabs);

    TGLayoutHints *laytabs = new TGLayoutHints(kLHintsBottom|kLHintsExpandX|kLHintsExpandY, 5, 5, 5, 5);
    fList->Add(laytabs);

    framelow->AddFrame(fTabs, laytabs);

    //
    // --- Create the first tab of the tabs ---
    //
    CreateTab1();
}

MBrowser::MBrowser(const TGWindow *main, const TGWindow *p,
                     const UInt_t w, const UInt_t h)
: TGTransientFrame(p?p:gClient->GetRoot(),
                   main?main:gClient->GetRoot(), w, h)
{
    fInputFile[0] = '\0';

    fList = new TList;
    fList->SetOwner();

    CreateMenuBar();

    TGLayoutHints *laylinesep  = new TGLayoutHints(kLHintsTop|kLHintsExpandX);
    fList->Add(laylinesep);

    TGHorizontal3DLine *linesep = new TGHorizontal3DLine(this);
    fList->Add(linesep);
    AddFrame(linesep, laylinesep);


    //
    // ---- Create the top window with a lot of buttons ----
    //
    TGCompositeFrame *frametop = new TGCompositeFrame(this, 300, 100, kVerticalFrame);
    fList->Add(frametop);
    AddFrame(frametop);

    linesep = new TGHorizontal3DLine(this);
    fList->Add(linesep);
    AddFrame(linesep, laylinesep);

    //
    // ---- Create the low window with a tabs in it ----
    //
    TGLayoutHints *layframelow = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY);
    fList->Add(layframelow);

    TGCompositeFrame *framelow = new TGCompositeFrame(this, 300, 100, kHorizontalFrame);
    fList->Add(framelow);

    AddFrame(framelow, layframelow);

    CreateUpperFrame(frametop);
    CreateLowerFrame(framelow);

    //
    //   Map the window, set up the layout, etc.
    //
    ChangeDir();
    SetWMSizeHints(400, 350, 1000, 1000, 10, 10);      // set the smallest and biggest size of the Main frame
}


// ======================================================================
// ======================================================================

MBrowser::~MBrowser()
{
    fClient->FreePicture(fPic1);
    fClient->FreePicture(fPic2);
    fClient->FreePicture(fPic3);

    delete fList;
} 

// ======================================================================
// ======================================================================

void MBrowser::CloseWindow()
{
   // Got close message for this MainFrame. Calls parent CloseWindow()
   // (which destroys the window) and terminate the application.
   // The close message is generated by the window manager when its close
   // window menu item is selected.

    delete this;
}


// ======================================================================
// ======================================================================

Bool_t MBrowser::InputFileSelected() 
{
    //
    // Checks if there is a selected input root file
    //
    return fInputFile[0]!='\0';
}


// ======================================================================
// ======================================================================

void MBrowser::DisplError(const char *txt)
{
    Int_t retval;
    new TGMsgBox(fClient->GetRoot(), this, "Error!", txt,
                 kMBIconExclamation, 4, &retval);
}

void MBrowser::DisplWarning(const char *txt)
{
    Int_t retval;
    new TGMsgBox(fClient->GetRoot(), this, "Warning!", txt,
                 kMBIconExclamation, 4, &retval);
}

void MBrowser::DisplInfo(const char *txt)
{
    Int_t retval;
    new TGMsgBox(fClient->GetRoot(), this, "Information!", txt,
                 kMBIconExclamation, 4, &retval);
}

void MBrowser::ChangeDir(const char *txt)
{
    fFileCont->ChangeDirectory(txt?txt:gSystem->WorkingDirectory());

    const char  *dir = fFileCont->GetDirectory();
    //    const UInt_t num = fDir->GetSelected()+1;

    //
    // FIXME: This is a big workaround!
    //
    fDir->InsertEntry(dir, -1/*num*/, -1);
    fDir->Select(-1/*num*/);
}

Bool_t MBrowser::ProcessMessage(Long_t msg, Long_t parm1, Long_t)
{     
  // Process events generated by the buttons in the frame.
  
  switch (GET_MSG(msg))
  {
  case kC_COMMAND:
      switch (GET_SUBMSG(msg))
      {
      case kCM_BUTTON:

          switch (parm1)
          {
          case M_PBUTTON_CDIR_UP :
              //
	      //  goto the parent directory
              //
              ChangeDir("..");
	      return kTRUE;
	    
	    case M_PBUTTON_LIST_MODE:
	      fFileView->SetViewMode(kLVList);
              fDetail->SetState(kButtonUp) ;
              return kTRUE;
	      
          case M_PBUTTON_DETAIL_MODE:
              fFileView->SetViewMode(kLVDetails);
              fListMode->SetState(kButtonUp);
              return kTRUE;
          }
          return kTRUE;

      case kCM_COMBOBOX:
          //
          // FIXME: Don't add the new entry to the list!
          // But to do this we need the number of entries in the list.
          //
          if (parm1 == M_DIRBOX)
              ChangeDir(((TGTextLBEntry*)fDir->GetSelectedEntry())->GetText()->GetString());
          return kTRUE;

	case kCM_MENU:
	  if (parm1==M_FILE_CLOSE)
              CloseWindow();
          return kTRUE;
      }
      return kTRUE;
      
  case kC_CONTAINER:
      switch (GET_SUBMSG(msg))
      {

          //      case kCT_ITEMCLICK:
          // 	printf ("itemclick\n");
          //      break;

      case kCT_ITEMDBLCLICK:
          //
          //  process the double click in the file view container
          //

          if (parm1 != kButton1)
              return kTRUE;

          if (fFileCont->NumSelected() != 1 )
              return kTRUE;

          //
          //  one file selected
          //
          void *dummy = NULL;
          const TGFileItem *item = (TGFileItem *)fFileCont->GetNextSelected(&dummy);

          const char *str = item->GetItemName()->GetString();

          //
          // if the user choose a directory
          // change to this directory
          //
          if (S_ISDIR(item->GetType())) 
          {
              ChangeDir(str);
              return kTRUE;
          }

          //
          // file is no directory, is a file
          //    determine the file type by extensions
          //
          const char *extension=strrchr(str, '.');

          if (!extension)
              return kTRUE;

          const char *dir = fFileCont->GetDirectory();

          if (!strcasecmp(extension, ".ps")) // postscript file
          {
              char *cmd = new char[strlen(dir)+strlen(str)+40];
              sprintf(cmd, "gv %s/%s &", dir, str);
              gSystem->Exec(cmd);
              delete cmd;
              return kTRUE;
          }

          if (!strcasecmp(extension, ".root"))
          {
              sprintf(fInputFile, "%s/%s", dir, str);
              return kTRUE;
          }
          return kTRUE;
      }
  }
  return kTRUE;
} 
