/* -*- Mode: c; c-basic-offset: 2 -*-
 *
 * raptor_serialize_turtle.c - Turtle serializer
 *
 * Copyright (C) 2006,2008 Dave Robillard
 * Copyright (C) 2004-2008 David Beckett http://www.dajobe.org/
 * Copyright (C) 2004-2005 University of Bristol, UK http://www.bristol.ac.uk/
 * Copyright (C) 2005 Steve Shepard steveshep@gmail.com
 * 
 * This package is Free Software and part of Redland http://librdf.org/
 * 
 * It is licensed under the following three licenses as alternatives:
 *   1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
 *   2. GNU General Public License (GPL) V2 or any newer version
 *   3. Apache License, V2.0 or any newer version
 * 
 * You may not use this file except in compliance with at least one of
 * the above three licenses.
 * 
 * See LICENSE.html or LICENSE.txt at the top of this package for the
 * complete terms and further detail along with the license texts for
 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
 * 
 */

#ifdef HAVE_CONFIG_H
#include <raptor_config.h>
#endif

#ifdef WIN32
#include <win32_raptor_config.h>
#endif


#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

/* Raptor includes */
#include "raptor.h"
#include "raptor_internal.h"


#define MAX_ASCII_INT_SIZE 13


/*
 * Raptor turtle serializer object
 */
typedef struct {
  raptor_namespace_stack *nstack;       /* Namespace stack */
  raptor_namespace *rdf_nspace;         /* the rdf: namespace */
  raptor_turtle_writer *turtle_writer;  /* where the xml is being written */
  raptor_sequence *namespaces;          /* User declared namespaces */
  raptor_sequence *subjects;            /* subject items */
  raptor_sequence *blanks;              /* blank subject items */
  raptor_avltree *nodes;                /* nodes */
  raptor_abbrev_node *rdf_type;         /* rdf:type uri */

  /* URI of rdf:XMLLiteral */
  raptor_uri* rdf_xml_literal_uri;

  /* URI of rdf:first */
  raptor_uri* rdf_first_uri;
  
  /* URI of rdf:rest */
  raptor_uri* rdf_rest_uri;

  /* URI of rdf:nil */
  raptor_uri* rdf_nil_uri;

  /* non zero if header is finished being written
   * (and thus no new namespaces can be declared).
   */
  int written_header;

  /* for labeling namespaces */
  int namespace_count;
} raptor_turtle_context;


/* prototypes for functions */

static int raptor_turtle_emit_resource(raptor_serializer *serializer,
                                       raptor_abbrev_node* node,
                                       int depth);

static int raptor_turtle_emit_literal(raptor_serializer *serializer,
                                      raptor_abbrev_node* node,
                                      int depth);
static int raptor_turtle_emit_xml_literal(raptor_serializer *serializer,
                                          raptor_abbrev_node* node,
                                          int depth);
static int raptor_turtle_emit_blank(raptor_serializer *serializer,
                                    raptor_abbrev_node* node,
                                    int depth);
static int raptor_turtle_emit_subject_list_items(raptor_serializer* serializer,
                                                 raptor_abbrev_subject* subject,
                                                 int depth);
static int raptor_turtle_emit_subject_collection_items(raptor_serializer* serializer,
                                                       raptor_abbrev_subject* subject,
                                                       int depth);
static int raptor_turtle_emit_subject_properties(raptor_serializer *serializer,
                                                 raptor_abbrev_subject* subject,
                                                 int depth);
static int raptor_turtle_emit_subject(raptor_serializer *serializer,
                                      raptor_abbrev_subject* subject,
                                      int depth);
static int raptor_turtle_emit(raptor_serializer *serializer);

static int raptor_turtle_serialize_init(raptor_serializer* serializer,
                                        const char *name);
static void raptor_turtle_serialize_terminate(raptor_serializer* serializer);
static int raptor_turtle_serialize_declare_namespace(raptor_serializer* serializer, 
                                                     raptor_uri *uri,
                                                     const unsigned char *prefix);
static int raptor_turtle_serialize_start(raptor_serializer* serializer);
static int raptor_turtle_serialize_statement(raptor_serializer* serializer, 
                                             const raptor_statement *statement);

static int raptor_turtle_serialize_end(raptor_serializer* serializer);
static void raptor_turtle_serialize_finish_factory(raptor_serializer_factory* factory);


/*
 * raptor_turtle_emit_resource:
 * @serializer: #raptor_serializer object
 * @node: resource node
 * @depth: depth into tree
 * 
 * Emit a description of a resource using an XML Element
 * 
 * Return value: non-0 on failure
 **/
