/*
 * servercommon.c
 * Routines used throughout the server.
 *
 * Copyright (C) Leni Mayo 2002
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License, version 2, as
 *	published by the Free Software Foundation.
 *	
 *	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.
 */
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "common.h"
#include "servercommon.h"

const char *pszXmlVersionEncoding = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";

typedef struct
{
	RdfProperty code;
	XmlNamespace namespace;
	const char *pszFragment;
} Triple;

const Triple * triple(RdfProperty code)
{
	static Triple table[] =
	{
		{ eRdfType,               eXmlRdf,   "type",             },

		{ eGraphGraph,            eXmlGraph, "graph",            },
		{ eGraphService,          eXmlGraph, "service",          },
		{ eGraphNodes,            eXmlGraph, "nodes",            },
		{ eGraphEdges,            eXmlGraph, "edges",            },
		{ eGraphNode,             eXmlGraph, "node",             },
		{ eGraphEdge,             eXmlGraph, "edge",             },
		{ eGraphFrom,             eXmlGraph, "source",           },
		{ eGraphTo,               eXmlGraph, "target",           },
		{ eGraphWeight,           eXmlGraph, "weight",           },

		{ eSerelMtime,            eXmlSerel, "mtime",            },
		{ eSerelSourceUri,        eXmlSerel, "sourceuri",        },
		{ eSerelStartUri,         eXmlSerel, "starturi",         },
		{ eSerelRootToLeafWeight, eXmlSerel, "RootToLeafWeight", },
		{ eSerelRankSlowest,      eXmlSerel, "RankSlowest",      },
		{ eSerelOnSlowestPath,    eXmlSerel, "OnSlowestPath",    },
		{ eSerelMarkDeleted,      eXmlSerel, "MarkDeleted",      },
		{ eSerelVisited,          eXmlSerel, "Visited",          },
		{ eSerelInventory,        eXmlSerel, "inventory",        },
		{ eSerelRuntime,          eXmlSerel, "runtime",          },
		{ eSerelLate,             eXmlSerel, "late",             },
		{ eSerelLast,             eXmlSerel, "last",             },
		{ eSerelParse,            eXmlSerel, "parse",            }
	};

	assert(code < eRdfPropertyLast && table[code].code == code);

	return &table[code];
}

const char * rdfPropertyFragment(RdfProperty code)
{
	return triple(code)->pszFragment;
}

const char * rdfPropertyNamespace(RdfProperty code)
{
	return namespaceFromCode(triple(code)->namespace);
}

const char *namespaceFromCode(XmlNamespace code)
{
	static const char *table[eXmlNamespaceLast];
	static int initialised = FALSE;

	if (!initialised)
	{
		/*
		 * if you add a namespace to this table, add the
		 * namespace prefix in the table below.
		 */
		table[eXmlRdf]   = "http://www.w3.org/1999/02/22-rdf-syntax-ns";
		table[eXmlDc]    = "http://purl.org/dc/elements/1.1/";
		table[eXmlGraph] = "http://www.fastboot.org/2002/03/graph-schema";
		table[eXmlSerel] = "http://www.fastboot.org/2002/03/serel-schema";

		initialised = TRUE;
	}
	
	assert(code < eXmlNamespaceLast);

	return table[code];
}

#ifdef TAKENOUT
 This was an idea - never implemented
const char *namespacePrefixFromCode(XmlNamespace code)
{
	static const char *table[eXmlNamespaceLast];
	static int initialised = FALSE;

	if (!initialised)
	{
		table[eXmlRdf]   = "rdf";
		table[eXmlDc]    = "dc";
		table[eXmlGraph] = "";  /* this is the default namespace everywhere */
		table[eXmlSerel] = "serel";

		initialised = TRUE;
	}
	
	assert(code < eXmlNamespaceLast);

	return table[code];
}
#endif


void print_rdf_header(FILE *fp)
{
	fprintf(fp, "%s\n", pszXmlVersionEncoding);
	fprintf(fp, "\n");
	fprintf(fp, "<rdf:RDF\n");
	fprintf(fp, "  xmlns:rdf=\"%s#\"\n", namespaceFromCode(eXmlRdf));
	fprintf(fp, "  xmlns:serel=\"%s#\"\n", namespaceFromCode(eXmlSerel));
	fprintf(fp, "  xmlns:graph=\"%s#\"\n", namespaceFromCode(eXmlGraph));
	fprintf(fp, "  xmlns=\"%s#\"\n", namespaceFromCode(eXmlGraph));
	fprintf(fp, ">\n");
	fprintf(fp, "\n");
}

void print_rdf_trailer(FILE *fp)
{
	fprintf(fp, "</rdf:RDF>\n");
}


void stringsInListToFp(FILE *fp, GSList *pList)
{
	GSList *pElement;

	for (pElement = pList; pElement != NULL; pElement = pElement->next)
	{
		assert(pElement->data);

		fprintf(fp, "%s%s", (const char *) pElement->data,
		                    pElement->next == NULL ? "" : " ");
	}
}

char * newStringFromStringsInList(GSList *pList)
{
	char tmpfilename[100];
	char *pszReturn = NULL;

	FILE *fp = createAndOpenTmpFp(tmpfilename, sizeof(tmpfilename), "w");

	if (fp != NULL)
	{
		stringsInListToFp(fp, pList);
		
		fclose(fp);

		fp = fopen(tmpfilename, "r");

		if (fp)
		{
			pszReturn = stringFromFp(fp);

			fclose(fp);
		}

		unlink(tmpfilename);
	}

	return pszReturn;
}

char * edgeFragmentFromPair(char buf[], int buflen, const char *pszFrom, const char *pszTo)
{
	snprintf(buf, buflen, "edge-%s-%s", pszFrom, pszTo);
	
	return buf;
}
