#include <sys/stat.h> // mkdir

#include <unistd.h> // close
#include <fcntl.h> // open, O_*
#include <string.h> // memcpy
#include <limits.h> // PATH_MAX
#include <stdbool.h>
#include <stdlib.h> // drand48
#include <errno.h>
#include <math.h> //
#include <err.h>
#include <errno.h>

#include <stdio.h> // debugging

/* smallest and largest file sizes, in bytes
 */

struct randstate {
	unsigned short state[3];
};
const struct randstate seed = {{
	42,
	9,
	6
}};

const int smallest_file = 40000;
const int largest_file = 80000;
const double steepness = 128;
const int number_of_subdirs = 29;
const int max_files_per_dir = 40;

double
between(int ymin, int ymax, int xmin, int xmax, double x) {
	/* maps from xmin-xmax to ymin-ymax at x */

	double effective_x = (((double)(x - xmin)) /(xmax-xmin)); /* 0-1 */
	/* bias towards ymax for higher x
	   like before 0.5 -> 0.5, but now 0.5 -> 0.9 and 0.9 to 0.99
	 */
	double result = pow(steepness, effective_x) / steepness;
	return result * (ymax-ymin) + ymin;
}	

int main(int argc, char *argv[])
{
	struct randstate base = seed;

	char path[PATH_MAX];

	const char schars[] = "ashtgyneoiqdrwbjfupzxmcvkl";
	char achar(void) {
		return schars[(int)(erand48(base.state) * (sizeof(schars)-1))];
	}

	int addsuffix(int plen) {
		int suff;
		int top = erand48(base.state)*6 + 1;
		for(suff=0;suff<top;++suff) {
			path[plen+suff] = achar();
		}
		return plen+top;
	}
	system("rm -rf herp");
	memcpy(path, "herp/\0", 6);
	mkdir(path, 0755);
	memcpy(path+5, "derp", 4);
	int plen = 4+5;
	int subdir;
	int save1 = plen;
#ifdef RANDOM_CONTENTS
	struct randstate contents = seed;
#endif	
	for(subdir=0;subdir<number_of_subdirs;++subdir) {
		/* make sure to ignore the null for plen! */
		plen = addsuffix(plen);
		path[plen] = 0;
		mkdir(path, 0755);
		path[plen] = '/'; ++plen;
		
		memcpy(path+plen, "file", 4);
		plen += 4;
		int file;
		int top = between(1,max_files_per_dir,0,number_of_subdirs,subdir);
		printf("%d FILES\n", top);
		int save2 = plen;
		for(file=0;file<top; ++file) {
			plen = addsuffix(plen);
			if(erand48(base.state) < 0.5) {
				path[plen] = '.'; ++plen;
				path[plen] = 'h'; ++plen;
				path[plen] = 't'; ++plen;
				path[plen] = 'm'; ++plen;
				path[plen] = 'l'; ++plen;
			} else {
				path[plen] = '.'; ++plen;
				path[plen] = 't'; ++plen;
				path[plen] = 'x'; ++plen;
				path[plen] = 't'; ++plen;
			}
			path[plen] = 0;
			int out = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
			if(out < 0) {
				write(2, "woops: ", 7);
				const char* err = strerror(errno);
				write(2, err, strlen(err));
				abort();
			}
			int idx;
			int contop = between(smallest_file, largest_file,
								 0, 1, pow(erand48(base.state), 0.5));
			char constr[contop];

			for(idx=0;idx<contop; ++idx) {
				constr[idx] =
#ifdef RANDOM_CONTENTS
					(char)(erand48(contents.state) * 0x100)
					//achar();
#else
					'Q'
#endif
					;
			}
			size_t off = 0;
			for(;;) {
				ssize_t amt = write(out, constr + off, contop - off);
				if(amt < 0) {
					err(errno, "write");
				}
				if(amt == 0) {
					break;
				}
				off += amt;
			}

			close(out);
			plen = save2;
		}
		plen = save1;
	}

    return 0;
}