static int
raptor_turtle_emit_resource(raptor_serializer *serializer,
                            raptor_abbrev_node* node,
                            int depth) 
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  raptor_turtle_writer *turtle_writer = context->turtle_writer;

  raptor_qname* qname = NULL;

  RAPTOR_DEBUG5("Emitting resource node %p refcount %d subject %d object %d\n",
                node, 
                node->ref_count, node->count_as_subject, node->count_as_object);

  if(node->type != RAPTOR_IDENTIFIER_TYPE_RESOURCE)
    return 1;

  qname = raptor_namespaces_qname_from_uri(context->nstack,
                                           node->value.resource.uri, 10);

  if(qname) {
    raptor_turtle_writer_qname(turtle_writer, qname);
    raptor_free_qname(qname);
  } else {
    raptor_turtle_writer_reference(turtle_writer, node->value.resource.uri);
  }

  RAPTOR_DEBUG2("Emitted %p\n", node);
  
  return 0;
}


/*
 * raptor_turtle_emit_literal:
 * @serializer: #raptor_serializer object
 * @node: literal node
 * @depth: depth into tree
 * 
 * Emit a description of a literal (object).
 * 
 * Return value: non-0 on failure
 **/
static int
raptor_turtle_emit_literal(raptor_serializer *serializer,
                           raptor_abbrev_node* node,
                           int depth)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  raptor_turtle_writer *turtle_writer = context->turtle_writer;
  int rc=0;
  
  RAPTOR_DEBUG5("Emitting literal node %p refcount %d subject %d object %d\n",
                node, 
                node->ref_count, node->count_as_subject, node->count_as_object);

  if(node->type != RAPTOR_IDENTIFIER_TYPE_LITERAL)
    return 1;
  
  rc=raptor_turtle_writer_literal(turtle_writer, context->nstack,
                                  node->value.literal.string,
                                  node->value.literal.language, 
                                  node->value.literal.datatype);

  RAPTOR_DEBUG2("Emitted %p\n", node);
  
  return rc;
}


/*
 * raptor_turtle_emit_xml_literal:
 * @serializer: #raptor_serializer object
 * @node: XML literal node
 * @depth: depth into tree
 * 
 * Emit a description of a literal using an XML Element
 * 
 * Return value: non-0 on failure
 **/
static int
raptor_turtle_emit_xml_literal(raptor_serializer *serializer,
                               raptor_abbrev_node* node,
                               int depth) 
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  raptor_turtle_writer *turtle_writer = context->turtle_writer;
  raptor_uri* type_uri;
  int rc=0;
  
  RAPTOR_DEBUG5("Emitting XML literal node %p refcount %d subject %d object %d\n",
                node, 
                node->ref_count, node->count_as_subject, node->count_as_object);

  if(node->type != RAPTOR_IDENTIFIER_TYPE_XML_LITERAL)
    return 1;

  type_uri = raptor_new_uri((const unsigned char*)
    "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral");
  
  rc=raptor_turtle_writer_literal(turtle_writer, context->nstack,
                                  node->value.literal.string, NULL, type_uri);

  raptor_free_uri(type_uri);

  return rc;
}


/*
 * raptor_turtle_emit_blank:
 * @serializer: #raptor_serializer object
 * @node: blank node
 * @depth: depth into tree
 * 
 * Emit a description of a blank node
 * 
 * Return value: non-0 on failure
 **/
static int
raptor_turtle_emit_blank(raptor_serializer *serializer,
                         raptor_abbrev_node* node,
                         int depth) 
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  int rc=0;
  
  RAPTOR_DEBUG5("Emitting blank node %p refcount %d subject %d object %d\n",
                node, 
                node->ref_count, node->count_as_subject, node->count_as_object);
  
  if(node->type != RAPTOR_IDENTIFIER_TYPE_ANONYMOUS)
    return 1;
  
  if((node->count_as_subject == 1 && node->count_as_object == 1)) {
    /* If this is only used as a 1 subject and object or never
     * used as a subject or never used as an object, it never need
     * be referenced with an explicit name */
    int idx;
    raptor_abbrev_subject* blank;

    blank = raptor_abbrev_subject_find(context->blanks,
                                       node->type,
                                       node->value.blank.string, &idx);
    if(blank) {
      rc = raptor_turtle_emit_subject(serializer, blank, depth+1);
      raptor_sequence_set_at(context->blanks, idx, NULL);
    }
          
  } else {
    /* Blank node that needs an explicit name */
    const unsigned char *node_id = node->value.blank.string;

    raptor_turtle_writer_raw(context->turtle_writer, (const unsigned char*)"_:");
    raptor_turtle_writer_raw(context->turtle_writer, node_id);
  }

  RAPTOR_DEBUG2("Emitted %p\n", node);
  
  return rc;
}


/*
 * raptor_turtle_emit_subject_list_items:
 * @serializer: #raptor_serializer object
 * @subject: subject node
 * @depth: depth into tree
 * 
 * Emit an rdf list of items (rdf:li) about a subject node.
 * 
 * Return value: non-0 on failure
 **/
