/* {{{ proto bool MarkdownDocument::setReferencePrefix(string) */
PHP_METHOD(markdowndoc, setReferencePrefix)
{
	char			*prefix;
	int				prefix_len;
	discount_object	*dobj;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
			&prefix, &prefix_len) == FAILURE) {
		RETURN_FALSE;
	}
	if ((dobj = markdowndoc_get_object(getThis(), 0 TSRMLS_CC)) == NULL) {
		RETURN_FALSE;
	}
	if (mkd_is_compiled(dobj->markdoc)) {
		zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC,
			"Invalid state: the markdown document has already been compiled");
		RETURN_FALSE;
	}

	if (dobj->ref_prefix != NULL) {
		efree(dobj->ref_prefix);
	}
	dobj->ref_prefix = estrndup(prefix, prefix_len);
	mkd_ref_prefix(dobj->markdoc, dobj->ref_prefix);

	RETURN_TRUE;
}
/* {{{ proto bool MarkdownDocument::writeXhtmlPage(mixed $out_stream) */
PHP_METHOD(markdowndoc, writeXhtmlPage)
{
	discount_object *dobj;
	zval			*zstream;
	php_stream		*stream;
	int				close;
	FILE			*f;
	int				status;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zstream) == FAILURE) {
		RETURN_FALSE;
	}
	if ((dobj = markdowndoc_get_object(getThis(), 1 TSRMLS_CC)) == NULL) {
		RETURN_FALSE;
	}
	if (markdowndoc_get_file(zstream, 1, &stream, &close, &f TSRMLS_CC) == FAILURE) {
		RETURN_FALSE;
	}
	
	status = mkd_xhtmlpage(dobj->markdoc, f);
	markdown_sync_stream_and_file(stream, close, f TSRMLS_CC);

	if (markdown_handle_io_error(status, "mkd_xhtmlpage" TSRMLS_CC) == FAILURE) {
		RETURN_FALSE;
	}
	
	RETURN_TRUE;
}
/* {{{ proto bool MarkdownDocument::dumpTree(mixed $out_stream [, string $title = "" ]) */
PHP_METHOD(markdowndoc, dumpTree)
{
	discount_object	*dobj;
	zval			*zstream;
	php_stream		*stream;
	int				close;
	FILE			*f;
	char			*title		= "";
	int				title_len	= 0;
	int				status;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s",
			&zstream, &title, &title_len) == FAILURE) {
		RETURN_FALSE;
	}
	if ((dobj = markdowndoc_get_object(getThis(), 1 TSRMLS_CC)) == NULL) {
		RETURN_FALSE;
	}
	if (markdowndoc_get_file(zstream, 1, &stream, &close, &f TSRMLS_CC) == FAILURE) {
		RETURN_FALSE;
	}

	status = mkd_dump(dobj->markdoc, f, title);

	markdown_sync_stream_and_file(stream, close, f TSRMLS_CC);
	
	if (status == -1) {
		/* should never happen */
		zend_throw_exception(spl_ce_RuntimeException,
			"Error dumping tree: call to the library failed", 0 TSRMLS_CC);
		RETURN_FALSE;
	}

	RETURN_TRUE;
}
/* {{{ proto bool MarkdownDocument::writeToc(mixed $out_stream) */
PHP_METHOD(markdowndoc, writeToc)
{
	discount_object *dobj;
	zval			*zstream;
	php_stream		*stream;
	int				close;
	FILE			*f;
	int				status;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zstream) == FAILURE) {
		RETURN_FALSE;
	}
	/* no compilation required */
	if ((dobj = markdowndoc_get_object(getThis(), 1 TSRMLS_CC)) == NULL) {
		RETURN_FALSE;
	}
	if (markdowndoc_get_file(zstream, 1, &stream, &close, &f TSRMLS_CC) == FAILURE) {
		RETURN_FALSE;
	}
	
	status = mkd_generatetoc(dobj->markdoc, f);
	markdown_sync_stream_and_file(stream, close, f TSRMLS_CC);

	if (markdown_handle_io_error(status, "mkd_generatetoc" TSRMLS_CC) == FAILURE) {
		RETURN_FALSE;
	}

	RETURN_BOOL(status == 1); /* 1 for no data; 0 for no MKD_TOC */
}
/* {{{ proto string MarkdownDocument::getToc() */
PHP_METHOD(markdowndoc, getToc)
{
	discount_object *dobj;
	char			*data	= NULL;
	int				status;

	if (zend_parse_parameters_none() == FAILURE) {
		RETURN_FALSE;
	}
	if ((dobj = markdowndoc_get_object(getThis(), 1 TSRMLS_CC)) == NULL) {
		RETURN_FALSE;
	}
	
	status = mkd_toc(dobj->markdoc, &data);
	if (status < 0) {
		/* no doc->ctx, shouldn't happen */
		zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
			"Call to library function mkd_toc() failed (should not happen!)");
		RETURN_FALSE;
	}
	/* status == 0 can indicate either empty string or no MKD_TOC, we
	 * must use data to disambiguate */
	if (data == NULL) {
		RETURN_FALSE; /* no MKD_TOC */
	}
	/* empty string included in general case */
	RETURN_STRINGL(data, status, 0);	
}
/* {{{ proto bool MarkdownDocument::setAttributesCallback(callback $attributes_callback) */
PHP_METHOD(markdowndoc, setAttributesCallback)
{
	zend_fcall_info			fci;
	zend_fcall_info_cache	fcc;
	discount_object			*dobj;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f!", &fci, &fcc) == FAILURE) {
		RETURN_FALSE;
	}
	if ((dobj = markdowndoc_get_object(getThis(), 0 TSRMLS_CC)) == NULL) {
		RETURN_FALSE;
	}

	if (fci.size > 0) { /* non-NULL passed */
		markdowndoc_store_callback(&fci, &fcc, &dobj->attr_fci, &dobj->attr_fcc);
		mkd_e_flags(dobj->markdoc, proxy_attributes_callback);
		mkd_e_free(dobj->markdoc, free_proxy_return);
		mkd_e_data(dobj->markdoc, dobj);
	} else { /* NULL */
		markdowndoc_free_callback(&dobj->attr_fci, &dobj->attr_fcc);
		mkd_e_url(dobj->markdoc, NULL);
	}
	
	RETURN_TRUE;
}
/* {{{ proto bool MarkdownDocument::isCompiled() */
PHP_METHOD(markdowndoc, isCompiled)
{
	discount_object	*dobj;

	if (zend_parse_parameters_none() == FAILURE) {
		RETURN_FALSE;
	}
	if ((dobj = markdowndoc_get_object(getThis(), 0 TSRMLS_CC)) == NULL) {
		RETURN_FALSE;
	}
	
	RETURN_BOOL(mkd_is_compiled(dobj->markdoc));
}
/* {{{ proto bool MarkdownDocument::compile([int $flags = 0]) */
PHP_METHOD(markdowndoc, compile)
{
	discount_object	*dobj;
	long			flags = 0;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) {
		RETURN_FALSE;
	}
	if ((dobj = markdowndoc_get_object(getThis(), 0 TSRMLS_CC)) == NULL) {
		RETURN_FALSE;
	}
	if (mkd_is_compiled(dobj->markdoc)) {
		zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC,
			"Invalid state: the markdown document has already been compiled");
		RETURN_FALSE;
	}

	/* always returns success (unless fed a null pointer) */
	mkd_compile(dobj->markdoc, (mkd_flag_t) flags);

	RETURN_TRUE;
}
/* {{{ proto string MarkdownDocument::getHtml() */
PHP_METHOD(markdowndoc, getHtml)
{
	discount_object *dobj;
	char			*data	= NULL;
	int				status;

	if (zend_parse_parameters_none() == FAILURE) {
		RETURN_FALSE;
	}
	if ((dobj = markdowndoc_get_object(getThis(), 1 TSRMLS_CC)) == NULL) {
		RETURN_FALSE;
	}
	
	status = mkd_document(dobj->markdoc, &data);
	if (status < 0) {
		/* should never happen, but... */
		zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
			"Call to library function mkd_document() failed (should not happen!)");
		RETURN_FALSE;
	}
	assert(data != NULL);
	RETURN_STRINGL(data, status, 0);	
}