// -*- c++ -*-
#ifndef TIME_MEASURE_H
#define TIME_MEASURE_H

#include <sys/time.h>
#include <sys/times.h>
#include <fstream>
#include <iostream>

double currTime() {
  timeval tv;
  //timezone tz;
  gettimeofday(&tv, 0);
  return double(tv.tv_sec)+double(tv.tv_usec)/1000000.0;
}

class TimeStamp
{
  tms ts;
public:

  tms &getTms() {return ts;}
  const tms &getTms() const {return ts;}

  void stamp() {times(&ts);}
  TimeStamp() { ts.tms_utime=ts.tms_stime=ts.tms_cutime=ts.tms_cstime=0;}
  TimeStamp(void *) { stamp();}
  
  TimeStamp &operator+=(const TimeStamp &b)
  {
    ts.tms_utime+=b.ts.tms_utime;
    ts.tms_stime+=b.ts.tms_stime;
    ts.tms_cutime+=b.ts.tms_cutime;
    ts.tms_cstime+=b.ts.tms_cstime;
    return *this;
  }
  TimeStamp operator+(const TimeStamp &b) const
  {
    TimeStamp t(*this);
    return t+=b;
  }
  TimeStamp &operator-=(const TimeStamp &b)
  {
    ts.tms_utime-=b.ts.tms_utime;
    ts.tms_stime-=b.ts.tms_stime;
    ts.tms_cutime-=b.ts.tms_cutime;
    ts.tms_cstime-=b.ts.tms_cstime;
    return *this;
  }
  TimeStamp operator-(const TimeStamp &b) const
  {
    TimeStamp t(*this);
    return t-=b;
  }

  TimeStamp Ellapsed() const
  {
    TimeStamp t(NULL);
    return t-*this;
  }
  
  friend std::ostream& operator<<(std::ostream& os,const TimeStamp &t);
  
};

class Timer
{
  TimeStamp start_time;

public: 
  void reset() {start_time.stamp();}
  Timer() {reset();}

  operator TimeStamp ()
  {
    TimeStamp t;
    t.stamp();
    return t-start_time;
  }  
};

inline std::ostream& operator<<(std::ostream& os,const TimeStamp &t)
{
  long cls = sysconf(_SC_CLK_TCK);
  os << "[ u: " << double(t.getTms().tms_utime)/cls <<
    "s, s: " << double(t.getTms().tms_stime)/cls <<
    "s, cu: " << double(t.getTms().tms_cutime)/cls <<
    "s, cs: " << double(t.getTms().tms_cstime)/cls << "s ]";
  return os;
}

#endif //TIME_MEASURE_H
