#include <iostream>
#include <string>
#include <sqlite3.h>

/**
   A simple example of writing a custom SQL function for sqlite3.

   It provides results of a so-called Fudge-dice roll. Fudge dice (dF)
   are used by the Fudge roleplaying system (http://fudgerpg.com).

   Call it with 0, 1 or 2 arguments:

   0 args: same as calling dF(4).

   1 arg: arg1 is an integer telling how many dice to roll.

   2 args: arg2 is any value. The TYPE of the value is used to
   dynamically set the return type. If arg2 is an INTEGER (the
   default) or DOUBLE then a number of the appropriate type is
   returned to the caller via sqlite_result_xxx(context,...). If arg2
   is a string then a description showing the results of each die roll
   of the set, plus the total, is sent back.


   You may bind this function to your db by calling something like:

   sqlite3_create_function( myDb, "dF",-1,SQLITE_ANY,0,sqlite_func_dF,0, 0 );

   Author: stephan at s11n dot net

   License: Public Domain

*/
void sqlite_func_dF(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv )
{
	static bool seeded = false;
	if( !seeded && (seeded=true) )
	{
		srand( time(NULL) );
	}

	if( argc > 2 )
	{
		sqlite3_result_error( context, "dF() function requires 0, 1, or 2 arguments: (0==roll 4dF and return int), (1==roll [ARG0]dF and return int), (2=roll [ARG0]dF and return result as TYPEOF(ARG1))", -1 );
		return;
	}

	int count = 0;
	int returnT = (argc<2) ? SQLITE_INTEGER : sqlite3_value_type(argv[1]);
	if( 0 == argc )
	{
		count = 4;
	}
	else
	{
		count = sqlite3_value_int(argv[0]);
	}
	if( count < 1 ) count = 4;

	int reti = 0;
	std::ostringstream rets;
	if( SQLITE_TEXT == returnT )
	{
		rets << count << "dF: ";
	}
	{
		int rnd;
		char marker;
		while( count-- )
		{
			rnd = rand() % 3 - 1;
			if( SQLITE_TEXT == returnT )
			{
				marker = ((0==rnd) ? '0' : ((1==rnd) ? '+' : '-'));
				rets << marker << ' ';
			}
			reti += rnd;
		}
	}
	if( SQLITE_TEXT == returnT )
	{
		rets << " = "<<reti;
		std::string rs = rets.str();
		sqlite3_result_text( context, rs.c_str(), rs.size(), SQLITE_TRANSIENT );
	}
	else if( SQLITE_FLOAT == returnT )
	{
	  // The 1.00001 thing here is a kludge to force the return result
	  // to be a true double. Can't quite remember why it was necessary
	  // (maybe it isn't).
		sqlite3_result_double(context, 1.00001 * reti);
	}
	else
	{
		sqlite3_result_int(context, reti);
	}
	return;
}

