/* $Id: ruby_xslt_stylesheet.c,v 1.8 2002/10/09 18:27:51 sean Exp $ */

/* See the LICENSE file for copyright and distribution information. */

#include "libxslt.h"
#include "ruby_xslt_stylesheet.h"


VALUE ruby_xslt_stylesheet_apply(VALUE self) {
  ruby_xslt_stylesheet *xss;
  ruby_xml_document *rxd;

  Data_Get_Struct(self, ruby_xslt_stylesheet, xss);

  if (NIL_P(xss->xml_doc_obj))
    rb_raise(rb_eArgError, "Need a document object");

  Data_Get_Struct(xss->xml_doc_obj, ruby_xml_document, rxd);

  /* the third param should be an array of xsltApplyStylesheet
   * paramaters that is generated from a hash */
  xss->parsed = ruby_xml_document_new(cXMLDocument,
				      xsltApplyStylesheet(xss->xsp,
							  rxd->doc, NULL));

  if (xss->parsed == Qnil)
    return(Qfalse);
  else
    return(Qtrue);
}


VALUE ruby_xslt_stylesheet_debug(int argc, VALUE *argv, VALUE self) {
#ifdef LIBXML_DEBUG_ENABLED
  OpenFile *fptr;
  VALUE io;
  FILE *out;
  ruby_xml_document *parsed;
  ruby_xslt_stylesheet *xss;

  Data_Get_Struct(self, ruby_xslt_stylesheet, xss);
  if (NIL_P(xss->parsed))
    rb_raise(eXMLXSLTStylesheetRequireParsedDoc, "must have a parsed XML result");

  switch (argc) {
  case 0:
    io = rb_stdout;
    break;
  case 1:
    io = argv[0];
    if (rb_obj_is_kind_of(io, rb_cIO) == Qfalse)
      rb_raise(rb_eTypeError, "need an IO object");
    break;
  default:
    rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
  }

  Data_Get_Struct(xss->parsed, ruby_xml_document, parsed);
  if (parsed->doc == NULL)
    return(Qnil);

  GetOpenFile(io, fptr);
  rb_io_check_writable(fptr);
  out = GetWriteFile(fptr);
  xmlDebugDumpDocument(out, parsed->doc);
  return(Qtrue);
#else
  rb_warn("libxml/libxslt was compiled without debugging support.  Please recompile libxml/libxslt and their Ruby modules");
  return(Qfalse);
#endif
}


void ruby_xslt_stylesheet_free(ruby_xslt_stylesheet *xss) {
  if (xss->xsp != NULL)
    xsltFreeStylesheet(xss->xsp);

  free(xss);
}


void ruby_xslt_stylesheet_mark(ruby_xslt_stylesheet *xss) {
  if (!NIL_P(xss->filename))    rb_gc_mark(xss->filename);
  if (!NIL_P(xss->parsed))      rb_gc_mark(xss->parsed);
  if (!NIL_P(xss->xml_doc_obj)) rb_gc_mark(xss->xml_doc_obj);
}


VALUE ruby_xslt_stylesheet_new(VALUE class, xsltStylesheetPtr xsp) {
  ruby_xslt_stylesheet *xss;

  xss = ALLOC(ruby_xslt_stylesheet);
  xss->xsp = xsp;
  xss->xml_doc_obj = Qnil;
  xss->parsed = Qnil;

  return(Data_Wrap_Struct(cXSLTStylesheet, ruby_xslt_stylesheet_mark,
			  ruby_xslt_stylesheet_free, xss));
}


VALUE ruby_xslt_stylesheet_print(int argc, VALUE *argv, VALUE self) {
  OpenFile *fptr;
  VALUE io;
  FILE *out;
  ruby_xml_document *parsed;
  ruby_xslt_stylesheet *xss;
  int bytes;

  Data_Get_Struct(self, ruby_xslt_stylesheet, xss);
  if (NIL_P(xss->parsed))
    rb_raise(eXMLXSLTStylesheetRequireParsedDoc, "must have a parsed XML result");

  switch (argc) {
  case 0:
    io = rb_stdout;
    break;
  case 1:
    io = argv[0];
    if (rb_obj_is_kind_of(io, rb_cIO) == Qfalse)
      rb_raise(rb_eTypeError, "need an IO object");
    break;
  default:
    rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
  }

  Data_Get_Struct(xss->parsed, ruby_xml_document, parsed);
  if (parsed->doc == NULL)
    return(Qnil);

  GetOpenFile(io, fptr);
  rb_io_check_writable(fptr);
  out = GetWriteFile(fptr);
  bytes = xsltSaveResultToFile(out, parsed->doc, xss->xsp);

  return(INT2NUM(bytes));
}

VALUE ruby_xslt_stylesheet_to_s(VALUE self) {
  ruby_xml_document *parsed;
  ruby_xslt_stylesheet *xss;
  xmlChar *str;
  int len;

  Data_Get_Struct(self, ruby_xslt_stylesheet, xss);
  if (NIL_P(xss->parsed))
    rb_raise(eXMLXSLTStylesheetRequireParsedDoc, "must have a parsed XML result");
  Data_Get_Struct(xss->parsed, ruby_xml_document, parsed);
  if (parsed->doc == NULL)
    return(Qnil);

  xsltSaveResultToString(&str, &len, parsed->doc, xss->xsp);
  if (str == NULL)
    return(Qnil);
  else
    return(rb_str_new(str,len));
}


VALUE ruby_xslt_stylesheet_save(VALUE self, VALUE io) {
  ruby_xml_document *parsed;
  ruby_xslt_stylesheet *xss;
  OpenFile *fptr;

  if (rb_obj_is_kind_of(io, rb_cIO) == Qfalse)
    rb_raise(rb_eArgError, "Only accept IO objects for saving");

  GetOpenFile(io, fptr);

  Data_Get_Struct(self, ruby_xslt_stylesheet, xss);
  Data_Get_Struct(xss->parsed, ruby_xml_document, parsed);

  xsltSaveResultToFile(fptr->f, parsed->doc, xss->xsp);

  return(Qtrue);
}


void ruby_init_xslt_stylesheet(void) {
  cXSLTStylesheet = rb_define_class_under(cXSLT, "Stylesheet", rb_cObject);
  eXMLXSLTStylesheetRequireParsedDoc =
    rb_define_class_under(cXSLTStylesheet, "RequireParsedDoc", rb_eException);

  rb_define_method(cXSLTStylesheet, "apply", ruby_xslt_stylesheet_apply, 0);
  rb_define_method(cXSLTStylesheet, "debug", ruby_xslt_stylesheet_debug, -1);
  rb_define_method(cXSLTStylesheet, "print", ruby_xslt_stylesheet_print, -1);
  rb_define_method(cXSLTStylesheet, "to_s", ruby_xslt_stylesheet_to_s, 0);
  rb_define_method(cXSLTStylesheet, "save", ruby_xslt_stylesheet_save, 1);
}
