#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 <sys/stat.h>       // S_ISDIR

#include <iostream.h>

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


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)
{

    //
    //    Main window to controll the october test
    //

    //    set non-gui members to starting values

    fInputFile[0] = '\0';

    //
    //    First create the MenuBar.
    //

    //     Layout objects for menue.

    fLayMenuBar  = new TGLayoutHints ( kLHintsTop | kLHintsLeft | kLHintsExpandX, 2, 2, 2, 2 ) ;
    fLayMenuItem = new TGLayoutHints ( kLHintsTop | kLHintsLeft , 0, 4, 0, 0 ) ;

    //  crate the menu bar

    fFileMenu = new TGPopupMenu ( fClient->GetRoot() ) ;
    fFileMenu->AddEntry ("Close", M_FILE_CLOSE ) ;
    fFileMenu->Associate(this) ;

    //  the button messages are handled by main frame (this)

    fMenuBar = new TGMenuBar ( this, 1, 1, kHorizontalFrame ) ;
    fMenuBar->AddPopup("File", fFileMenu, fLayMenuItem ) ;
    AddFrame(fMenuBar, fLayMenuBar ) ;

    //
    //    Create the top window with a lot of buttons
    //
    fFrameTop = new TGCompositeFrame (this, 300,100, kVerticalFrame ) ;

    fTop1 = new TGHorizontalFrame (fFrameTop, 300, 100 ) ;
    fTop2 = new TGHorizontalFrame (fFrameTop, 300, 100 ) ;
    fTop3 = new TGHorizontalFrame (fFrameTop, 300, 100 ) ;

    fFrameTop->AddFrame (fTop1, new TGLayoutHints(kLHintsCenterX, 10, 10, 5, 5) );
    fFrameTop->AddFrame (fTop2, new TGLayoutHints(kLHintsCenterX, 10, 10, 5, 5) );
    fFrameTop->AddFrame (fTop3, new TGLayoutHints(kLHintsCenterX, 10, 10, 5, 5) );
    AddFrame(fFrameTop, new TGLayoutHints (kLHintsTop ) ) ;

    //
    //    Create the low window with a tabs in it
    //
    fFrameLow = new TGCompositeFrame (this, 300,100, kHorizontalFrame ) ;

    fLayTab = new TGLayoutHints ( kLHintsExpandX   , 5, 5, 5, 5 ) ;

    //    create the first tab

    fTab = new TGTab ( fFrameLow, 400, 400 ) ;

    TGCompositeFrame *tf = fTab->AddTab("Input File") ;

    fTabF1  = new TGCompositeFrame (tf, 100, 100, kHorizontalFrame) ;
    fTabF1a = new TGCompositeFrame(tf, 100, 100, kHorizontalFrame);
    fTabF1b = new TGCompositeFrame(tf, 100, 100, kVerticalFrame);

    tf->AddFrame(fTabF1a,  new TGLayoutHints ( kLHintsTop | kLHintsLeft | kLHintsExpandX, 5, 5, 5, 5 ) ) ;
    tf->AddFrame(fTabF1b,  new TGLayoutHints ( kLHintsExpandX | kLHintsExpandY  , 5, 5, 5, 5 ) ) ;

    fDir = new TGComboBox(fTabF1a, M_DIRBOX);
    fDir->Resize(350, 20) ;
    fDir->Associate(this);

    fPicCdup   = fClient->GetPicture("tb_uplevel.xpm");
    fPicList   = fClient->GetPicture("tb_list.xpm");
    fPicDetail = fClient->GetPicture("tb_details.xpm") ;

    fCdup = new TGPictureButton(fTabF1a, fPicCdup, M_PBUTTON_CDIR_UP ) ;
    fCdup->SetToolTipText("One Level up!") ;
    fCdup->Associate(this) ;

    fListMode = new TGPictureButton(fTabF1a, fPicList, M_PBUTTON_LIST_MODE);
    fListMode->SetToolTipText("List Mode") ;
    fListMode->Associate(this);
    fListMode->SetState(kButtonUp);
    fListMode->AllowStayDown(kTRUE);

    fDetail = new TGPictureButton(fTabF1a, fPicDetail, M_PBUTTON_DETAIL_MODE ) ;
    fDetail->SetToolTipText("Details Mode") ;
    fDetail->Associate(this) ;
    fDetail->SetState(kButtonEngaged) ;
    fDetail->AllowStayDown(kTRUE) ;

    fTabF1a->AddFrame(fDir,      new TGLayoutHints(kLHintsTop|kLHintsLeft|kLHintsExpandX, 5, 5, 5, 5)) ;
    fTabF1a->AddFrame(fCdup,     new TGLayoutHints(kLHintsLeft|kLHintsTop, 5, 5, 5, 5));
    fTabF1a->AddFrame(fListMode, new TGLayoutHints(kLHintsLeft|kLHintsTop, 5, 5, 5, 5));
    fTabF1a->AddFrame(fDetail,   new TGLayoutHints(kLHintsLeft|kLHintsTop, 5, 5, 5, 5));

    fFileView = new TGListView(fTabF1b, 540, 380 ) ;
    fFileCont = new TGFileContainer(fFileView->GetViewPort(), 100, 100,
                                    kVerticalFrame, fgWhitePixel) ;

    fFileCont->Associate(this) ;
    fFileView->GetViewPort()->SetBackgroundColor(fgWhitePixel) ;
    fFileView->SetContainer(fFileCont) ;
    fFileCont->SetFilter("*") ;
//    fFileCont->ChangeDirectory(gSystem->WorkingDirectory()) ;
    fFileView->SetViewMode(kLVDetails);
    fFileCont->Sort(kSortByName) ;

    fTabF1b->AddFrame(fFileView, new TGLayoutHints(kLHintsTop | kLHintsExpandX | kLHintsExpandY, 5, 5, 5, 5) ) ;

    tf->AddFrame(fTabF1, fLayTab) ;

    fFrameLow->AddFrame ( fTab, new TGLayoutHints(kLHintsBottom | kLHintsExpandX | kLHintsExpandY, 5, 5, 5, 5) );

    AddFrame(fFrameLow, new TGLayoutHints (kLHintsExpandX|kLHintsExpandY) ) ;

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

    SetWMSizeHints(400, 350, 1000, 1000, 10, 10 ) ;      // set the smallest and biggest size of the Main frame
}


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

MBrowser::~MBrowser()
{
  //delete  fPicCdup, fPicList, fPicDetail; 
    delete fLayTab;
    delete fLayMenuBar;
    delete fLayMenuItem;
    delete fFileView;
    delete fFileCont;
    delete fCdup;
    delete fListMode;
    delete fDetail;
    delete fDir ;
    delete fTabF1b;
    delete fTabF1a;
    delete fTabF1;
    delete fTop3;
    delete fTop2;
    delete fTop1;
    delete fTab;
    delete fFrameTop;
    delete fFrameLow;
    delete fFileMenu;
    delete fMenuBar;

} 


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

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;
} 
