
/*---------------------------------------------------------------------
 *
 * sparql.h
 *   SPARQL-related functions for RDF data manipulation.
 * 
 * Implements SPARQL 1.1 string functions, accessor functions, and
 * type checking.
 *
 * Copyright (C) 2022-2026 Jim Jones <jim.jones@uni-muenster.de>
 *
 * ---------------------------------------------------------------------
 */

#ifndef SPARQL_H
#define SPARQL_H

#include "postgres.h"
#include "utils/numeric.h"
#include "lib/stringinfo.h"

/*
 * XSD numeric type promotion hierarchy for SPARQL aggregates.
 * Based on SPARQL 1.1 spec section 18.5.1.3 and XPath type promotion rules.
 */
typedef enum
{
	XSD_TYPE_INTEGER = 0,  /* xsd:integer and subtypes (int, long, short, byte, etc.) */
	XSD_TYPE_DECIMAL = 1,  /* xsd:decimal */
	XSD_TYPE_FLOAT = 2,    /* xsd:float */
	XSD_TYPE_DOUBLE = 3    /* xsd:double */
} XsdNumericType;

/*
 * RdfnodeAggState
 * ---------------
 * Unified state structure for all rdfnode aggregate functions.
 * Different aggregates use different fields:
 *   - SUM: uses numeric_value, maxType, has_input, has_non_numeric
 *   - AVG: uses numeric_value, count, maxType, has_input, has_non_numeric
 *   - MIN/MAX: uses rdfnode_value, has_mixed_types
 *   - COUNT: uses count only
 *   - GROUP_CONCAT: uses result_str, separator, has_input
 */
typedef struct
{
    Numeric numeric_value;  /* accumulated numeric value (SUM), sum for average (AVG) */
    float8 float_value;  /* accumulated numeric value (SUM), sum for average (AVG) */
    text *rdfnode_value;    /* current min/max as full rdfnode text (MIN/MAX) */
    StringInfo result_str;  /* accumulated concatenated string (GROUP_CONCAT) */
    text *separator;        /* separator between values (GROUP_CONCAT) */
    int64 count;            /* count of non-NULL values (AVG, COUNT) */
    XsdNumericType maxType; /* highest numeric type seen (for type promotion in SUM/AVG) */
    bool has_input;         /* true if any input values were processed (SUM/AVG/GROUP_CONCAT) */
    bool has_non_numeric;   /* true if any non-numeric values were encountered (SUM/AVG) */
} RdfnodeAggState;

/* 17.4.2 Functions on RDF Terms */
extern bool isIRI(char *input);
extern bool isBlank(char *term);
extern bool isLiteral(char *term);
extern bool isNumeric(char *term);
extern char *str(char *input);
extern char *lang(char *input);
extern char *datatype(char *input);
extern char *iri(char *input);
extern char *bnode(char *input);
extern char *strdt(char *literal, char *datatype);
extern char *strlang(char *literal, char *language);

/* 17.4.3 Functions on Strings */
extern int strlen_rdf(char *str);
extern char *substr_sparql(char *str, int start, int length);
extern char *lcase(char *str);
extern char *ucase(char *str);
extern bool strstarts(char *str, char *substr);
extern bool strends(char *str, char *substr);
extern bool contains(char *str, char *substr);
extern char *strbefore(char *str, char *delimiter);
extern char *strafter(char *str, char *delimiter);
extern char *encode_for_uri(char *str);
extern char *concat(char *left, char *right);
extern bool langmatches(char *lang_tag, char *pattern);

/* Custom functions */
extern char *lex(char *input);
extern char *generate_uuid_v4(void);
extern XsdNumericType get_xsd_numeric_type(const char *dtype);
extern const char *get_xsd_datatype_uri(XsdNumericType type);

/* SPARQL Aggregate Functions */
extern Datum sum_rdfnode_sfunc(PG_FUNCTION_ARGS);
extern Datum sum_rdfnode_finalfunc(PG_FUNCTION_ARGS);
extern Datum avg_rdfnode_sfunc(PG_FUNCTION_ARGS);
extern Datum avg_rdfnode_finalfunc(PG_FUNCTION_ARGS);
extern Datum min_rdfnode_sfunc(PG_FUNCTION_ARGS);
extern Datum min_rdfnode_finalfunc(PG_FUNCTION_ARGS);
extern Datum max_rdfnode_sfunc(PG_FUNCTION_ARGS);
extern Datum max_rdfnode_finalfunc(PG_FUNCTION_ARGS);
extern Datum sample_rdfnode_sfunc(PG_FUNCTION_ARGS);
extern Datum sample_rdfnode_finalfunc(PG_FUNCTION_ARGS);
extern Datum group_concat_sfunc(PG_FUNCTION_ARGS);
extern Datum group_concat_finalfunc(PG_FUNCTION_ARGS);

#endif /* SPARQL_H */
