#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <which.h>
#include <spawn.h>

#define spawn(argv, envp) posix_spawn(NULL, argv[0], NULL, NULL, argv, envp)

#ifndef gammel
void help(){
	fputs(
		"Usage:"
		"automix PROG ARGS\n"
		"	invokes PROG rand_order(ARGS)\n"
		"automix PROG OPTS -- ARGS\n"
		"	invokes PROG -- rand_order(ARGS)\n"
		"automix PROG OPTS ---[-[-[-[-[...]]]]] ARGS\n"
		"	invokes PROG rand_order(ARGS)\n"
		,stdout
	);
}

int dashcount(char *arg){
	if(!arg) return 0;
	char *end=arg;
	while(*end == '-') end++;
	if(*end != '\0') end = arg;
	return end - arg;
}

int main(int argc, char *argv[], char *envp[]){
	if(argc < 3){
		help();
		return 0;
	}
	srand(time(NULL));
	argv++; argc--;
	int endopt = 1;
	while(dashcount(argv[endopt]) < 2) endopt++;
	if(dashcount(argv[endopt]) > 2){
		int opt;
		for(opt=endopt; opt; opt--){
			argv[opt] = argv[opt-1];
		}
		argv++; argc--;
	}else{
		endopt++;
	}

	for(;; endopt++){
		int remain = argc - endopt;
		if(remain < 2) break;
		int random = (rand() % remain) + endopt;
		char *swp = argv[endopt];
		argv[endopt] = argv[random];
		argv[random] = swp;
	}
	char *prog = which(argv[0]);
	if(!prog){
		perror(argv[0]);
		return 1;
	}
	execve(prog, argv, envp);
	perror(prog);
	free(prog);
	return 1;
}
#elif defined enkel
int main(int argc, char *argv[], char *envp[]){
	char *prog[3];
	prog[0] = which(argv[1]);
	prog[2] = NULL;

	srand(time(NULL));
	argv += 2; argc -= 2;
	int b;
	for(b=argc; b;){
		int r = rand() % b;
		b--;
		if(r != b){
			register char *t = argv[r];
			argv[r] = argv[b];
			argv[b] = t;
		}
	}

	while(b < argc){
		prog[1] = argv[b];
		e = spawn(prog, envp);
		if(e) fprintf(stderr, "%s: %s\n", prog[0], strerror(e));
		else wait(NULL);
		//printf("%s %s\n", prog[0], prog[1]);
		b++;
	}

	free(prog[0]);
	return 0;
}
#else
int main(int argc, char *argv[], char *envp[]){
	argv++; argc--;
	char opttree[]={
		'a',70, 'h', 8, 'o',18, 'v',40, '\0',0,
		'e', 4, '\0',0,
		'l', 4, '\0',0,
		'p', 2, '\0',1,
		'p', 4, '\0',0,
		't', 4, '\0',0,
		'a', 4, '\0',0,
		'r', 4, '\0',0,
		'g', 4, '\0',0,
		's', 2, '\0',2,
		'e', 4, '\0',0,
		'r', 4, '\0',0,
		's', 4, '\0',0,
		'i', 4, '\0',0,
		'o', 4, '\0',0,
		'n', 2, '\0',3,
		'a', 4, '\0',0,
		'l', 4, '\0',0,
		'l', 4, '\0',0,
		'a', 4, '\0',0,
		'r', 4, '\0',0,
		'g', 4, '\0',0,
		's', 2, '\0',4,
	};
	int optargs=-1;
	while(argv[0][0] == '-' && argv[0][1] == '-'){
		int optnum=-1;
		register char *i = argv[0]+2, *j = opttree;
		for(;;){
			if(*i == *j){
				if(*j == '\0'){
					optnum = j[1];
					break;
				}else{
					j += j[1];
				}
				i++;
			}else{
				if(*i == '\0') break;
				if(*j == '\0') break;
				j += 2;
			}
		}
		switch(optnum){
			case 1:
				puts("automix - Execute PROGRAM with each of the ARGUMENTS\none by one in random order. Usage:\nautomix PROGRAM ARGUMENTS\nautomix --optargs NUM_OPTARGS PROGRAM OPTARGS ARGUMENTS\n\nOptions:\n--help\t\tShow this text\n--optargs N\tTreat the first N ARGUMENTS as OPTARGS, which are\n\t\talways passed to PROGRAM and excepted from ARGUMENTS.");
				break;
			case 2:
				argv++; argc--;
				register char *str = *argv;
				while(*str != '\0'){
					optargs *= 10;
					optargs += *str - '0';
					str++;
				}
				break;
			case 3:
				puts("automix 1.1");
				break;
			default:
				printf("%s: no such option\n", argv[0]);
				break;
		}
		argv++; argc--;
	};

	argv++; argc--;
	srand(time(NULL));
	int b=argc;
	while(b){
		int r = rand() % b;
		b--;
		if(r != b){
			register char *t = argv[r];
			argv[r] = argv[b];
			argv[b] = t;
		}
	}
	argv--; argc++;

	int e;
	if(optargs == -1){
		argv[0] = which(argv[0]);
		if(!argv[0]) return -1;
		e = spawn(argv, envp);
		if(e) fprintf(stderr,
			"%s: %s\n",
			argv[0],
			strerror(e));
		else wait(NULL);
		free(argv[0]);
	}else{
		char *prog[3 + optargs];//C99
		char **pr = prog;
		prog[0] = which(argv[0]);
		if(!prog[0]) return -1;
		argv++; argc--; pr++;
		while(optargs--){
			*pr = *argv;
			argv++; argc--; pr++;
		}
		*(pr+1) = NULL;

		while(b < argc){
			*pr = argv[b];
			e = spawn(prog, envp);
			if(e) fprintf(stderr, "%s: %s\n", prog[0], strerror(e));
			else wait(NULL);
			//printf("%s %s\n", prog[0], prog[1]);
			b++;
		}
		free(prog[0]);
	}
	return 0;
}
#endif

