/*
 *  mod-xslt -- Copyright (C) 2002, 2003 
 *   		 Carlo Contavalli 
 *   		 <ccontavalli at masobit.net>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#ifndef MXSLT_H
# define MXSLT_H

# undef PACKAGE_BUGREPORT
# undef PACKAGE_NAME
# undef PACKAGE_STRING
# undef PACKAGE_TARNAME
# undef PACKAGE_VERSION

# include <modxslt0/modxslt-system.h>
# include "modxslt-version.h"
# include "modxslt-table.h"

# include <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <string.h>
# include <errno.h>

# ifdef HAVE_PTHREADS
#  include <pthread.h>
# endif

  /* XML include files */
# include <libxml/tree.h>
# include <libxml/uri.h>
# include <libxml/parserInternals.h>
# include <libxml/threads.h>
# include <libxml/nanohttp.h>

  /* XSLT include files */
# include <libxslt/xslt.h>
# include <libxslt/xsltInternals.h>
# include <libxslt/transform.h>
# include <libxslt/xsltutils.h>
# include <libxslt/extensions.h>
# include <libxslt/templates.h>
# include <libxslt/imports.h>

  /* Define some constants */
# define MXSLT_NAME "mod_xslt"
# define MXSLT_STD_HANDLER "mod-xslt"
# define MXSLT_NS_URI "http://www.mod-xslt2.com/ns/1.0"
# define MXSLT_SITE "http://www.mod-xslt2.com/"

# ifdef MXSLT_DO_DEBUG
#  ifndef MXSLT_DEBUG
#   define MXSLT_DEBUG(str, ...) fprintf(stderr, "%s " str, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#  endif /* MXSLT_DEBUG */
# else /* MXSLT_DO_DEBUG */
#  define MXSLT_DEBUG(...) 
# endif /* MXSLT_DO_DEBUG */

# ifdef MXSLT_DO_DEBTMP
#  ifndef MXSLT_DEBUG1
#   define MXSLT_DEBUG1(str, ...) fprintf(stderr, "%s " str, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#  endif
# else
#  define MXSLT_DEBUG1(...)
# endif

# ifndef MXSLT_XSLT_OPTIONS
#  ifndef MXSLT_DISABLE_XINCLUDE
#   define MXSLT_XSLT_OPTIONS XML_PARSE_NOENT|XML_PARSE_DTDLOAD|XML_PARSE_DTDATTR| \
 	   XML_PARSE_NSCLEAN|XML_PARSE_NOCDATA|XML_PARSE_XINCLUDE
#  else
#   define MXSLT_XSLT_OPTIONS XML_PARSE_NOENT|XML_PARSE_DTDLOAD|XML_PARSE_DTDATTR| \
 	   XML_PARSE_NSCLEAN|XML_PARSE_NOCDATA
#  endif
# endif

  /* Initial size of params table.
   * Should be a power of 2 minus 1.
   * Default 2^3 - 1 = 7 */
# define MXSLT_PARAM_START 7 
# define APOS(str) "'" str "'"
# define STR(macro) #macro

typedef enum mxslt_status_t {
  MXSLT_OK=0,
  MXSLT_FAILURE,
  MXSLT_NONE,
  MXSLT_UNLOADABLE,
  MXSLT_DECLINE,
  MXSLT_SKIP,
  MXSLT_PARAM,
  MXSLT_PARAM_BADKEY,
  MXSLT_PARAM_OVERFLOW,
  MXSLT_LOOP,
  MXSLT_MAX_LEVEL
} mxslt_status_t;

typedef enum mxslt_lookup_status_t {
  MXSLT_FOUND=0,
  MXSLT_NOT_FOUND=-1
} mxslt_lookup_status_t;

typedef enum mxslt_op_t {
  MXSLT_ERROR=-1,
  MXSLT_FALSE=0,
  MXSLT_TRUE=1
} mxslt_op_t;

  /* Holds call backs to be called
   * to output data */
typedef struct mxslt_callback_t {
  int (*writer)(void *, const char *, int);
  int (*closer)(void *);
} mxslt_callback_t;

# define BIT(a) 1<<a
typedef enum mxslt_doc_flags_e {
  MXSLT_BERAW=BIT(0),  /* Return raw result */
  MXSLT_ISWRG=BIT(1),  /* Document contains errors */
  MXSLT_STYLE=BIT(3)   /* We're loading stylesheet */
} mxslt_doc_flags_e;

typedef enum mxslt_pi_e {
  MXSLT_PI_NONE,
  MXSLT_PI_PARAM,
  MXSLT_PI_STDST,
  MXSLT_PI_MODST,
  MXSLT_PI_UBASE
} mxslt_pi_e;

  /* A generic processing instruction
   * found in the document */
