#include "postgres.h"

#include <stdio.h>    /* snprintf */
#include <stdlib.h>    /* malloc, free */
#include <string.h>    /* strncpy, strlen */
#include <sys/types.h>  /* for uint32 and size_t*/

#include "catalog/pg_type.h"
#include "utils/builtins.h"  /* text_to_cstring */
#include "funcapi.h"
#include "fmgr.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1(srfpoc);

Datum srfpoc(PG_FUNCTION_ARGS) {
  FuncCallContext *funcctx;
  TupleDesc        tupdesc;
  text            *t;
  int              max_calls,
                   call_cntr;

  t = (text *)PG_GETARG_TEXT_PP(0);
  
  if (SRF_IS_FIRSTCALL()) {
    MemoryContext    oldcontext;

    funcctx = SRF_FIRSTCALL_INIT();
    oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

    funcctx->max_calls = (uint32)PG_GETARG_INT32(1);

    tupdesc = CreateTemplateTupleDesc(2, false);
    TupleDescInitEntry(tupdesc, (AttrNumber) 1, "t", TEXTOID, -1, 0);
    TupleDescInitEntry(tupdesc, (AttrNumber) 2, "count", INT4OID, -1, 0);

    funcctx->user_fctx = BlessTupleDesc(tupdesc);

    MemoryContextSwitchTo(oldcontext);
  }

  funcctx = SRF_PERCALL_SETUP();
  max_calls = funcctx->max_calls;
  call_cntr = funcctx->call_cntr;
  tupdesc = funcctx->user_fctx;

  if(call_cntr < max_calls && t != NULL) {
    bool         nulls[2];
    Datum        values[2];
    HeapTuple    tuple;
    text        *cpyt;

    cpyt = (text *)palloc(VARHDRSZ + VARSIZE_ANY_EXHDR(t));
    SET_VARSIZE(cpyt, VARHDRSZ + VARSIZE_ANY_EXHDR(t));
    memcpy((void *)VARDATA(cpyt), (void *)VARDATA(t), VARSIZE_ANY_EXHDR(t));

    values[0] = PointerGetDatum(cpyt);
    values[1] = Int32GetDatum(call_cntr);
    nulls[0] = false;
    nulls[1] = false;

    tuple = heap_form_tuple(tupdesc, values, nulls);
    SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));

  } else {
    SRF_RETURN_DONE(funcctx);
  }
}