static int
raptor_turtle_emit_subject_list_items(raptor_serializer* serializer,
                                      raptor_abbrev_subject* subject,
                                      int depth)
{
  int rv = 0;
  int i=0;
  
  RAPTOR_DEBUG5("Emitting subject list items for node %p refcount %d subject %d object %d\n", 
                subject->node,
                subject->node->ref_count, subject->node->count_as_subject, 
                subject->node->count_as_object);

  while(!rv && i < raptor_sequence_size(subject->list_items)) {
    raptor_abbrev_node* object;
    
    object = (raptor_abbrev_node*)raptor_sequence_get_at(subject->list_items,
                                                          i++);
    if(!object)
      continue;
    
    switch(object->type) {
      case RAPTOR_IDENTIFIER_TYPE_RESOURCE:
        rv = raptor_turtle_emit_resource(serializer, object, depth+1);
        break;
          
      case RAPTOR_IDENTIFIER_TYPE_LITERAL:
        rv = raptor_turtle_emit_literal(serializer, object, depth+1);
        break;
          
      case RAPTOR_IDENTIFIER_TYPE_XML_LITERAL:
        rv = raptor_turtle_emit_xml_literal(serializer, object, depth+1);
        break;
          
      case RAPTOR_IDENTIFIER_TYPE_ANONYMOUS:
        rv = raptor_turtle_emit_blank(serializer, object, depth+1);
        break;

      case RAPTOR_IDENTIFIER_TYPE_ORDINAL:
        /* ordinals should never appear as an object with current parsers */
      case RAPTOR_IDENTIFIER_TYPE_PREDICATE:
        /* predicates should never appear as an object */
      case RAPTOR_IDENTIFIER_TYPE_UNKNOWN:
      default:
        RAPTOR_FATAL1("Unsupported identifier type\n");
        break;

    }
    
  }
  
  return rv;
}


/*
 * raptor_turtle_emit_subject_collection_items:
 * @serializer: #raptor_serializer object
 * @subject: subject node
 * @depth: depth into tree
 * 
 * Emit an abbreviated rdf collection of items (rdf:first, rdf:rest) about a subject node.
 * 
 * Return value: non-0 on failure
 **/
static int
raptor_turtle_emit_subject_collection_items(raptor_serializer* serializer,
                                            raptor_abbrev_subject* subject,
                                            int depth)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  int rv = 0;
  int idx;
  raptor_avltree_iterator* iter=NULL;
  int i;

  RAPTOR_DEBUG5("Emitting subject collection items for node %p refcount %d subject %d object %d\n", 
                subject->node,
                subject->node->ref_count, subject->node->count_as_subject, 
                subject->node->count_as_object);

  
  for(i=0, (iter=raptor_new_avltree_iterator(subject->properties, NULL, NULL, 1));
      iter && !rv;
      i++, (rv=raptor_avltree_iterator_next(iter))) {
    raptor_abbrev_node** nodes;
    raptor_abbrev_node* predicate;
    raptor_abbrev_node* object;

    nodes=(raptor_abbrev_node**)raptor_avltree_iterator_get(iter);
    if(!nodes)
      break;
    predicate= nodes[0];
    object= nodes[1];
    
    if(!raptor_uri_equals(predicate->value.resource.uri, 
                          context->rdf_first_uri)) {
      raptor_serializer_error(serializer,
                              "Malformed collection - first predicate is not rdf:first");
      return 1;
    }
    
    if(!object)
      continue;
    
    if(i > 0)
      raptor_turtle_writer_newline(context->turtle_writer);
    
    switch(object->type) {
      case RAPTOR_IDENTIFIER_TYPE_RESOURCE:
        rv = raptor_turtle_emit_resource(serializer, object, depth+1);
        break;
          
      case RAPTOR_IDENTIFIER_TYPE_LITERAL:
        rv = raptor_turtle_emit_literal(serializer, object, depth+1);
        break;
          
      case RAPTOR_IDENTIFIER_TYPE_XML_LITERAL:
        rv = raptor_turtle_emit_xml_literal(serializer, object, depth+1);
        break;
          
      case RAPTOR_IDENTIFIER_TYPE_ANONYMOUS:
        rv = raptor_turtle_emit_blank(serializer, object, depth+1);
        break;

      case RAPTOR_IDENTIFIER_TYPE_ORDINAL:
        /* ordinals should never appear as an object with current parsers */
      case RAPTOR_IDENTIFIER_TYPE_PREDICATE:
        /* predicates should never appear as an object */
      case RAPTOR_IDENTIFIER_TYPE_UNKNOWN:
      default:
        RAPTOR_FATAL1("Unsupported identifier type\n");
        break;
    }

    /* last item */
    rv=raptor_avltree_iterator_next(iter);
    if(rv)
      break;

    nodes=(raptor_abbrev_node**)raptor_avltree_iterator_get(iter);
    predicate = nodes[0];
    object = nodes[1];

    if(!raptor_uri_equals(predicate->value.resource.uri, context->rdf_rest_uri)) {
      raptor_serializer_error(serializer,
                              "Malformed collection - second predicate is not rdf:rest");
      return 1;
    }
    
    if(object->type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS) {
      subject = raptor_abbrev_subject_find(context->blanks, object->type,
                                         object->value.blank.string, &idx);

      if(!subject) {
        raptor_serializer_error(serializer,
                            "Malformed collection - could not find subject for rdf:rest");
        return 1;
      }
    } else {
      if(object->type != RAPTOR_IDENTIFIER_TYPE_RESOURCE ||
         !raptor_uri_equals(object->value.resource.uri, context->rdf_nil_uri)) {
        raptor_serializer_error(serializer,
                                "Malformed collection - last rdf:rest resource is not rdf:nil");
        return 1;
      }
      break;
    }
  }
  if(iter)
    raptor_free_avltree_iterator(iter);
  
  return rv;
}