typedef struct mxslt_pi_t {
  int type;
  struct mxslt_pi_t * next;
  xmlNodePtr node;
} mxslt_pi_t;

  /* A stylesheet processing
   * instruction */
typedef struct mxslt_pi_style_t {
  int type;
  struct mxslt_pi_t * next;
  xmlNodePtr node;

  char * ctype;
  char * href;
  char * media;

} mxslt_pi_style_t;

  /* A param processing 
   * instruction */
typedef struct mxslt_pi_param_t {
  int type;
  struct mxslt_pi_t * next;
  xmlNodePtr node;
  
  char * param;
  char * value;
} mxslt_pi_param_t;

  /* A base processing 
   * instruction */
typedef struct mxslt_pi_base_t {
  int type;
  struct mxslt_pi_t * next;
  xmlNodePtr node;
  
  char * directory;
  char * file;
} mxslt_pi_base_t;


  /* Keeps temporary state 
   * of a wrapper http handler */
typedef struct mxslt_http_t {
  int handled;
  void * data;
} mxslt_http_t;

#ifndef MXSLT_MAX_RECURSION_LEVEL
# define MXSLT_MAX_RECURSION_LEVEL 15
#endif

  /* Holds information about the maximum
   * recursion level reached by the server */
typedef struct mxslt_recursion_t {
  int rec_level;
  mxslt_table_t rec_table;
  mxslt_table_record_t * rec_lastrecord;
} mxslt_recursion_t;

# define MXSLT_RECURSION_INIT { 0, mxslt_table_init_static(), NULL }

  /* Holds informations about a 
   * single document */
typedef struct mxslt_doc_t {
  int flags; 	/* Document state flags */
  void * ctx; 	/* Document context, used by sapi handlers */

    /* URL of the document */
  char * localurl;
  char * localfile;

    /* Header handling callbacks */
  void (*header_set)(void *, char *, char *);
  void * header_data;

    /* Xml translation handling */
  xmlDocPtr file;
  xmlDocPtr parsed;

  xsltStylesheetPtr stylesheet;
  char * parser; /* 'apache1', 'apache2... */

    /* Xml pi pointers */
  mxslt_pi_t * pi_first;
  mxslt_pi_t * pi_last;

    /* Xml document info */
  xmlChar * encoding;
  xmlChar * content_type;
  xmlCharEncodingHandlerPtr encoder;

    /* Error handling */
  void (* errhdlr)(void * ctx, const char * msg, ...);
  void * errctx; 

    /* Parameters parsing */
  mxslt_table_t table;

    /* Context used by http handler */

    /* State being currently used */
  struct mxslt_state_t {
    struct mxslt_http_handler_t {
      int (*handle)(struct mxslt_doc_t *, void **, void *, const char *);
      int (*close)(struct mxslt_doc_t *, void *);
      int (*read)(struct mxslt_doc_t *, void *, const char *, int);
      int (*open)(struct mxslt_doc_t *, void *, void *, const char **, void **);
        /* int (*get)(struct mxslt_doc_t **, void **, mxslt_recursion_t **);*/
    } http_handler;
    struct mxslt_recursion_t * recursion;
    struct mxslt_doc_t * document;
    void * ctx;
  } * state;

  struct mxslt_shoot_t {
    struct mxslt_state_t * mxslt_state;
    void * xml_state;
  } shoot;
} mxslt_doc_t;

  /* Shortcut for many other boring cast */
/* typedef int (*mxslt_http_data_get_t)(struct mxslt_doc_t **, void **, mxslt_recursion_t **); */
typedef int (*mxslt_http_handle_t)(struct mxslt_doc_t *, void **, void *, const char *);
typedef int (*mxslt_http_open_t)(struct mxslt_doc_t *, void *, void *, const char **, void **);
typedef int (*mxslt_http_read_t)(struct mxslt_doc_t *, void *, const char *, int);
typedef int (*mxslt_http_close_t)(struct mxslt_doc_t *, void *);

  /* Keeps the function pointers
   * used by sapi to override http handling */
typedef struct mxslt_http_handler_t mxslt_http_handler_t;
# define MXSLT_HTTP_HANDLER_INIT { mxslt_http_handle, NULL, NULL, NULL }

  /* Holds the current global state of the library */
typedef struct mxslt_state_t mxslt_state_t;
# define MXSLT_STATE_INIT { MXSLT_HTTP_HANDLER_INIT, NULL, NULL, NULL }

  /* Holds current yaslt state. Created at
   * xml_init time, restored on each request */
