/*


*/
#include <iostream>
#include <cstdlib>
#include <climits>
#include <string.h>
/*
void shuffleAnArray (int length, int * array_i) {
	int c = length;
		for (array_i=0; array_i < c-1 ; array_i++) {
			int v = rand() % (c -array_i-1);
			int cursor = v+array_i+1;
			if (cursor >= c)
				continue;
			int tmp = myarray[cursor ];
			myarray[cursor ] = myarray[array_i];
			myarray[array_i] = tmp;
		}
}
void recursiveRandomFlipPermute(unsigned long long pattern, int * lanes  ,int total_depth, int current_depth) {
}
*/
inline void createIndices(unsigned long long n, unsigned long long  m, unsigned long long  k, unsigned long long * rindx) {
	unsigned long long i = 0LL,dsi =1LL,j=0LL;
	for (i=0LL; i<m; i++) {
		dsi = (k) % (n-i);
		if (dsi==0LL) 
			dsi = n-i;
		rindx[i] = dsi;
		if (k<= n-i) {
			for (j = i+1LL;j<m;j++)
				rindx[j] = 1LL;
			break;
		} 
		//k = (k-1) /(n-i+1);
		k = (k-1LL)/(n-i)+1LL;
	}
}
inline void parsePermutation (unsigned long long  n, unsigned long long  m, unsigned long long  * rindx,unsigned long long  *results) {

unsigned long long  * data = new unsigned long long [n];


	unsigned long long  i =0LL,j=0LL;
	for (i=0LL; i<n;i++)
		data[i] = i+1;
	for (i=0LL; i<m;i++) {
		results[i] = data[rindx[i]-1LL];
		for (j=rindx[i]-1LL; j<n-1LL; j++) {
			data[j] = data[j+1LL];
		}
	}
	//	delete [] data; data = NULL;
}



//CloseOpen is namely [min,max) <=> [0, range) as the typical random range specification
unsigned long long pseudoGetAULLRandomCloseOpenRange(unsigned long long  range) {
	//RAND_MAX is typically 2G -1 = 2 * 2^30 -1
	//ULLONG_MAX should be 2^64-1 = 16 * 2^60 - 1 = (4 * 2 ^30 )^ 2 - 1 = (4 * 2 ^30 -1 )*(4 * 2 ^30 + 1 )
	// we need a randmon number between [0, max (RAND_MAX,ULLONG_MAX) ) 
	
	
	
	unsigned long long start_pattern = ULLONG_MAX;
	unsigned long upper_pattern = 0LL;
	unsigned long lower_pattern = 0LL;

	memcpy(&lower_pattern, &start_pattern, sizeof lower_pattern);
	memcpy(&upper_pattern, (char *) &start_pattern + sizeof lower_pattern, sizeof upper_pattern);

	int spi = 0;
	for (spi = 0; spi< 64; ++spi) {
		//start_pattern &= ~(1 << spi);
		bool flipornot =  ( (rand() % 2) == 0 );
		if (flipornot) {
			if ( spi < 32 ) {
				lower_pattern &= ~(1 << spi);
			} else {
				upper_pattern &= ~(1 << (spi-32));
			}
		}
		//std::bitset<32> bsup(upper_pattern);
		//std::bitset<32> bslo(lower_pattern);
		//std::cout<<bsup <<bslo <<std::endl; 

	}

	
	memcpy(&start_pattern, &lower_pattern, sizeof lower_pattern);
	memcpy( (char *) &start_pattern + sizeof lower_pattern, &upper_pattern, sizeof upper_pattern);

	return start_pattern % range;
}
int main () {
srand(time(NULL)%1597);
	// unsigned long long start_pattern = ULLONG_MAX;
	// int filp_depth = 3;
	// int * lanes = new int[filp_depth];
	// int i = 0;
	// for (i = 0; i < filp_depth; ++i) {
		// lanes[i] = i;
	// }
	unsigned long long lli = 0LL;
	unsigned long long factorial40 = 1LL;
	for (lli = 1; lli <= 40LL; ++lli) {
		factorial40 *= lli;
	}
	std::cout <<"40! is "<<factorial40<<std::endl;
	std::cout <<"RAND_MAX is "<<RAND_MAX<<std::endl;
	
	for (lli = 1; lli <= 1024LL; ++lli) {
		unsigned long long  tmp_result= pseudoGetAULLRandomCloseOpenRange (factorial40);
		//if ( tmp_result <0 || tmp_result >= result)
			//std::cout<<tmp_result<<std::endl;
	}
	
	
	unsigned long long  tmp_result= pseudoGetAULLRandomCloseOpenRange (factorial40);
	std::cout<<"tmp_result: "<<tmp_result<<std::endl;
	unsigned long long * rindx = new unsigned long long[40];
	createIndices(40, 40, tmp_result, rindx);
	unsigned long long * permute = new unsigned long long[40];
	parsePermutation (40, 40,  rindx,permute);
	int i = 0;
	for (i = 0; i < 40; ++i) {
		std::cout<<permute[i]<<std::endl;
	}

	
	

	return 0;
}