/*
 * raptor_turtle_emit_subject_properties:
 * @serializer: #raptor_serializer object
 * @subject: subject node
 * @depth: depth into tree
 * 
 * Emit the properties about a subject node.
 * 
 * Return value: non-0 on failure
 **/
static int
raptor_turtle_emit_subject_properties(raptor_serializer* serializer,
                                      raptor_abbrev_subject* subject,
                                      int depth)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  raptor_turtle_writer *turtle_writer = context->turtle_writer;
  raptor_abbrev_node* last_predicate=NULL;
  int rv = 0;  
  raptor_avltree_iterator* iter=NULL;
  int i;

  RAPTOR_DEBUG5("Emitting subject properties for node %p refcount %d subject %d object %d\n", 
                subject->node, subject->node->ref_count, 
                subject->node->count_as_subject,
                subject->node->count_as_object);

  /* Emit any rdf:_n properties collected */
  if(raptor_sequence_size(subject->list_items) > 0)
    rv = raptor_turtle_emit_subject_list_items(serializer, subject, depth+1);

  for(i=0, (iter=raptor_new_avltree_iterator(subject->properties, NULL, NULL, 1));
      iter && !rv;
      i++, (rv=raptor_avltree_iterator_next(iter))) {
    raptor_abbrev_node** nodes;
    raptor_abbrev_node* predicate;
    raptor_abbrev_node* object;
    raptor_qname *qname;

    nodes=(raptor_abbrev_node**)raptor_avltree_iterator_get(iter);
    if(!nodes)
      break;
    predicate= nodes[0];
    object= nodes[1];

    if(!(last_predicate && raptor_abbrev_node_equals(predicate, last_predicate))) {
      /* no object list abbreviation possible, terminate last object */
      if(last_predicate) {
        raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)" ;");
        raptor_turtle_writer_newline(turtle_writer);
      }

      if(predicate->type == RAPTOR_IDENTIFIER_TYPE_ORDINAL) {
        /* we should only get here in rare cases -- usually when there
         * are multiple ordinals with the same value. */

        unsigned char uri_string[MAX_ASCII_INT_SIZE + 2];

        sprintf((char*)uri_string, "_%d", predicate->value.ordinal.ordinal);

        qname = raptor_new_qname_from_namespace_local_name(context->rdf_nspace,
                                                           uri_string, NULL);

      } else {
        qname = raptor_namespaces_qname_from_uri(context->nstack,
                                                 predicate->value.resource.uri, 10);
      
      }

      if(raptor_abbrev_node_equals(predicate, context->rdf_type))
        raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)"a");
      else if(qname)
        raptor_turtle_writer_qname(turtle_writer, qname);
      else
        raptor_turtle_writer_reference(turtle_writer, predicate->value.resource.uri);

      raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)" ");
    
      if(qname)
        raptor_free_qname(qname);
    } else
      raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)", ");


    switch(object->type) {
      case RAPTOR_IDENTIFIER_TYPE_RESOURCE:
        rv = raptor_turtle_emit_resource(serializer, object, depth+1);
        break;
          
      case RAPTOR_IDENTIFIER_TYPE_LITERAL:
        rv = raptor_turtle_emit_literal(serializer, object, depth+1);
        break;
          
      case RAPTOR_IDENTIFIER_TYPE_ANONYMOUS:
        rv = raptor_turtle_emit_blank(serializer, object, depth+1);
        break;
          
      case RAPTOR_IDENTIFIER_TYPE_XML_LITERAL:
        rv = raptor_turtle_emit_xml_literal(serializer, object, depth+1);
        break;

      case RAPTOR_IDENTIFIER_TYPE_ORDINAL:
        /* ordinals should never appear as an object with current parsers */
      case RAPTOR_IDENTIFIER_TYPE_PREDICATE:
        /* predicates should never appear as an object */
      case RAPTOR_IDENTIFIER_TYPE_UNKNOWN:
      default:
        RAPTOR_FATAL1("Unsupported identifier type\n");
        break;
    }    
    
    last_predicate = predicate;
  }

  if (iter)
    raptor_free_avltree_iterator(iter);
         
  return rv;
}

/*
 * raptor_turtle_emit_subject:
 * @serializer: #raptor_serializer object
 * @subject: subject node
 * @depth: depth into tree
 * 
 * Emit a subject node
 * 
 * Return value: non-0 on failure
 **/