typedef struct mxslt_shoot_t mxslt_shoot_t;
# define MXSLT_SHOOT_INIT  { NULL, NULL }

typedef enum mxslt_scan_flag_e {
  MSF_WITHOUT_MEDIA=BIT(0)
} mxslt_scan_flag_e;

  /* Holds information about the current
   * scanning state */
typedef struct mxslt_scan_t {
  int flags;

  int status;
  mxslt_doc_t * document;
} mxslt_scan_t;

  /* Shortcut some boring casts */
typedef int (*mxslt_opr_call_t)(mxslt_doc_t *, void *, void *);

  /* Holds informations abouta an
   * operator */
typedef struct mxslt_opr_t {
  char * opr;
  mxslt_opr_call_t call;
} mxslt_opr_t;

  /* Holds a list of static attributes
   * to be looked for in an array */
typedef struct mxslt_attr_search_t {
  xmlChar * name;
  int size;
} mxslt_attr_search_t;

  /* Holds a variable for the yaslt
   * parser */
typedef struct mxslt_var_t {
  char * string;  /* Variable value. NULL is valid */
  int found;	/* If the variable was found */
} mxslt_var_t;

  /* Include parsing prototypes */
/* # include "../parser/modxslt-screen-expr.parser.h" */

  /* Used internally to call operator handlers */
# define mxslt_opr_bool_call(op, doc, val1, val2) ((op)->call)(doc, (void *)val1, (void *)val2)
# define mxslt_opr_cmp_call(op, doc, val1, val2) ((op)->call)(doc, (void *)val1, (void *)val2)

  /* Used to call http handlers */
# ifdef HAVE_PTHREADS
#  define mxslt_global_http_state (*(mxslt_http_handler_t *)(pthread_getspecific(mxslt_global_http_handler)))
# else /* HAVE_PTHREADS */
#  define mxslt_global_http_state mxslt_global_http_handler
# endif

  /* Used to call http handling globals */
# define mxslt_sapi_http_data_get(doc, store, ctx, rec) ((mxslt_global_http_state.get)(doc, store, ctx, rec))
# define mxslt_sapi_http_open(doc, store, ctx, uri, ret) (((doc->state->http_handler).open)(doc, store, ctx, uri, ret))
# define mxslt_sapi_http_read(doc, ctx, buffer, len) (((doc->state->http_handler).read)(doc, ctx, buffer, len))
# define mxslt_sapi_http_close(doc, ctx) (((doc->state->http_handler).close)(doc, ctx))
# define mxslt_sapi_http_handle(doc, store, ctx, uri) (((doc->state->http_handler).handle)(doc, store, ctx, uri))

  /* Error reporting function */
# define mxslt_error(doc, ...) ((doc)->errhdlr((doc)->errctx, __VA_ARGS__))

  /* Returns the size of an array */
# define array_size(array) ((sizeof(array))/(sizeof(array[0])))
# define str_size(str) ((sizeof(str))-1)

  /* Ok, I'm lazy... */
# ifndef IS_BLANK
#  define IS_BLANK(val) (((val)== ' ') || ((val)== '\n') || ((val)=='\r') || ((val)=='\t'))
# endif 

/* ./parser/modxslt-screen-expr.lexer.c */
extern int mxslt_doc_screen_check(mxslt_doc_t *, char **, int flags);

/* ./modxslt-opr-cmp.c */
extern const struct mxslt_opr_t *mxslt_opr_cmp_lookup(char *str);
/* ./modxslt-opr-bool.c */
extern const struct mxslt_opr_t *mxslt_opr_bool_lookup(char *str);

/* ./modxslt-memory.c */
# ifndef MXSLT_DO_DEBUG
#  define xfree(ptr) free(ptr)
# else
extern void xfree(void *ptr);
# endif

# ifdef MXSLT_LIBXML_HTTP_STATUS
extern void * mxslt_http_real_open(mxslt_doc_t *, char *);
# else
#  define mxslt_http_real_open(doc, uri) xmlNanoHTTPMethodRedir(uri, NULL, NULL, NULL, NULL, NULL, 0)
# endif

extern void *xmalloc(size_t size);
extern void *xrealloc(const void *ptr, size_t size);
extern char *xstrdup(const char *str);
extern void *xstrndup(const char *str, size_t size);

/* ./modxslt-url.c */
extern int mxslt_doc_url_decode(char *url);
extern int mxslt_doc_param_urlparse(mxslt_doc_t *document, const char *query);

