#include "TRint_ap.hh"

#include "TROOT.h"
#include "TVirtualX.h"
#include "TStopwatch.h"
#include "TSystem.h"
#include "TEnv.h"
#include "TException.h"
#include "TInterpreter.h"
#include "TTabCom.h"
#include "TError.h"
#include <stdlib.h>

#include "Getline.h"

#ifdef R__UNIX
#include <signal.h>
#endif

R__EXTERN void *gMmallocDesc; //is used and set in TMapFile and TClass

//----- Interrupt signal handler -----------------------------------------------
//______________________________________________________________________________
class TInterruptHandler : public TSignalHandler {
public:
   TInterruptHandler() : TSignalHandler(kSigInterrupt, kFALSE) { }
   Bool_t  Notify();
};

//______________________________________________________________________________
Bool_t TInterruptHandler::Notify()
{
   // TRint_ap interrupt handler.

   if (fDelay) {
      fDelay++;
      return kTRUE;
   }

   // make sure we use the sbrk heap (in case of mapped files)
   gMmallocDesc = 0;

   if (!gCint->GetSecurityError())
      gCint->GenericError("\n *** Break *** keyboard interrupt");
   else {
      Break("TInterruptHandler::Notify", "keyboard interrupt");
      if (TROOT::Initialized()) {
         Getlinem(kInit, "Root > ");
         gCint->RewindDictionary();
#ifndef WIN32
         Throw(GetSignal());
#endif
      }
   }
   return kTRUE;
}

//----- Terminal Input file handler --------------------------------------------
//______________________________________________________________________________
class TTermInputHandler : public TFileHandler {
public:
   TTermInputHandler(Int_t fd) : TFileHandler(fd, 1) { }
   Bool_t Notify();
   Bool_t ReadNotify() { return Notify(); }
};

//______________________________________________________________________________
Bool_t TTermInputHandler::Notify()
{
   // Notify implementation.  Call the application interupt handler.

   return gApplication->HandleTermInput();
}
//----- TRint_ap ---------------------------------------------------------------
//______________________________________________________________________________
ClassImp(TRint_ap)
//______________________________________________________________________________
TRint_ap::TRint_ap(const char *appClassName, Int_t *argc, char **argv,
		   void *options, Int_t numOptions, Bool_t noLogo)
: TRint(appClassName, argc, argv, options, numOptions, kTRUE)
{

   fNcmd          = 0;
   fDefaultPrompt = "aproot [%d] ";
   fInterrupt     = kFALSE;

   if (!noLogo && !NoLogoOpt()) {
      Bool_t lite = (Bool_t) gEnv->GetValue("Rint.WelcomeLite", 0);
      PrintLogo(lite);
   }

   // Install interrupt and terminal input handlers
   TInterruptHandler *ih = new TInterruptHandler();
   ih->Add();
   SetSignalHandler(ih);

   // Handle stdin events
   fInputHandler = new TTermInputHandler(0);
   fInputHandler->Add();

}
//______________________________________________________________________________
TRint_ap::~TRint_ap(){
   delete gTabCom;
   gTabCom = 0;
   Gl_in_key = 0;
   Gl_beep_hook = 0;
   fInputHandler->Remove();
   delete fInputHandler;
}
//______________________________________________________________________________
void TRint_ap::PrintLogo(Bool_t lite){
   const char *root_version = gROOT->GetVersion();
   static const char *months[] = {"January","February","March","April","May",
				  "June","July","August","September","October",
				  "November","December"};
   Int_t idatqq = gROOT->GetVersionDate();
   Int_t iday   = idatqq%100;
   Int_t imonth = (idatqq/100)%100;
   Int_t iyear  = (idatqq/10000);
   char *version_date = Form("%d %s %4d",iday,months[imonth-1],iyear);
   
   Printf("  *******************************************");
   Printf("  *                                         *");
   Printf("  *      W E L C O M E  to  A P R O O T     *");
   Printf("  *     (Anapaw-like command interpreter)   *");
   Printf("  *                                         *");
   Printf("  * Root Version%10s%17s *", root_version, version_date);
   Printf("  *                                         *");
   Printf("  *  You are welcome to visit our Web site  *");
   Printf("  *          http://root.cern.ch            *");
   Printf("  *                                         *");
   Printf("  *******************************************\n");
}

//_____________________________________________________________________________________________
Bool_t TRint_ap::HandleTermInput()
{
   // Handle input coming from terminal.

   static TStopwatch timer;
   const char *line;

   if ((line = Getlinem(kOneChar, 0))) {
      if (line[0] == 0 && Gl_eof())
         Terminate(0);

      gVirtualX->SetKeyAutoRepeat(kTRUE);

      Gl_histadd(line);

      TString sline = line;

      // strip off '\n' and leading and trailing blanks
      sline = sline.Chop();
      sline = sline.Strip(TString::kBoth);
      ReturnPressed((char*)sline.Data());

      fInterrupt = kFALSE;

      if (!gCint->GetMore() && !sline.IsNull()) fNcmd++;

      // prevent recursive calling of this input handler
      fInputHandler->DeActivate();

      if (gROOT->Timer()) timer.Start();

      Bool_t added = kFALSE;

      // This is needed when working with remote sessions
      SetBit(kProcessRemotely);

#ifdef R__EH
      try {
#endif
         TRY {
            if (!sline.IsNull())
               LineProcessed(sline);
// modified for anapaw-like Rint
//               ProcessLine(sline);
	       anapaw.ProcessLine(sline);
         } CATCH(excode) {
            // enable again input handler
            fInputHandler->Activate();
            added = kTRUE;
            Throw(excode);
         } ENDTRY;
#ifdef R__EH
      }
      // handle every exception
      catch (...) {
         // enable again intput handler
         if (!added) fInputHandler->Activate();
         throw;
      }
#endif

      if (gROOT->Timer()) timer.Print("u");

      // enable again intput handler
      fInputHandler->Activate();

      if (!sline.BeginsWith(".reset"))
         gCint->EndOfLineAction();

      gTabCom->ClearAll();
      Getlinem(kInit, GetPrompt());
   }
   return kTRUE;
}
//______________________________________________________________________________
char *TRint_ap::GetPrompt()
{
   // Get prompt from interpreter. Either "root [n]" or "end with '}'".

   char *s = gCint->GetPrompt();
   if (s[0])
      strlcpy(fPrompt, s, sizeof(fPrompt));
   else
      snprintf(fPrompt, sizeof(fPrompt), fDefaultPrompt.Data(), fNcmd);

   return fPrompt;
}
//______________________________________________________________________________
