/*
 * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org>
 * Copyright (C) 2010 David King <davidk@openismus.com>
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <glib-object.h>
#include <libgda/binreloc/gda-binreloc.h>
#include <libgda/libgda.h>
#include <string.h>

#define FILE_NAME "information_schema.xml"
#define OUT_TYPES_FILENAME "gda-meta-column-types.h"

int
main (G_GNUC_UNUSED int argc, G_GNUC_UNUSED char** argv)
{
        xmlDocPtr doc;
        xmlNodePtr node;
        gchar *fname;
	GString *out_types_str;

	gda_init();

        fname = g_build_filename (ROOT_DIR, "libgda", FILE_NAME, NULL);
	if (! g_file_test (fname, G_FILE_TEST_EXISTS)) {
		g_free (fname);
		fname = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, FILE_NAME, NULL);
		if (! g_file_test (fname, G_FILE_TEST_EXISTS)) {
			g_print ("Could not find '%s'.\n", FILE_NAME);
			exit (1);
		}
	}

	doc = xmlParseFile (fname);
	if (!doc) {
		g_print ("Missing or malformed file '%s', check your installation", fname);
		g_free (fname);
		exit (1);
        }
	
	node = xmlDocGetRootElement (doc);
	g_free (fname);
	if (strcmp ((gchar *) node->name, "schema")) {
		g_print ("Root node should be <schema>, got <%s>\n", (gchar *) node->name);
		xmlFreeDoc (doc);
		exit (1);
	}

	out_types_str = g_string_new ("/*\n * File generated by the tools/information-schema-types "
				"program from the\n"
				" * libgda/" FILE_NAME " file,\n"
				" * This file contains declaration of the expected data types when\n"
				" * extracting meta data, it should be updated when the "
				"libgda/"FILE_NAME " file changes\n"
				" * DO NOT MODIFY\n */\n\n\n");
	g_string_append (out_types_str, "#ifdef __GNUC__\n"
			 "#define MAY_BE_UNUSED __attribute__ ((unused))\n"
			 "#else\n"
			 "#define MAY_BE_UNUSED\n"
			 "#endif\n\n");

	for (node = node->children; node; node = node->next) {
		if (!strcmp ((gchar *) node->name, "table")) {
			xmlChar *prop, *descr, *table_name = NULL;
			xmlNodePtr child;
			GString *tmp_out_types_str;

			tmp_out_types_str = g_string_new ("");
			descr = xmlGetProp (node, BAD_CAST "descr");
			prop = xmlGetProp (node, BAD_CAST "name");
			if (prop) {
				g_string_append (tmp_out_types_str, "\n\n");
				if (descr) {
					g_string_append_printf (tmp_out_types_str, "/*\n * TABLE: %s\n *\n * %s\n */\n",
								(gchar*) prop, (gchar *) descr);
				}
				else {
					g_string_append_printf (tmp_out_types_str, "/*\n * TABLE: %s\n */\n",
								(gchar*) prop);
				}
				g_string_append_printf (tmp_out_types_str,
							"MAY_BE_UNUSED static GType _col_types%s[] = {\n", prop);
				table_name = prop;
			}
			else {
				g_warning ("FIXME: table not named");
				continue;
			}

			if (descr)
				xmlFree (descr);

			gint ncols = 0;
			for (child = node->children; child; child = child->next) {
				if (!strcmp ((gchar *) child->name, "column")) {
					if (ncols == 0)
						g_string_append (tmp_out_types_str, "  ");
					else
						g_string_append (tmp_out_types_str, ", ");
					ncols++;

					prop = xmlGetProp (child, BAD_CAST "type");
					if (prop) {
						GType type;
						type = gda_g_type_from_string ((gchar*) prop);
						if (type == G_TYPE_STRING)
							g_string_append (tmp_out_types_str, "G_TYPE_STRING");
						else if (type == G_TYPE_BOOLEAN)
							g_string_append (tmp_out_types_str, "G_TYPE_BOOLEAN");
						else if (type == G_TYPE_INT)
							g_string_append (tmp_out_types_str, "G_TYPE_INT");
						else if (type == GDA_TYPE_TIMESTAMP) {
							xmlChar *tname;
							tname = xmlGetProp (node, BAD_CAST "name");
							g_print ("Warning: ignoring table %s because the '%s' type is "
								 "not constant.\n", (gchar*) tname, (gchar*) prop);
							xmlFree (tname);
							g_string_free (tmp_out_types_str, TRUE);
							tmp_out_types_str = NULL;
							break;
						}
						else
							g_error ("Non handled type "
								 "%s (interpreted as %s)\n", prop,
								 g_type_name (type));

						xmlFree (prop);
					}
					else
						g_string_append (tmp_out_types_str, "G_TYPE_STRING");

					prop = xmlGetProp (child, BAD_CAST "name");
					if (prop) {
						g_string_append_printf (tmp_out_types_str, "  /* column: %s */\n",
									prop);
						xmlFree (prop);
					}
					else
						g_string_append (tmp_out_types_str, "\n");
				}
			}
			if (tmp_out_types_str) {
				g_string_append (tmp_out_types_str, ", G_TYPE_NONE /* end of array marker */\n");
				g_string_append (tmp_out_types_str, "};\n\n");

				g_string_append (out_types_str, tmp_out_types_str->str);
				g_string_free (tmp_out_types_str, TRUE);
			}
			xmlFree (table_name);
		}
	}
	xmlFreeDoc (doc);

	g_string_append (out_types_str, "#undef MAY_BE_UNUSED\n");

	if (! g_file_set_contents (OUT_TYPES_FILENAME, out_types_str->str, -1, NULL)) 
		g_print ("Could not write output file '%s'\n", OUT_TYPES_FILENAME);
	else
		g_print ("Doc. written to '%s'\n", OUT_TYPES_FILENAME);
	g_string_free (out_types_str, TRUE);
	
	return 0;
}
