
// File:	OSD_Timer.cxx
// Created:	Fri Dec 4 15:02:28 1992
// Author:	Didier PIFFAULT , Mireille MERCIEN
//		<model@sdsun2>
//
// Update: J.P. TIRAULT Sep,1993
//         On heterogeneous platforms we need to use the 
//         system call gettimeofday. This function is portable and give us
//         elapsed time in seconds and microseconds.
//          

#ifndef WNT

//---------- No Windows NT Systems ----------------------------------

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <OSD_Timer.ixx>
#include <Standard_Address.hxx>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif

static struct timezone *tz=(struct timezone*) malloc(sizeof(struct timezone));

//=======================================================================
//function : OSD_Timer
//purpose  : 
//=======================================================================

OSD_Timer::OSD_Timer()
{
  RefToInitialTimeB = (Standard_Address)new timeval;
  RefToCurrentTimeB = (Standard_Address)new timeval;
  TimeCumulInt      = 0;
  MicroCumulInt     = 0;
}

//=======================================================================
//function : Compute
//purpose  : Calcul les Heures,Minutes,Secondes,Millisecondes a partir
//           de deux variables input qui sont:
//           TimeCumulInt : Contient un periode de temps exprimee en secondes,
//           MicroCumulInt: Contient cette meme periode exprimee en 
//                       microsecondes.
//=======================================================================

static void Compute (Standard_Integer  TimeCumulInt,
		     Standard_Integer  MicroCumulInt,
		     Standard_Integer& heure,
		     Standard_Integer& minut,
		     Standard_Real&    second) {

  Standard_Integer diffr;
  diffr =  TimeCumulInt ;
  heure =  diffr/3600   ;
  diffr -= heure * 3600 ;
  minut =  diffr/60     ;
  diffr -= minut * 60   ;
  second = (Standard_Real) diffr ;
  second += MicroCumulInt / 1000000.;  
}

//=======================================================================
//function : Destroy
//purpose  : 
//=======================================================================

void OSD_Timer :: Destroy () {

 delete (timeval*) RefToCurrentTimeB;
 delete (timeval*) RefToInitialTimeB;

}

//=======================================================================
//function : Reset
//purpose  : 
//=======================================================================

void OSD_Timer::Reset ()
{
  TimeCumulInt = 0;
  MicroCumulInt= 0;
  OSD_Chronometer::Reset();
}

//=======================================================================
//function : Show
//purpose  : 
//=======================================================================

void OSD_Timer::Show ()
{
  Standard_Boolean StopSav=Stopped;
  
  if (!StopSav) Stop();

  Standard_Integer heure,minut;
  Standard_Real    second;
  Compute (TimeCumulInt,MicroCumulInt,heure,minut,second);

  cout << "Elapsed time: "<<heure<< " Hours ";
  if(minut < 10) cout<<"  "<<minut;
  else           cout<<" " <<minut;
  cout << " Minutes ";  
  if(second < 10) cout<<"  "<<second;
  else            cout<<" " <<second;
  cout << " Seconds " << endl;

  if (!StopSav) Start();
  
  OSD_Chronometer::Show();
}


//=======================================================================
//function : Show
//purpose  : 
//=======================================================================

void OSD_Timer::Show (Standard_Real&    seconds,
                      Standard_Integer& minutes,
                      Standard_Integer& hours,
                      Standard_Real&    CPUtime) 
{
  Standard_Boolean StopSav=Stopped;
  
  if (!StopSav) Stop();

  Compute (TimeCumulInt,MicroCumulInt,hours,minutes,seconds);

  if (!StopSav) Start();
  
  OSD_Chronometer::Show(CPUtime);
}


//=======================================================================
//function : Show
//purpose  : 
//=======================================================================

void OSD_Timer::Show (Standard_OStream& os)
{
  Standard_Boolean StopSav=Stopped;
  
  if (!StopSav) Stop();
  
  Standard_Integer heure,minut;
  Standard_Real    second;
  Compute (TimeCumulInt,MicroCumulInt,heure,minut,second);

  os << "Elapsed time: "<< heure << " Hours ";
  if ( minut < 10 ) os << "  "<< minut;
  else             os  << " " << minut;
  os << " Minutes ";
  if ( second < 10 ) os << "  " << second;
  else               os << " "  << second;
  os << " Seconds " << endl;
  
  if (!StopSav) Start();
  
  OSD_Chronometer::Show(os);
}

//=======================================================================
//function : Stop
//purpose  : 
//=======================================================================

void OSD_Timer::Stop ()
{
  if (!Stopped) {
    OSD_Chronometer::Stop();
    gettimeofday((timeval*)RefToCurrentTimeB,tz);

//    cout << " stop : " << (int) (((timeval*)RefToCurrentTimeB)->tv_sec) << " seconds " << endl;   
   
    TimeCumulInt += (int) (((timeval*)RefToCurrentTimeB)->tv_sec -
	   	          ((timeval*)RefToInitialTimeB)->tv_sec);

//    cout << " stop, cumul : " <<  TimeCumulInt << " seconds " << endl;   


    MicroCumulInt += (int) (((timeval*)RefToCurrentTimeB)->tv_usec -
		           ((timeval*)RefToInitialTimeB)->tv_usec);
    }
  else cout << "WARNING: OSD_Timer already Stopped !\n";
}