static int
raptor_turtle_emit_subject(raptor_serializer *serializer,
                           raptor_abbrev_subject* subject,
                           int depth) 
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  raptor_turtle_writer* turtle_writer=context->turtle_writer;
  int blank = 1;
  int collection = 0;
  int rc = 0;
  
  RAPTOR_DEBUG5("Emitting subject node %p refcount %d subject %d object %d\n", 
                subject->node,
                subject->node->ref_count, 
                subject->node->count_as_subject,
                subject->node->count_as_object);

  if(!depth &&
     subject->node->type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS &&
     subject->node->count_as_subject == 1 &&
     subject->node->count_as_object == 1) {
    RAPTOR_DEBUG2("Skipping subject node %p\n", subject->node);
    return 0;
  }
  
  if(raptor_avltree_size(subject->properties) == 0) {
    RAPTOR_DEBUG2("Skipping subject node %p\n", subject->node);
    return 0;
  }

  /* check if we can do collection abbreviation */
  if(raptor_avltree_size(subject->properties) >= 4) {
    raptor_avltree_iterator* iter=NULL;
    raptor_abbrev_node* pred1;
    raptor_abbrev_node* pred2;

    iter=raptor_new_avltree_iterator(subject->properties, NULL, NULL, 1);
    if(!iter)
      return 1;
    pred1=((raptor_abbrev_node**)raptor_avltree_iterator_get(iter))[0];
    raptor_avltree_iterator_next(iter);
    pred2=((raptor_abbrev_node**)raptor_avltree_iterator_get(iter))[0];
    raptor_free_avltree_iterator(iter);

    if(pred1->type == RAPTOR_IDENTIFIER_TYPE_RESOURCE &&
       pred2->type == RAPTOR_IDENTIFIER_TYPE_RESOURCE &&
       (
        (raptor_uri_equals(pred1->value.resource.uri, context->rdf_first_uri) &&
         raptor_uri_equals(pred2->value.resource.uri, context->rdf_rest_uri))
        ||
        (raptor_uri_equals(pred2->value.resource.uri, context->rdf_first_uri) &&
         raptor_uri_equals(pred1->value.resource.uri, context->rdf_rest_uri))
        )
       ) {
      collection = 1;
    }
  }

  /* emit the subject node */
  if(subject->node->type == RAPTOR_IDENTIFIER_TYPE_RESOURCE) {
    rc= raptor_turtle_emit_resource(serializer, subject->node, depth+1);
    if(rc)
      return rc;
    blank = 0;
    
  } else if(subject->node->type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS) {
    if((subject->node->count_as_subject == 1 && 
        subject->node->count_as_object == 0) && depth > 1) { 
      blank = 1;
    } else if(subject->node->count_as_object == 0) {
      raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)"[]");
      blank = 0;
    } else if(!collection && subject->node->count_as_object > 1) {
      /* Referred to (used as an object), so needs a nodeID */
      const unsigned char* genid = subject->node->value.blank.string;
      size_t len = strlen((const char*)genid);
      unsigned char* subject_str;
      subject_str= (unsigned char *)RAPTOR_MALLOC(cstring, len+3);
      if(!subject_str)
        return 1;

      subject_str[0]='_';
      subject_str[1]=':';
      strncpy((char*)&subject_str[2], (const char*)genid, len+1);
      raptor_turtle_writer_raw(turtle_writer, subject_str);
      RAPTOR_FREE(cstring, subject_str);
    }
  } else if(subject->node->type == RAPTOR_IDENTIFIER_TYPE_ORDINAL) {
    unsigned char* subject_str;
    subject_str = (unsigned char *)RAPTOR_MALLOC(string,
                                                 raptor_rdf_namespace_uri_len + MAX_ASCII_INT_SIZE + 2);
    if(!subject_str)
      return 1;
    
    sprintf((char*)subject, "%s_%d", raptor_rdf_namespace_uri,
            subject->node->value.ordinal.ordinal);
      
    raptor_turtle_writer_raw(turtle_writer, subject_str);
    RAPTOR_FREE(cstring, subject_str);
    return blank = 0;
  } 

  if(collection) {
    raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)"(");
    
    raptor_turtle_writer_increase_indent(turtle_writer);
    
    rc=raptor_turtle_emit_subject_collection_items(serializer, subject, depth+1);
    
    raptor_turtle_writer_decrease_indent(turtle_writer);
    raptor_turtle_writer_newline(turtle_writer);
    
    raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)")");

  } else {
    if(blank && depth > 1)
      raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)"[");
    
    raptor_turtle_writer_increase_indent(turtle_writer);
    raptor_turtle_writer_newline(turtle_writer);

    raptor_turtle_emit_subject_properties(serializer, subject, depth+1);
    
    raptor_turtle_writer_decrease_indent(turtle_writer);
    
    if(blank && depth > 1) {
      raptor_turtle_writer_newline(turtle_writer);
      raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)"]");
    }
  }

  if(depth == 0) {
    /* NOTE: the space before the . here MUST be there or statements
     * that end in a numeric literal will be interpreted incorrectly
     * (the "." will be parsed as part of the literal and statement
     * left unterminated) 
     */
    raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)" .");
    raptor_turtle_writer_newline(turtle_writer);
    raptor_turtle_writer_newline(turtle_writer);
  }

  return rc;
}


