#include <dispatcher.h>
#include <stdio.h>

using namespace Arts;
using namespace std;

namespace Options {
	static bool includeInherited = false;
	vector<string> interfaces;
	string prefix;
};

void parse_args (int *argc_p, char ***argv_p)
{
	unsigned int argc = *argc_p;
	char **argv = *argv_p;
	int i, e;

	for (i = 1; i < argc; i++)
    {
		if (strcmp ("-h", argv[i]) == 0 ||
			strcmp ("--help", argv[i]) == 0)
		{
			fprintf (stderr, "Usage: %s [options...] [interfaces...]\n",argv[0]);
			fprintf (stderr, "       generates a header file containing the method definitions\n");
			fprintf (stderr, "Options:\n");
			fprintf (stderr, "       -i, --include-inherited  include inherited interfaces into code generation\n");
			fprintf (stderr, "       -h, --help               this help\n");
			argv[i] = NULL;
			exit (0);
		}
		else if (strcmp ("--include-inherited", argv[i]) == 0
			 ||  strcmp ("-i", argv[i]) == 0)
		{
			Options::includeInherited = true;
			argv[i] = NULL;
		}
		else if (strcmp ("--prefix", argv[i]) == 0
			 ||  strcmp ("-p", argv[i]) == 0)
		{
			if(i+1 < argc)
			{
				Options::prefix = string(argv[i+1]) + "_";
				argv[i] = NULL;
				i++;
				argv[i] = NULL;
			}
		}
		else Options::interfaces.push_back(argv[i]);
	}
	e = 0;
	for (i = 1; i < argc; i++)
	{
		if (e)
		{
			if (argv[i])
			{
				argv[e++] = argv[i];
				argv[i] = NULL;
			}
		}
		else if (!argv[i])
			e = i;
	}
	if (e)
		*argc_p = e;
}

string noColon(const string& name)
{
	string result;
	string::const_iterator i;
	bool swallowColon = false;

	for(i = name.begin(); i != name.end(); i++)
	{
		if(swallowColon)
		{
			if(*i != ':')
				result += *i;
			else
				swallowColon = false;
		}
		else if(*i == ':')
		{
			swallowColon = true;
			result += '_';
		}
		else
		{
			result += *i;
		}
	}
	return result;
}

void collectInterface(const string& name)
{
	static map<string, bool> done;
	done[name] = true;

	InterfaceDef id = Dispatcher::the()->interfaceRepo().queryInterface(name);

	vector<MethodDef> methods (id.methods);

	vector<AttributeDef>::const_iterator ai;

	for(ai = id.attributes.begin(); ai != id.attributes.end(); ai++)
	{
		const AttributeDef& ad = *ai;

		if(ad.flags & attributeAttribute)
		{
			if(ad.flags & streamOut)  /* readable from outside */
			{
				MethodDef md;
				md.name = "_get_"+ad.name;
				md.type = ad.type;
				md.flags = methodTwoway;
				/* no parameters (don't set md.signature) */

				methods.push_back(md);
			}
			if(ad.flags & streamIn)  /* writeable from outside */
			{
				MethodDef md;
				md.name = "_set_"+ad.name;
				md.type = "void";
				md.flags = methodTwoway;

				ParamDef pd;
				pd.type = ad.type;
				pd.name = "newValue";
				md.signature.push_back(pd);

				methods.push_back(md);
			}
		}
	}
	vector<MethodDef>::iterator i;
	string iname = noColon(id.name);
	string guard = "__" + Options::prefix + "_" + iname + "__";

	printf("/*\n");
	printf(" * Autogenerated code for interface %s by mcopcheader\n",id.name.c_str());
	printf(" * do not edit manually\n");
	printf(" */\n\n");

	printf("#ifndef %s\n",guard.c_str());
	printf("#define %s\n\n",guard.c_str());

	for(i = methods.begin(); i != methods.end(); i++)
	{
		string defname = Options::prefix+iname+"_"+i->name;
		Buffer b;
		i->writeType(b);

		printf("#define %-50s \"%s\"\n",
			defname.c_str(), b.toString("").c_str());
	}
	printf("\n");
	printf("#endif /* %s */\n\n",guard.c_str());

	vector<string>::iterator ii;
	for(ii = id.inheritedInterfaces.begin(); 
		ii != id.inheritedInterfaces.end(); ii++)
	{
		if(Options::includeInherited && !done[*ii])
			collectInterface(*ii);
	}
	if(Options::includeInherited && !done["Arts::Object"])
		collectInterface("Arts::Object");
}

int main(int argc, char **argv)
{
	Dispatcher dispatcher;

	parse_args(&argc, &argv);

	vector<string>::iterator i;
	for(i = Options::interfaces.begin(); i != Options::interfaces.end(); i++)
		collectInterface(*i);
}

/* vim:ts=4:sw=4:sts=4
 */
