// just messing with some code at blog
// http://k...content-available-to-author-only...s.com/2012/02/06/exploring-c11-part-1-time/#more-458
#include <iostream>
#include <chrono>
#include <thread>

// used for not yet finished (and for chrono) irrelevant time printouts
#include <mutex>
#include <iomanip>
#include <ctime>


namespace g2
{	
  typedef std::chrono::high_resolution_clock clock;
  typedef std::chrono::microseconds microseconds;
  typedef std::chrono::milliseconds milliseconds;

  clock::time_point now(){return clock::now();}
  
  microseconds intervalUs(const clock::time_point& t1, const clock::time_point& t0)
  {return std::chrono::duration_cast<microseconds>(t1 - t0);}
  
  milliseconds intervalMs(const clock::time_point& t1,const clock::time_point& t0)
  {return std::chrono::duration_cast<milliseconds>(t1 - t0);}


  template<typename Duration>
  void short_sleep(Duration d) // thanks to Anthony Williams for the suggestion of short_sleep
  {                            
    clock::time_point const start=clock::now(), stop=start+d;
    do{
      std::this_thread::yield();
    } while(clock::now()<stop);
  }

  class StopWatch
  {
    clock::time_point start_;
  public:
    StopWatch() : start_(clock::now()){}
    clock::time_point restart()		{ start_ = clock::now(); return start_;}
    microseconds elapsedUs()		{ return intervalUs(now(), start_);}
    milliseconds elapsedMs()		{return intervalMs(now(), start_);}
  };
} // g2

std::mutex io_mutex;
void greeting(const char* message){
  std::lock_guard<std::mutex> lk(io_mutex);
  std::cout<<message<<std::endl;
}



void silly_sleep_ms_original_and_ugly(unsigned int ms)
{
  using std::chrono::high_resolution_clock;
  using std::chrono::milliseconds;
  
  auto t0 = high_resolution_clock::now();
  std::this_thread::sleep_for(milliseconds(ms));
  auto t1 = high_resolution_clock::now();
  milliseconds total_ms = std::chrono::duration_cast<milliseconds>(t1 - t0);
 
  std::cout <<"this_thread_sleep (" << ms <<") milliseconds: "
            << total_ms.count() << "ms\n";
}

void silly_sleep_ms(unsigned int ms)
{
  using namespace g2;
  StopWatch measure;
  std::this_thread::sleep_for(milliseconds(ms));
  std::cout <<" 2this_thread_sleep (" << ms <<") milliseconds: " 
    << measure.elapsedMs().count() << "ms\n";
}


void silly_sleep_us(unsigned int us)
{
  using namespace g2;
  StopWatch measure;
  std::this_thread::sleep_for(microseconds(us));
  std::cout <<" this_thread_sleep (" << us <<") microseconds: " 
    << measure.elapsedUs().count() << "us\n";
}

void silly_improved_short_sleep_us(unsigned int us)
{
  using namespace g2;
  StopWatch measure;
  short_sleep(microseconds(us));
  auto elapsed_us = measure.elapsedUs().count();

  std::cout <<"SHORT this_thread_sleep (" << us <<") microseconds: " 
    << elapsed_us << "us\n";
}


int main()
{
  silly_sleep_ms_original_and_ugly(50);
  silly_sleep_ms_original_and_ugly(50);
  silly_sleep_ms_original_and_ugly(50);
  silly_sleep_ms(50);
  silly_sleep_ms(50);
  silly_sleep_ms(50);
  silly_sleep_us(50);
  silly_sleep_us(50);
  silly_sleep_us(50);
  silly_improved_short_sleep_us(50);
  silly_improved_short_sleep_us(50);
  silly_improved_short_sleep_us(50);
  {
    g2::StopWatch watch;
    std::this_thread::sleep_for(g2::microseconds(50));
    std::cout << "sleep(50us) took: " << watch.elapsedUs().count() << " us" << std::endl;
    
    g2::clock::time_point t0 = g2::now();
    g2::short_sleep(g2::microseconds(50));
    g2::clock::time_point t1 = g2::now();
    std::cout << "intervalUs check - short_sleep(50us) took: " << g2::intervalUs(t1, t0).count() << " us" << std::endl;
  }

  g2::StopWatch watch;
  g2::clock::time_point t0 =g2:: clock::now();
  std::this_thread::sleep_for(g2::microseconds(50));
  std::cout << g2::intervalUs(g2::now(), t0).count() << "us\n";
  std::cout << watch.elapsedUs().count();
  std::time_t t = std::time(NULL);
  std::cout << "UTC:   " << std::put_time(std::gmtime(&t), "%c %Z" )<< '\n'; 
  std::cout << "local: " << std::put_time(std::localtime(&t), "%c %Z") << '\n';


  return 0;
}