/*
 * raptor_turtle_emit:
 * @serializer: #raptor_serializer object
 * 
 * Emit Turtle for all stored triples.
 * 
 * Return value: non-0 on failure
 **/
static int
raptor_turtle_emit(raptor_serializer *serializer)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  raptor_abbrev_subject* subject;
  raptor_abbrev_subject* blank;
  int i;
  int rc;
  
  for(i=0; i < raptor_sequence_size(context->subjects); i++) {
    subject = (raptor_abbrev_subject* )raptor_sequence_get_at(context->subjects, i);
    if(subject) {
      rc= raptor_turtle_emit_subject(serializer, subject, 0);
      if(rc)
        return rc;
    }
  }
  
  /* Emit any remaining blank nodes */
  for(i=0; i < raptor_sequence_size(context->blanks); i++) {
    blank = (raptor_abbrev_subject* )raptor_sequence_get_at(context->blanks, i);
    if(blank) {
      rc= raptor_turtle_emit_subject(serializer, blank, 0);
      if(rc)
        return rc;
    }
  }
  
  return 0;
}


/*
 * raptor serializer Turtle implementation
 */


/* create a new serializer */
static int
raptor_turtle_serialize_init(raptor_serializer* serializer, const char *name)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  const raptor_uri_handler *uri_handler;
  raptor_uri *rdf_type_uri;
  void *uri_context;

  raptor_uri_get_handler(&uri_handler, &uri_context);
  context->nstack=raptor_new_namespaces(uri_handler, uri_context,
                                        (raptor_simple_message_handler)raptor_serializer_simple_error,
                                        serializer,
                                        1);
  if(!context->nstack)
    return 1;
  context->rdf_nspace=raptor_new_namespace(context->nstack,
                                           (const unsigned char*)"rdf",
                                           (const unsigned char*)raptor_rdf_namespace_uri,
                                           0);

  context->namespaces=raptor_new_sequence(NULL, NULL);

  context->subjects =
    raptor_new_sequence((raptor_sequence_free_handler *)raptor_free_abbrev_subject,NULL);

  context->blanks =
    raptor_new_sequence((raptor_sequence_free_handler *)raptor_free_abbrev_subject,NULL);

  context->nodes =
    raptor_new_avltree((raptor_data_compare_function)raptor_abbrev_node_cmp,
                       (raptor_data_free_function)raptor_free_abbrev_node, 0);

  rdf_type_uri = raptor_new_uri_for_rdf_concept("type");
  if(rdf_type_uri) {
    context->rdf_type = raptor_new_abbrev_node(RAPTOR_IDENTIFIER_TYPE_RESOURCE,
                                               rdf_type_uri, NULL, NULL);
    raptor_free_uri(rdf_type_uri);
  } else
    context->rdf_type = NULL;

  context->rdf_xml_literal_uri=raptor_new_uri(raptor_xml_literal_datatype_uri_string);
  context->rdf_first_uri=raptor_new_uri((const unsigned char*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#first");
  context->rdf_rest_uri=raptor_new_uri((const unsigned char*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest");
  context->rdf_nil_uri=raptor_new_uri((const unsigned char*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#nil");

  if(!context->rdf_nspace || !context->namespaces ||
     !context->subjects || !context->blanks || !context->nodes ||
     !context->rdf_xml_literal_uri || !context->rdf_first_uri ||
     !context->rdf_rest_uri || !context->rdf_nil_uri || !context->rdf_type)
  {
    raptor_turtle_serialize_terminate(serializer);
    return 1;
  }

  /* Note: item 0 in the list is rdf:RDF's namespace */
  if(raptor_sequence_push(context->namespaces, context->rdf_nspace)) {
    raptor_turtle_serialize_terminate(serializer);
    return 1;
  }

  return 0;
}


/* destroy a serializer */
static void
raptor_turtle_serialize_terminate(raptor_serializer* serializer)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;

  if(context->turtle_writer) {
    raptor_free_turtle_writer(context->turtle_writer);
    context->turtle_writer=NULL;
  }

  if(context->rdf_nspace) {
    raptor_free_namespace(context->rdf_nspace);
    context->rdf_nspace=NULL;
  }

  if(context->namespaces) {
    int i;

    /* Note: item 0 in the list is rdf:RDF's namespace and freed above */
    for(i=1; i< raptor_sequence_size(context->namespaces); i++) {
      raptor_namespace* ns;
      ns =(raptor_namespace*)raptor_sequence_get_at(context->namespaces, i);
      if(ns)
        raptor_free_namespace(ns);
    }
    raptor_free_sequence(context->namespaces);
    context->namespaces=NULL;
  }

  if(context->subjects) {
    raptor_free_sequence(context->subjects);
    context->subjects=NULL;
  }

  if(context->blanks) {
    raptor_free_sequence(context->blanks);
    context->blanks=NULL;
  }

  if(context->nodes) {
    raptor_free_avltree(context->nodes);
    context->nodes=NULL;
  }

  if(context->nstack) {
    raptor_free_namespaces(context->nstack);
    context->nstack=NULL;
  }

  if(context->rdf_type) {
    raptor_free_abbrev_node(context->rdf_type);
    context->rdf_type=NULL;
  }

  if(context->rdf_xml_literal_uri) {
    raptor_free_uri(context->rdf_xml_literal_uri);
    context->rdf_xml_literal_uri=NULL;
  }

  if(context->rdf_first_uri) {
    raptor_free_uri(context->rdf_first_uri);
    context->rdf_first_uri=NULL;
  }

  if(context->rdf_rest_uri) {
    raptor_free_uri(context->rdf_rest_uri);
    context->rdf_rest_uri=NULL;
  }

  if(context->rdf_nil_uri) {
    raptor_free_uri(context->rdf_nil_uri);
    context->rdf_nil_uri=NULL;
  }
}


#define TURTLE_NAMESPACE_DEPTH 0

/* add a namespace */
static int
raptor_turtle_serialize_declare_namespace_from_namespace(raptor_serializer* serializer, 
                                                         raptor_namespace *nspace)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  int i;
 
  if(context->written_header)
    return 1;
  
  for(i=0; i< raptor_sequence_size(context->namespaces); i++) {
    raptor_namespace* ns;
    ns=(raptor_namespace*)raptor_sequence_get_at(context->namespaces, i);

    /* If prefix is already declared, ignore it */
    if(!ns->prefix && !nspace->prefix)
      return 1;
    
    if(ns->prefix && nspace->prefix && 
       !strcmp((const char*)ns->prefix, (const char*)nspace->prefix))
      return 1;

    if(ns->uri && nspace->uri &&
       raptor_uri_equals(ns->uri, nspace->uri))
      return 1;
  }

  nspace=raptor_new_namespace_from_uri(context->nstack,
                                       nspace->prefix, nspace->uri,
                                       TURTLE_NAMESPACE_DEPTH);
  if(!nspace)
    return 1;
  
  raptor_sequence_push(context->namespaces, nspace);
  return 0;
}


/* add a namespace */
static int
raptor_turtle_serialize_declare_namespace(raptor_serializer* serializer, 
                                          raptor_uri *uri,
                                          const unsigned char *prefix)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  raptor_namespace *ns;
  int rc;
  
  ns=raptor_new_namespace_from_uri(context->nstack, prefix, uri, 
                                   TURTLE_NAMESPACE_DEPTH);

  rc=raptor_turtle_serialize_declare_namespace_from_namespace(serializer, ns);
  raptor_free_namespace(ns);
  
  return rc;
}


/* start a serialize */
static int
raptor_turtle_serialize_start(raptor_serializer* serializer)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  raptor_turtle_writer* turtle_writer;
  const raptor_uri_handler *uri_handler;
  void *uri_context;

  raptor_uri_get_handler(&uri_handler, &uri_context);

  if(context->turtle_writer)
    raptor_free_turtle_writer(context->turtle_writer);

  turtle_writer=raptor_new_turtle_writer(serializer->base_uri,
                                         serializer->feature_write_base_uri,
                                         context->nstack,
                                         uri_handler, uri_context,
                                         serializer->iostream,
                                         (raptor_simple_message_handler)raptor_serializer_simple_error,
                                         serializer);
  if(!turtle_writer)
    return 1;

  raptor_turtle_writer_set_feature(turtle_writer,
                                   RAPTOR_FEATURE_WRITER_AUTO_INDENT,1);
  raptor_turtle_writer_set_feature(turtle_writer,
                                   RAPTOR_FEATURE_WRITER_INDENT_WIDTH,2);
  
  context->turtle_writer=turtle_writer;

  return 0;
}

static void
raptor_turtle_ensure_writen_header(raptor_serializer* serializer,
                                   raptor_turtle_context* context) 
{
  int i;

  if(context->written_header)
    return;
  
  if(!context->turtle_writer)
    return;

  for(i=0; i< raptor_sequence_size(context->namespaces); i++) {
    raptor_namespace* ns;
    ns=(raptor_namespace*)raptor_sequence_get_at(context->namespaces, i);
    raptor_turtle_writer_namespace_prefix(context->turtle_writer, ns);
    raptor_namespace_copy(context->nstack, ns, 0);
  }
  
  raptor_turtle_writer_raw(context->turtle_writer, (const unsigned char*)"\n");

  context->written_header=1;
}

/* serialize a statement */
static int
raptor_turtle_serialize_statement(raptor_serializer* serializer, 
                                  const raptor_statement *statement)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  raptor_abbrev_subject* subject = NULL;
  raptor_abbrev_node* predicate = NULL;
  raptor_abbrev_node* object = NULL;
  int rv;
  raptor_identifier_type object_type;
  int subject_created = 0;
  int predicate_created = 0;
  int object_created = 0;

  if(!(statement->subject_type == RAPTOR_IDENTIFIER_TYPE_RESOURCE ||
       statement->subject_type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS ||
       statement->subject_type == RAPTOR_IDENTIFIER_TYPE_ORDINAL)) {
    raptor_serializer_error(serializer,
                            "Do not know how to serialize node type %d\n",
                            statement->subject_type);
    return 1;
  }  

  subject = raptor_abbrev_subject_lookup(context->nodes, context->subjects,
                                         context->blanks,
                                         statement->subject_type,
                                         statement->subject,
                                         &subject_created);
  if(!subject)
    return 1;

  object_type=statement->object_type;
  if(object_type == RAPTOR_IDENTIFIER_TYPE_LITERAL) {
    if(statement->object_literal_datatype &&
       raptor_uri_equals(statement->object_literal_datatype, 
                         context->rdf_xml_literal_uri))
      object_type = RAPTOR_IDENTIFIER_TYPE_XML_LITERAL;
  }


  if(!(object_type == RAPTOR_IDENTIFIER_TYPE_RESOURCE ||
       object_type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS ||
       object_type == RAPTOR_IDENTIFIER_TYPE_LITERAL ||
       object_type == RAPTOR_IDENTIFIER_TYPE_XML_LITERAL || 
       object_type == RAPTOR_IDENTIFIER_TYPE_ORDINAL)) {
    raptor_serializer_error(serializer,
                            "Cannot serialize a triple with object node type %d\n",
                            object_type);
    return 1;
  }

  object = raptor_abbrev_node_lookup(context->nodes, object_type,
                                     statement->object,
                                     statement->object_literal_datatype,
                                     statement->object_literal_language,
                                     &object_created);
  if(!object)
    return 1;          


  if((statement->predicate_type == RAPTOR_IDENTIFIER_TYPE_PREDICATE) ||
     (statement->predicate_type == RAPTOR_IDENTIFIER_TYPE_RESOURCE)) {
    predicate = raptor_abbrev_node_lookup(context->nodes,
                                          statement->predicate_type,
                                          statement->predicate, NULL, NULL,
                                          &predicate_created);
    if(!predicate)
      return 1;
	      
    rv = raptor_abbrev_subject_add_property(subject, predicate, object);
    if(rv < 0) {
      raptor_serializer_error(serializer,
                              "Unable to add properties to subject %p\n",
                              subject);
      return rv;
    }
  
  } else if(statement->predicate_type == RAPTOR_IDENTIFIER_TYPE_ORDINAL) {
    int idx = *(int*)statement->predicate;
    rv = raptor_abbrev_subject_add_list_element(subject, idx, object);
    if(rv) {
      /* An ordinal might already exist at that location, the fallback
       * is to just put in the properties list */
      predicate = raptor_abbrev_node_lookup(context->nodes,
                                            statement->predicate_type,
                                            statement->predicate, NULL, NULL,
                                            &predicate_created);
      if(!predicate)
        return 1;

      rv = raptor_abbrev_subject_add_property(subject, predicate, object);
      if(rv < 0) {
        raptor_serializer_error(serializer,
                                "Unable to add properties to subject %p\n",
                                subject);
        return rv;
      }
    }
  } else {
    raptor_serializer_error(serializer,
                            "Do not know how to serialize node type %d\n",
                            statement->predicate_type);
    return 1;
  }
  
  if(object_type == RAPTOR_IDENTIFIER_TYPE_RESOURCE ||
     object_type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS)
    object->count_as_object++;

  return 0;
}


