/* sdsl - succinct data structures library
    Copyright (C) 2008 Simon Gog 

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses/ .
*/
#include "sdsl/testutils.hpp"
#include <cxxabi.h>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <unistd.h> // for get_file_size 
#include <sys/types.h> // for get_file_size
#include <sys/stat.h>  // for get_file_size

namespace sdsl{

timeval stop_watch::m_first_t = {0,0};
rusage stop_watch::m_first_r = {{0,0},{0,0}};

void stop_watch::start(){
	gettimeofday(&m_timeOfDay1, 0);
	getrusage(RUSAGE_SELF, &m_ruse1);
}

void stop_watch::stop(){
	getrusage(RUSAGE_SELF, &m_ruse2);
	gettimeofday(&m_timeOfDay2, 0);
}

double stop_watch::get_user_time(){
	timeval t1, t2;
	t1 = m_ruse1.ru_utime;
	t2 = m_ruse2.ru_utime;
	return ((double)(t2.tv_sec*1000000 + t2.tv_usec - (t1.tv_sec*1000000 + t1.tv_usec )))/1000.0;
}

double stop_watch::get_sys_time(){
	timeval t1, t2;
	t1 = m_ruse1.ru_stime;
	t2 = m_ruse2.ru_stime;
	return ((double)(t2.tv_sec*1000000 + t2.tv_usec - (t1.tv_sec*1000000 + t1.tv_usec )))/1000.0;
}

double stop_watch::get_real_time(){
	double result = ((double)((m_timeOfDay2.tv_sec*1000000 + m_timeOfDay2.tv_usec)-(m_timeOfDay1.tv_sec*1000000 + m_timeOfDay1.tv_usec)))/1000.0;
	if( result < get_sys_time() + get_user_time() )
		return get_sys_time()+get_user_time();
	return result;
}

long long stop_watch::get_abs_real_time(){
	long long result = (((m_timeOfDay2.tv_sec*1000000 + m_timeOfDay2.tv_usec - (m_first_t.tv_sec*1000000 + m_first_t.tv_usec) )))/1000;
	return result;
}

long long stop_watch::get_abs_user_time(){
	timeval t1, t2;
	t1 = m_first_r.ru_utime;
	t2 = m_ruse2.ru_utime;
	return (t2.tv_sec*1000000 + t2.tv_usec - (t1.tv_sec*1000000 + t1.tv_usec ))/1000;
}


long long stop_watch::get_abs_sys_time(){
	timeval t1, t2;
	t1 = m_first_r.ru_stime;
	t2 = m_ruse2.ru_stime;
	return (t2.tv_sec*1000000 + t2.tv_usec - (t1.tv_sec*1000000 + t1.tv_usec ))/1000;
}

long long stop_watch::get_abs_page_faults(){
	return m_ruse2.ru_majflt - m_first_r.ru_majflt; // does not work on my platform
}

void write_R_output(std::string data_structure, std::string action, std::string state, uint64_t times, uint64_t check){
//#ifndef NDEBUG  	
#ifdef WRITE_R_OUTPUT	
	stop_watch _sw;
	_sw.stop();
	std::cout << data_structure << "\t" << action << "\t" << state << "\t" 
		      << std::setw(9)<< times << "\t" << std::setw(9) << check << "\t" 
			  << std::setw(9) << _sw.get_abs_real_time() << "\t " 
			  << std::setw(9) << _sw.get_abs_user_time() << "\t" 
			  << std::setw(9) << _sw.get_abs_sys_time() << std::endl;
#endif	
//#endif	
}

std::string clock::get_time_string(){
	time_t rawtime;
	struct tm * timeinfo;
	char buffer[1024];	
	time( &rawtime );
	timeinfo = localtime( &rawtime );

	strftime(buffer, 1024, "%Y-%m-%d-%H%M%S", timeinfo);
	return buffer;
} 

off_t get_file_size(const char *file_name){
	struct stat filestatus;
	stat(file_name, &filestatus);
	return filestatus.st_size;
}

uint64_t file::read_text(const char *file_name, char* &c, bool trunc, uint64_t lim){
	if( c != NULL ){
		delete [] c;
		c = NULL;
	}
	uint64_t n = get_file_size(file_name) + 1; // add one for the 0 byte
	if( trunc and lim+1 < n ){
		n = lim+1;
	}
//std::cerr<<"file has size "<< n <<std::endl;	
	std::ifstream in;
	in.open(file_name);
	if( in ){
		c = new char[n];
		c[n-1] = '\0';
		char *cp = c;
		in.read(cp, n-1);
		if( c[n-2] == 0 )
			return n-1; // last byte was already a null byte
		else
			return n; // added 0 byte
	}
	return 0;
/*	
	std::ifstream in;
	in.open(file_name);
	if( in ){
		const uint64_t BLOCK_SIZE = (1<<20);
		uint64_t n=0, read = 0;
		char buf[BLOCK_SIZE], *cp;
		do{
			in.read(buf, BLOCK_SIZE);
			read = in.gcount();
			n+=read;
		}while( BLOCK_SIZE == read );
		if(n==0)
			return 0;
		c = new char[n+2+BLOCK_SIZE]; //TODO checken warum das nicht gut ist
//		*(c+(n+1)) = 0;
		in.close();
		in.open(file_name);
		if(!in){ 
			delete [] c; 
			c = NULL; 
			return 0;
		}
		cp=c;
		do{
			in.read(cp, BLOCK_SIZE);
			read = in.gcount();
			cp+= read;
		}while( BLOCK_SIZE == read );
		*(c+n) = '\0';
		return n;
	}
	else
		return 0;
*/	
}



} // end of namespace sdsl
