#include <stdarg.h>
#include <string.h>
#include <epp_avcall.h>
#include <epp_pal.h>
#include "swi-internals.h"
#include "../epp_internals.h"

static int __swi_query_update(pl_query *q, const char *params_spec, ...) {
    int	retval;
    va_list vl;
    
    va_start(vl, params_spec);
    retval = __swi_get_params(params_spec, q -> t0, vl);
    va_end(vl);
    
    return(retval);
}

int pl_vopen_query(pl_query *q, const char *predicate, const char *params_spec, va_list args) {
    unsigned int arity = params_spec ? strlen(params_spec) : 0;
    unsigned int retval = PL_TRUE;
    predicate_t	p;
    
    if (!(pl_is_engine_attached() && pl_is_engine_idle()))
	return(PL_ERROR_PAL);

    av_start_void(q -> update, __swi_query_update);
    av_ptr(q -> update, pl_query*, q);

    if (__epp_make_av_args(&(q -> update), params_spec, args)) {
	return(PL_ERROR_PAL);
    }

    if(!(q -> frame = PL_open_foreign_frame())) {
	return(PL_ERROR_PAL);
    }

    __swi_set_engine_busy();    
    p = PL_predicate(predicate, arity, NULL);

    if (arity) {
	q -> t0 = PL_new_term_refs(arity);

    	if (!__swi_put_params(params_spec, q -> t0, args) || !(q -> t0)) {
	    q -> query = PL_open_query(NULL, PL_Q_NORMAL, p, q -> t0);
	} else {
	    retval = PL_ERROR_PAL;
	    PL_discard_foreign_frame(q -> frame);
	    __swi_set_engine_idle();
	}
    } else {
	q -> query = PL_open_query(NULL, PL_Q_NORMAL, p, 0);
    }

    return(retval);
}


int pl_open_query(pl_query *q, const char *predicate, const char *params_spec, ...) {
    int retval;
    va_list vl;

    va_start(vl, params_spec);
    retval = pl_vopen_query(q, predicate, params_spec, vl);
    va_end(vl);

    return(retval);
}

int pl_next_solution(pl_query *q) {
    int retval = PL_next_solution(q -> query);

    if (av_call(q -> update))
	retval = PL_ERROR_PAL;
    
    if (PL_exception(q -> query))
	retval = PL_ERROR_PROLOG;

    return(retval);
}

void pl_close_query(pl_query *q) {
    PL_cut_query(q -> query);
    PL_close_foreign_frame(q -> frame);
    __swi_set_engine_idle();
}
