/*
 * Copyright (C) 2012 - Juan Ferrer Toribio
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */

#include "db-plugin.h"

/**
 * SECTION: db-plugin
 * @Short_description: manages a connection to a database.
 * @Title: DbPlugin
 * @See_also: #DbConn
 * 
 * This class manages a connection to a database internally. This 
 * is accessed through the #DbConn class to internally connect, query and
 * disconnect the database.
 **/
G_DEFINE_ABSTRACT_TYPE (DbPlugin, db_plugin, G_TYPE_OBJECT);

/**
 * db_plugin_close:
 * @obj: a #DbPlugin
 *
 * Closes de current connection to the database.
 **/
void db_plugin_close (DbPlugin * obj)
{
	g_return_if_fail (DB_IS_PLUGIN (obj));

	g_mutex_lock (&obj->mutex);
	g_mutex_lock (&obj->kill_mutex);

	DB_PLUGIN_GET_CLASS (obj)->close (obj);

	g_mutex_unlock (&obj->kill_mutex);
	g_mutex_unlock (&obj->mutex);
}

/**
 * db_plugin_open:
 * @obj: a #DbPlugin
 * @host: the hostname
 * @schema: the database schema
 * @user: the user name
 * @pass: the password
 * @err: (out) (allow-none): destination of #GError, if you want to handle it.
 *
 * Opens a new connection to the database.
 *
 * Return value: Returns %TRUE if connection was made, %FALSE otherwise.
 **/
gboolean db_plugin_open (DbPlugin * obj, const gchar * host,
	const gchar * schema, const gchar * user, const gchar * pass, GError ** err)
{
	gboolean opened;

	g_return_val_if_fail (DB_IS_PLUGIN (obj), FALSE);

	g_mutex_lock (&obj->mutex);
	g_mutex_lock (&obj->kill_mutex);

	DB_PLUGIN_GET_CLASS (obj)->close (obj);

	if (obj->ca)
		DB_PLUGIN_GET_CLASS (obj)->set_ssl (obj, obj->ca);

	opened = DB_PLUGIN_GET_CLASS (obj)->open (obj,
		host, schema, user, pass, err);

	g_mutex_unlock (&obj->kill_mutex);
	g_mutex_unlock (&obj->mutex);
	
	return opened;
}

/**
 * db_plugin_set_ssl:
 * @obj: a #DbPlugin
 * @ca: path to the certificate authority file
 *
 * Sets the certificate authority file needed to use SSL. If the secure
 * connection through SSL is not properly set, @db_plugin_open will fail.
 */
void db_plugin_set_ssl (DbPlugin * obj, const gchar * ca)
{
	g_return_if_fail (DB_IS_PLUGIN (obj));

	g_mutex_lock (&obj->mutex);
	g_free (obj->ca);
	obj->ca = strdup (ca);
	g_mutex_unlock (&obj->mutex);
}

/**
 * db_plugin_query:
 * @obj: a #DbPlugin
 * @sql: a #gchar string containing an sql query
 * @err: (out) (allow-none): destination of #GError, if you want to handle it.
 *
 * If everything was ok (i.e. the sql query wasn't empty, it was completed
 * successfully, etc.), it will return a #GList of #DbResult with the
 * database response, depending on the query or queries passed. Note that if
 * the input string @sql is a multi-query and any of the queries inside of it
 * fails the rest of the queries will fail.
 * 
 * Refer to #DbError for the possible errors.
 *
 * Return value: (transfer full) (allow-none): a #DbResultSet containing the
 * results or %NULL if error
 **/
DbResultSet * db_plugin_query (DbPlugin * obj, const gchar * sql, GError ** err)
{
	DbResultSet * set;

	g_return_val_if_fail (DB_IS_PLUGIN (obj), NULL);

	g_mutex_lock (&obj->mutex);
	set = DB_PLUGIN_GET_CLASS (obj)->query (obj, sql, err);
	g_mutex_unlock (&obj->mutex);
	
	return set;
}

/**
 * db_plugin_kill_query:
 * @obj: a #DbPlugin
 *
 * Tryes to kill the current query.
 **/
void db_plugin_kill_query (DbPlugin * obj)
{
	DbPluginClass * klass;

	g_return_if_fail (DB_IS_PLUGIN (obj));

	klass = DB_PLUGIN_GET_CLASS (obj);

	if (klass->kill_query)
	{
		g_mutex_lock (&obj->kill_mutex);
		klass->kill_query (obj);
		g_mutex_unlock (&obj->kill_mutex);
	}
}
 
/**
 * db_plugin_parse:
 * @obj: a #DbPlugin.
 * @sql: (transfer none): an SQL string.
 *
 * Parses a string and makes an #SqlStmt from it.
 * 
 * Return value: (transfer none): a new #SqlStmt parsed from @sql.
 **/
SqlStmt * db_plugin_parse (DbPlugin * obj, gchar * sql)
{
	g_return_val_if_fail (DB_IS_PLUGIN (obj), NULL);

	return NULL;
}

/**
 * db_plugin_render:
 * @obj: a #DbPlugin
 * @object: the #GObject to render
 * @err: (out) (allow-none): the return location for #GError
 *
 * Renders a #GObject object as a SQL string to send it in a database
 * query. It takes the plugin to know the codification in wich to escape
 * the data.
 * 
 * Return value: (transfer full): the rendered string, or %NULL if error.
 **/
gchar *	db_plugin_render (DbPlugin * obj, gpointer object, SqlBatch * batch, GError ** err)
{
	g_return_val_if_fail (DB_IS_PLUGIN (obj), NULL);
	g_return_val_if_fail (G_IS_OBJECT (object), NULL);
	g_return_val_if_fail (SQL_IS_BATCH (batch) || !batch, NULL);

	return sql_render_get_string (obj->render, object, batch, obj, err);
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++ Class

static void db_plugin_init (DbPlugin *obj)
{
	obj->render = NULL;
	obj->ca = NULL;
	g_mutex_init (&obj->mutex);
	g_mutex_init (&obj->kill_mutex);
}

static void db_plugin_finalize (DbPlugin * obj)
{
	g_clear_object (&obj->render);
	g_free (obj->ca);
	g_mutex_clear (&obj->mutex);
	g_mutex_clear (&obj->kill_mutex);
	G_OBJECT_CLASS (db_plugin_parent_class)->finalize (G_OBJECT (obj));
}

static void db_plugin_class_init (DbPluginClass * k)
{	
	G_OBJECT_CLASS (k)->finalize = (GObjectFinalizeFunc) db_plugin_finalize;
}