#pragma once

/*
	TODO:
		- implement setopt_long and setopt_long_only
		- add support repeated options
		- add support for embeding format strings
*/

#include <unordered_map>
#include <string>
#include <string.h>
#include <ctype.h>


#define OPTPREFIX "-"
#define OPTLONGPREFIX "--"
#define OPTGAP " "

enum {
	SETOPTINVALIDOPTSTRING = 1,
	SETOPTMISSINGREQUIRED,
	SETOPTUNKNOWNOPT
};

struct option {
    const char *name;
    int         has_arg;
    int        *flag;
    int         val;
};

enum {
   no_argument       = 0,
   required_argument = 1,
   optional_argument = 2
};

int optc, optred, opterrno = 0;

static inline void setopt_init(){
	optc = 0;
}

char* setopt(const char* optstring, std::unordered_map<char, std::string> argv){
	setopt_init();

	std::string rs;

	for(const char* i = optstring; *i; i++){
		if(not isgraph(*i) or
				*i == '-' or
				*i == ':' or
				*i == ';'
		){
			opterrno = SETOPTINVALIDOPTSTRING;
			continue;
		}	

		auto h = argv.find(*i);
		if(h != argv.end()){
			const char &opt = h->first;
			const std::string &optarg = h->second;
			rs += OPTGAP;
			rs += OPTPREFIX;
			rs += opt;
			++optc;
			if(*(i+1) == ':'){
				if(optarg != ""){
					rs += OPTGAP;
					rs += optarg;
				}else if(*(i+2) == ':'){
					++i;
				}else{
					opterrno = SETOPTMISSINGREQUIRED;
				}
				++i;
			}
			argv.erase(h);
		}else{
			for(int j = 0; j < 2; j++){
				if(*(i+1) == ':'){
					++i;
				}
			}
		}
	}

	if(argv.size()){
		opterrno = SETOPTUNKNOWNOPT;
	}

	char* r;
	if(rs.size()){
		r = new char[rs.size()-1];
		strcpy(r, rs.c_str()+sizeof(OPTGAP)-1);
	}else{
		r = new char[1];
		r[0] = '\00';
	}
	return r;
}

char* setopt_long(const char* optstring, std::unordered_map<std::string, std::string> argv, const struct option* longopts){ return NULL; }
char* setopt_long_only(const char* optstring, std::unordered_map<std::string, std::string> argv, const struct option* longopts){ return NULL; }