#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/time.h>

#define LRAND(s) \
(((s) = (s) * 41943011 - 2147483647) >> 32)

static int utf8_encode(char *out, const uint32_t utf){
        int i = 0;
        static const uint8_t s0 = 0;
        static const uint8_t s1 = 6;
        static const uint8_t s2 = 12;
        static const uint8_t s3 = 18;
        static const uint8_t a0 = 0x07;
        static const uint8_t a1 = 0x0F;
        static const uint8_t a2 = 0x1F;
        static const uint8_t a3 = 0x3F;
        static const uint8_t o0 = 0x80;
        static const uint8_t o1 = 0xC0;
        static const uint8_t o2 = 0xE0;
        static const uint8_t o3 = 0xF0;
        if(utf < 0x0080){
                //Plain ASCII
                out[i++] = (char)utf;
                return i;
        }else if(utf < 0x0800){
                //2-byte unicode
                out[i++] = (char)(((utf >> s1) & a2) | o1);
                out[i++] = (char)(((utf >> s0) & a3) | o0);
                return i;
        }else if(utf < 0x10000){ //65,536
                //3-byte unicode
                out[i++] = (char)(((utf >> s2) & a1) | o2);
                out[i++] = (char)(((utf >> s1) & a3) | o0);
                out[i++] = (char)(((utf >> s0) & a3) | o0);
                return i;
        }else if(utf < 0x110000){ //RFC3629 §3 limit
                //4-byte unicode
                out[i++] = (char)(((utf >> s3) & a0) | o3);
                out[i++] = (char)(((utf >> s2) & a3) | o0);
                out[i++] = (char)(((utf >> s1) & a3) | o0);
                out[i++] = (char)(((utf >> s0) & a3) | o0);
                return i;
        }else{
                //utf-8 outside of current unicode code-space
                printf("invalid utf-8 range\n");
                return i;
        }
}


int main(int argc, char **argv){
	FILE *file;
	const char *file_name = "./all-utf8.txt";
	uint32_t num1 = 0;
	uint32_t num2 = 0;
	//uint32_t num3 = 0;
	char out[5];
	//int size;
	struct timeval cur;
	gettimeofday(&cur, NULL);
	uint64_t rseed = (uint64_t)cur.tv_usec + 3;
	uint32_t rand1;
	const uint32_t max_codepages = 1114112;
	uint8_t used[max_codepages];
//1114111
	if( ( file = fopen(file_name, "w" ) ) == NULL ) {
		fprintf( stderr, "Error opening %s\n", file_name );
		exit(1);
	}


//num = (rand() % (upper – lower + 1)) + lower

	for(num1=0; num1<256; num1++){
		memset((void *)used, 0, max_codepages);
		for(num2=0; num2<max_codepages; num2++){
			//take the closest member from rand1 that is not used
			rand1 = LRAND(rseed) % max_codepages;
			while(used[rand1] == 1){
				if(rand1 < max_codepages-1)
					rand1++;
				else
					rand1 = 0;
				//if(rand1 == max_codepages-1)
				//	rand1 = 0;
				//else
				//	rand1++;
			}
			used[rand1] = 1;
			memset((void*)out, '\0', 5);
			(void)utf8_encode(out, rand1);
			fprintf(file, "%s", out);
			//num3++;
		}
	}

//	while(num1 < 0x110000){
//		memset((void*)out, '\0', 5);
//		size = utf8_encode(out, num1);
//		fprintf(file, "%s", out);
//		num1++;
//	}

	fclose(file);
	return 0;
}
