#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define CHR_NUMBER    0x01
#define CHR_LC_LETTER 0x02
#define CHR_UC_LETTER 0x04
#define CHR_OTHER     0x08
#define CHR_UNCOMMON  0x10

/*
#define CHR_LETTERS   0x06
#define CHR_ALPHANUM  0x07
#define CHR_COMMON    0x0F
#define CHR_ALL       0x1F
*/

char password[512];
int length;

int random_type(int choices)
{
	int r = 0;
	r += (choices & CHR_NUMBER)    ? 10 : 0;
	r += (choices & CHR_LC_LETTER) ? 26 : 0;
	r += (choices & CHR_UC_LETTER) ? 26 : 0;
	r += (choices & CHR_OTHER)     ? 16 : 0;
	r += (choices & CHR_UNCOMMON)  ? 15 : 0;
	r = rand() % r;
	if(choices & CHR_NUMBER) {
		if(r < 10) return CHR_NUMBER;
		else r -= 10;
	}
	if(choices & CHR_LC_LETTER) {
		if(r < 26) return CHR_LC_LETTER;
		else r -= 26;
	}
	if(choices & CHR_UC_LETTER) {
		if(r < 26) return CHR_UC_LETTER;
		else r -= 26;
	}
	if(choices & CHR_OTHER) {
		if(r < 16) return CHR_OTHER;
		else r -= 16;
	}
	if(choices & CHR_UNCOMMON) {
		if(r < 15) return CHR_UNCOMMON;
		else r -= 15;
	}
	return 0;
}

char random_char(int type)
{
	char c1[] = {33, 35, 36, 37, 38, 42, 43, 44, 45, 58, 59, 60, 61, 62, 63, 95};
	char c2[] = {34, 39, 40, 41, 64, 91, 92, 93, 94, 95, 96, 123, 124, 125, 126};
	switch(type) {
		case CHR_NUMBER:
			return '0' + (rand() % 10);
		case CHR_LC_LETTER:
			return 'a' + (rand() % 26);
		case CHR_UC_LETTER:
			return 'A' + (rand() % 26);
		case CHR_OTHER:
			return c1[rand() % 16];
		case CHR_UNCOMMON:
			return c2[rand() % 15];
		default:
			return '?';
	}
}

void place_type(int type)
{
	int r;
	do {
		r = rand() % length;
	} while(password[r]);
	password[r] = type;
}

int error(char *str)
{
	fprintf(stderr, "%s\n", str);
	return 1;
}

int main()
{
	int i;
	
	int a = 8;
	int b = 2;
	int c = 2;
	int verbose = 0;

	srand(time(NULL) + getpid() - getppid());
	
	memset(password, 0, 512 * sizeof(int));

	length = a;

	if(c > (a-b) / 2)
		return error("Too many numbers");
	if(a < 6)
		return error("Not enough characters");
	if(b < 2)
		return error("Not enough non-alphanumerical characters");

	for(i = 0; i < c; i++)
		place_type(CHR_NUMBER);
	for(i = 0; i < b; i++)
		place_type(CHR_OTHER);
	for(i = 0; i < 0; i++)
		place_type(CHR_UNCOMMON);
	for(i = 0; i < (a-b-c)/2; i++)
		place_type(CHR_UC_LETTER);
	for(i = 0; i < a; i++)
		if(!password[i]) password[i] = CHR_LC_LETTER;
	
	for(i = 0; i < a; i++)
		password[i] = random_char(password[i]);
	
	if(verbose)
		for(i = 0; i < a; i++)
			printf("'%c' (%d)\n", password[i], password[i]);
	else {
		for(i = 0; i < a; i++)
			putchar(password[i]);
		putchar('\n');
	}
	
	return 0;
}



