#include <string.h>
#include <stdio.h>
#include <mysql/mysql.h>
#include <pcre.h>
#include "pcrs/pcrs.h"

// string REGEXT_REPLACE(pattern, replace, subject[, options])

typedef struct {
    pcrs_job *pcrs;
} workdata_t;

my_bool regexp_replace_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
    workdata_t *d = 0;
    int error = 0;
    int errptr;
    char *options = "";

    do
    {
	if (args->arg_count < 3 || args->arg_count > 4)
	{
	    strcpy(message, "REGEXP_REPLACE() requires 3 or 4 arguments.");
	    error = 1;
	    break;
	}

	if (
	    args->args[0] == 0 || args->arg_type[0] != STRING_RESULT
	    || args->args[1] == 0 || args->arg_type[1] != STRING_RESULT
	)
	{
	    strcpy(message, "REGEXP_REPLACE() requires constant strings for regexp and replace paterns.");
	    error = 1;
	    break;
	}

	args->arg_type[2] = STRING_RESULT;

	if (args->arg_count == 4)
	{
	    if (args->args[3] == 0 || args->arg_type[3] != STRING_RESULT)
	    {
		strcpy(message, "REGEXP_REPLACE() requires constant string for a options.");
		error = 1;
		break;
	    }

	    options = args->args[3];
	}

	d = (workdata_t*)malloc(sizeof(workdata_t));
	memset((void*)d, 0, sizeof(workdata_t));

	d->pcrs = pcrs_compile(args->args[0], args->args[1], options, &errptr);

	if (d->pcrs == 0)
	{
	    sprintf(message, "REGEXP_REPLACE(): error on regexp compile: %s.", pcrs_strerror(errptr));
	    error = 1;
	    break;
	}
    }
    while(0);

    if (error)
    {
	if (d)
	{
	    if (d->pcrs)
		pcrs_free_job(d->pcrs);

	    free(d);
	}

	return 1;
    }

    initid->maybe_null = 0;
    initid->const_item = 0;
    initid->ptr = (char*)d;

    return 0;
}

char* regexp_replace(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
    char *pcrs_result;
    size_t pcrs_length;

    if (args->args[2] == 0)
    {
	*error = 1;
	return 0;
    }

    if (pcrs_execute(((workdata_t*)initid->ptr)->pcrs, args->args[2], args->lengths[2], &pcrs_result, &pcrs_length) >= 0)
    {
	*length = pcrs_length;
	return pcrs_result;
    }

    *error = 1;
    return 0;
}

void regexp_replace_deinit(UDF_INIT *initid)
{
    pcrs_free_job(((workdata_t*)initid->ptr)->pcrs);
    free((void*)initid->ptr);
}