/* ./modxslt-doc.c */
extern void mxslt_doc_param_hdr_add(mxslt_doc_t * doc, char * uc_key, char * uc_value);
extern mxslt_table_status_e mxslt_doc_param_add(mxslt_doc_t *, char *, char *); 
extern mxslt_table_status_e mxslt_doc_param_get(mxslt_doc_t *, char *, char **);
extern int mxslt_get_static_attr(const char *content, const mxslt_attr_search_t *attr, char **store, int nelems);
extern void mxslt_doc_init(mxslt_doc_t *document, char * tsapi, mxslt_shoot_t *shoot, mxslt_recursion_t * rec,
			   void (*mxslt_doc_error)(void *, const char *, ...), void *errctx, void *ctx);
extern int mxslt_doc_load(mxslt_doc_t *document, xmlParserInputBufferPtr buf, char *filename, 
			  char *hostname, int port, char *path);
extern int mxslt_doc_done(mxslt_doc_t *document, mxslt_shoot_t *);
extern int mxslt_doc_parse(mxslt_doc_t *document, void (*header_set)(void *, char *, char *), void *);
extern int mxslt_doc_send(mxslt_doc_t *document, mxslt_callback_t *callback, void *ctx);
extern int mxslt_doc_parse_stylesheet(mxslt_doc_t *document, char *media, int flags);
extern xsltStylesheetPtr mxslt_doc_load_stylesheet_file(mxslt_doc_t *document, char *file);
extern int mxslt_doc_load_stylesheet(mxslt_doc_t *document, char *href);
extern int mxslt_doc_parse_pi(mxslt_doc_t *document);
extern void mxslt_xml_init(mxslt_shoot_t *, mxslt_http_handle_t, mxslt_http_open_t, 
			   mxslt_http_close_t, mxslt_http_read_t);
extern void mxslt_xml_done(mxslt_shoot_t * shoot);

/* ./modxslt-io.c */
extern xmlParserInputBufferPtr mxslt_create_input_file(mxslt_doc_t *doc, char *tmpfile);
extern xmlParserInputBufferPtr mxslt_create_input_fd(mxslt_doc_t *doc, int fd);

/* ./modxslt-libxml.c */
extern void mxslt_sax_errhdlr(void *ctx, const char *msg, ...);
extern void mxslt_sax_processing_instruction(void *ctx, const xmlChar *target, const xmlChar *data);
extern xmlParserInputPtr mxslt_sax_resolve_entity(void *ctx, const xmlChar *publicId, const xmlChar *systemId);
extern xmlDocPtr mxslt_doc_xml_parse(mxslt_doc_t *document, xmlParserInputBufferPtr buf, char *localfile);
extern xmlDocPtr mxslt_doc_xml_load_entity(mxslt_doc_t *document, char *localfile);
extern char * mxslt_yy_str_parse(mxslt_doc_t * document, char * start, int size);
extern xmlDocPtr mxslt_doc_xml_apply_stylesheet(mxslt_doc_t *, xsltStylesheetPtr, xmlDocPtr, const char **);

# if !defined(HAVE_LIBXML_HACK) && defined(HAVE_LIBXML_THREADS) 
extern int xmlSetGlobalState(xmlGlobalStatePtr state, xmlGlobalStatePtr *);
extern void xmlFreeGlobalState(xmlGlobalStatePtr state);
extern xmlGlobalStatePtr xmlNewGlobalState(void);
# endif /* !defined(HAVE_LIBXML_HACK) && defined(HAVE_LIBXML_THREADS) */

# ifdef HAVE_PTHREADS
extern mxslt_state_t * mxslt_get_state(void);
# else
#  define mxslt_get_state() mxslt_global_state
extern mxslt_state_t * mxslt_global_state;
# endif

extern int mxslt_http_match(const char *);
extern int mxslt_local_match(const char *);
extern void * mxslt_http_open(const char *);
extern void * mxslt_local_open(const char *);
extern int mxslt_http_read(void *, char *, int);
extern int mxslt_http_close(void *);
extern void mxslt_xml_load(void);
extern void mxslt_xml_unload(void);

# define mxslt_http_recurse_level(rec) ((rec)->rec_level)
extern int mxslt_http_recurse_allowed(mxslt_recursion_t *, const char * uri);
extern void mxslt_http_recurse_push(mxslt_recursion_t *, const char * uri); 
extern void mxslt_http_recurse_pop(mxslt_recursion_t *, int n); 
extern void mxslt_http_recurse_dump(mxslt_recursion_t *, void (*)(void *, char *, ...), void *);

extern void mxslt_state_init(mxslt_shoot_t *);
extern void mxslt_recursion_init(mxslt_recursion_t * rec);

#endif /* MXSLT_H */