//=======================================================================
//function : Start
//purpose  : 
//=======================================================================

void OSD_Timer::Start()
{
  if (Stopped) {
    gettimeofday((timeval*)RefToInitialTimeB,tz);

//    cout << " start : " <<(int) (((timeval*)RefToInitialTimeB)->tv_sec) << " seconds " << endl;

    OSD_Chronometer::Start();
  }
  else cout << "WARNING: OSD_Timer already Running !\n";
}

#else

//------------------------------------------------------------------------
//-------------------  Windows NT sources for OSD_Timer ------------------
//------------------------------------------------------------------------

#define STRICT
#include <windows.h>

#include <OSD_Timer.ixx>

__int64 __fastcall FileTimeToQuadWord ( PFILETIME          );
void    __fastcall QuadWordToFileTime ( __int64, PFILETIME );

static void __fastcall _compute (
                        Standard_Real, Standard_Integer&, Standard_Integer&, Standard_Real&
                       );

OSD_Timer :: OSD_Timer () {

 RefToInitialTimeB = ( Standard_Address )new FILETIME;
 RefToCurrentTimeB = ( Standard_Address )new FILETIME;

 Reset ();

}  // end constructor

void OSD_Timer :: Destroy () {

 delete RefToCurrentTimeB;
 delete RefToInitialTimeB;

}  // end OSD_Timer :: Destroy

void OSD_Timer :: Reset () {

 TimeCumul  = 0;
 MicroCumul = 0;

 OSD_Chronometer :: Reset ();

}  // end OSD_Timer :: Reset

void OSD_Timer :: Show () {

Standard_Boolean stopSav = Stopped;

if ( !stopSav ) Stop ();

 Standard_Integer hh, mm;
 Standard_Real    ss;

 _compute ( TimeCumul, hh, mm, ss );

 cout << "Elapsed time: " << setw ( 2 ) << hh << " Hour(s)"
                          << setw ( 2 ) << mm << " Minute(s) "
                          << ss << " Second(s)" << endl << flush;

if ( !stopSav ) Start ();

OSD_Chronometer :: Show ();

}  // end OSD_Timer :: Show ( 1 )

void OSD_Timer :: Show ( Standard_OStream& os ) {

Standard_Boolean stopSav = Stopped;

if ( !stopSav ) Stop ();

 Standard_Integer hh, mm;
 Standard_Real    ss;

 _compute ( TimeCumul, hh, mm, ss );

 os << "Elapsed time: " << setw ( 2 ) << hh << " Hour(s)"
                        << setw ( 2 ) << mm << " Minute(s) "
                        << ss << " Second(s)" << endl << flush;

if ( !stopSav ) Start ();

OSD_Chronometer :: Show ( os );

}  // end OSD_Timer :: Show ( 2 )

void OSD_Timer :: Show (
                   Standard_Real&    seconds,Standard_Integer& minutes,
                   Standard_Integer& hours,  Standard_Real&    CPUtime
                  ) {

Standard_Boolean stopSav = Stopped;

if ( !stopSav ) Stop ();

 Standard_Integer hh, mm;
 Standard_Real    ss;

 _compute ( TimeCumul, hh, mm, ss );

 seconds = ss;
 minutes = mm;
 hours   = hh;

if ( !stopSav ) Start ();

OSD_Chronometer :: Show ( CPUtime );

}  // end  OSD_Timer :: Show ( 3 )

void OSD_Timer :: Stop () {

 if ( !Stopped ) {
 
  OSD_Chronometer :: Stop ();

  __int64    qwInitialTime;
  __int64    qwCurrentTime;
  SYSTEMTIME st;

  GetSystemTime ( &st );
  SystemTimeToFileTime (  &st, ( LPFILETIME )RefToCurrentTimeB  );
  qwCurrentTime = FileTimeToQuadWord (  ( LPFILETIME )RefToCurrentTimeB  );
  qwInitialTime = FileTimeToQuadWord (  ( LPFILETIME )RefToInitialTimeB  );

  TimeCumul += (  ( Standard_Real )qwCurrentTime - ( Standard_Real )qwInitialTime  );
 
 } else

  cerr << "WARNING: OSD_Timer already stopped !\n" << flush;

}  // end OSD_Timer :: Stop

void OSD_Timer :: Start () {

 if ( Stopped ) {
 
  SYSTEMTIME st;

  GetSystemTime ( &st );
  SystemTimeToFileTime (  &st, ( LPFILETIME )RefToInitialTimeB  );

  OSD_Chronometer :: Start ();
 
 } else

  cerr << "WARNING: OSD_Timer already started !\n" << flush;

}  // end OSD_Timer :: Start

static void __fastcall _compute (
                        Standard_Real total,
                        Standard_Integer& hour, Standard_Integer& min, Standard_Real& sec
                       ) {

 FILETIME   ftTotal;
 SYSTEMTIME stTotal;
 __int64    qwTotal = ( __int64 )total;

 QuadWordToFileTime   ( qwTotal,  &ftTotal );
 FileTimeToSystemTime ( &ftTotal, &stTotal );

 hour = stTotal.wHour;
 min  = stTotal.wMinute;
 sec  = ( Standard_Real )stTotal.wSecond + ( Standard_Real )stTotal.wMilliseconds / ( Standard_Real )1000.;

}  // end _compute

#endif