/* end a serialize */
static int
raptor_turtle_serialize_end(raptor_serializer* serializer)
{
  raptor_turtle_context* context=(raptor_turtle_context*)serializer->context;
  
  raptor_turtle_ensure_writen_header(serializer, context);
  
  raptor_turtle_emit(serializer);  

  /* reset serializer for reuse */
  context->written_header=0;

  return 0;
}


/* finish the serializer factory */
static void
raptor_turtle_serialize_finish_factory(raptor_serializer_factory* factory)
{
  /* NOP */
}


static int
raptor_turtle_serializer_register_factory(raptor_serializer_factory *factory)
{
  factory->context_length     = sizeof(raptor_turtle_context);
  
  factory->init                = raptor_turtle_serialize_init;
  factory->terminate           = raptor_turtle_serialize_terminate;
  factory->declare_namespace   = raptor_turtle_serialize_declare_namespace;
  factory->declare_namespace_from_namespace   = raptor_turtle_serialize_declare_namespace_from_namespace;
  factory->serialize_start     = raptor_turtle_serialize_start;
  factory->serialize_statement = raptor_turtle_serialize_statement;
  factory->serialize_end       = raptor_turtle_serialize_end;
  factory->finish_factory      = raptor_turtle_serialize_finish_factory;

  return 0;
}


int
raptor_init_serializer_turtle(void)
{
  return raptor_serializer_register_factory("turtle", "Turtle", 
                                            "application/x-turtle",
                                            NULL,
                                            (const unsigned char*)"http://www.dajobe.org/2004/01/turtle",
                                            &raptor_turtle_serializer_register_factory);
}

