/*
Science and technology promotion license applied.
(c) Zhikai Wang/ www.heteroclinic.net 2013
*/
/* 
Update: 20130512
It was a little bit dis-encouraging to find RaceConditionRandomSeeder.cpp only works for Cygwin environment. After more experiments, we provide remedies.
We need some disambiguation about the term 'race condition'. You can better understand what this program tries to do from the following. You have a highly accurate watch. You want to get the time when you start to watch time. But the time you get is the time you finish the action, if you don't freeze/lock/synchronize the watch.
We make some fixes to make the program work under both Cygwin and Linux. So let it be an observation of what happened than sourcing/digging theoretical or technical documents, that a complete understanding or explanation is not in an immediate sight.
To be implemented otherwise (should) be trivia.
*/
/* Please refer to http://en.cppreference.com/w/c/chrono/clock (20130512)
Begin quote:
Returns the approximate processor time used by the process since the beginning of an implementation-defined era related to the program's execution. To convert result value to seconds divide it by CLOCKS_PER_SEC.
Only the difference between two values returned by different calls to clock is meaningful, as the beginning of the clock era does not have to coincide with the start of the program. clock time may advance faster or slower than the wall clock, depending on the execution resources given to the program by the operating system. For example, if the CPU is shared by other processes, clock time may advance slower than wall clock. On the other hand, if the current process is multithreaded and more than one execution core is available, clock time may advance faster than wall clock. 
End quote
*/
/* 
20130509
We utilize some natural feature of CPU processor and OS.
I am not sure this program will survive all platforms all OSs.
But we are sure whenever there is a race condition, there would be contingency, thus randomness.
It may not perform as good as linear congruential random generator, but it provides a seeding solution.
*/
/*
20130509
How to:
$ g++ -o RaceConditionRandomSeeder.exe RaceConditionRandomSeeder.cpp
$ ./RaceConditionRandomSeeder.exe
2363563459
1909203736
3261123683
3162715086
1930226747
2633383142
822405021
2352027847
2565609614
1664631857
*/
#include <iostream>
#include <cstdlib>
#include <climits>
#include <string>
#include <bitset>
#include <time.h>
#include <ctime>

#include <sstream>
#include <iostream>
#include <sstream>
#include <iomanip>


#include <sys/time.h>

/*BEG test 2 */
/*
// #include <dynamic_bitset> // not in cygwin
//std::bitset<32> bsup(upper_pattern);
class bitsetWrapper {
	const int length;
	void * pt;
public:
	bitsetWrapper (const int  n_length): length(n_length)
	//,pt((void *) new std::bitset<length>())  
	{
		//pt = (void *) new std::bitset<length>();
		//std::bitset<length> bsup; // NO
		
		//const int length = 10; //must be const
		//std::bitset<length> bsup; // OK
	}
};
/*END test 2 */
inline int getWidth (int d) {
	int i = 0; 
	d = abs(d);
	if (0==d)
		return 1;
	while ( d >0 ) {
		d /= 10;
		++i;
	}
	return i;
}
inline const std::string getFormatedIntegerString (int d, int a,char c) {// it is required |a|>=|d|
	std::stringstream ss;
	ss << std::setw(getWidth(a))<<std::setfill(c) <<d;
	return ss.str();
}
inline const std::string getRandomBitsPattern (const unsigned int length ) {
	std::string bits="";
	clock_t start= std::clock();
    clock_t endd = start;
	struct timeval  endtv;
	
	int i = 0;
	int * arr = new int [length];
	gettimeofday(&endtv, NULL);
	while (i<length) {
		endd = std::clock();
		if (start != endd) {
			//std::cout<<start<<"\t"<<endd<<std::endl;
			start = endd;
			gettimeofday(&endtv, NULL);
			//std::cout<<endd%2<<std::endl;
		
			//bits+= getFormatedIntegerString(endd%2,1,' ');
			//arr[i]= endd%2;
#ifdef	 	__CYGWIN__
//std::cout<<"This is Cygwin environment."<<std::endl;
arr[i++] = ((endd)%2);
#else
//std::cout<<"This is Linux or other environments."<<std::endl;
arr[i++] = ((endtv.tv_usec)%2);
#endif			
			
			//++i;
		}
	}
	for (i= 0; i<length; i++) {
		bits+=getFormatedIntegerString(arr[i],1,' ');
	}
	//std::cout<<bits<<std::endl;
	delete [] arr ; arr = NULL;
	return bits;
}
inline const unsigned long getULSeed()  {
	std::string bits = getRandomBitsPattern (32);
	std::bitset<32> bitsbs (bits);
	return bitsbs.to_ulong();
}
int main () {
	//srand((unsigned)time(NULL));
	
	/*BEG test 1 */
	/*
	clock_t start= std::clock();
    clock_t endd = start;
	int i = 0;
	int * di = new int[10];
	while (i<10) {
		endd = std::clock();
		if (start != endd) {
			di[i++] = endd -start;
			start = endd;
		}
	}
	for (i=0; i<10; i++) {
		std::cout<<di[i]<<std::endl;
	}
	*/
	/*END test 1 */
	
	/*BEG test 3 */
	/*
	int i = 0;
	for (i=0; i<2; i++) {
	//getRandomBitsPattern(20);
	//std::cout<<std::endl;
		std::cout<< getRandomBitsPattern(20)<<std::endl;
	}
	*/
	/*END test 3 */
	
	
	/*BEG test 4 */
	int i = 0;
	for (i=0; i<10; i++) {
		std::cout<< getULSeed()<<std::endl;
	}
	/*END test 4 */

	return 0;
}