/*
 * 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/>.
 */

#ifndef DB_CONN_H
#define DB_CONN_H

#include <sql/sql.h>
#include "db-plugin.h"

#define DB_CONN_LOG_DOMAIN		(g_quark_from_string ("DbConn"))

#define DB_TYPE_CONN			(db_conn_get_type ())
#define DB_CONN(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), DB_TYPE_CONN, DbConn))
#define DB_IS_CONN(obj)			(G_TYPE_CHECK_INSTANCE_TYPE ((obj), DB_TYPE_CONN))
#define DB_CONN_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), DB_TYPE_CONN, DbConnClass))
#define DB_IS_CONN_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), DB_TYPE_CONN))
#define DB_CONN_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), DB_TYPE_CONN, DbConnClass))

//#define PLUGIN_DIR "./plugin/%s/.libs"

typedef struct _DbConn DbConn;
typedef struct _DbConnClass DbConnClass;

#include "db-request.h"

struct _DbConn
{
	GObject parent;
	DbPlugin * plugin;
	gchar * plugin_name;
	gchar * query_path;
	gchar ** query_dirs;
	gchar * host;
	gchar * user;
	gchar * pass;
	gchar * schema;
	gint status; // DbConnStatus
	GMutex * mutex;
	GMutex * settings_mutex;
	GThread * thread;
	GCond * thread_cond;
	GQueue * requests;
	guint transaction;
};

struct _DbConnClass
{
	GObjectClass parent;
};

typedef enum
{
	 DB_CONN_ERROR_LOST = 1
	,DB_CONN_ERROR_PLUGIN
	,DB_CONN_ERROR_OPENING
	,DB_CONN_ERROR_BAD_LOGIN
	,DB_CONN_ERROR_BAD_RESPONSE
	,DB_CONN_ERROR_QUERY_EMPTY
	,DB_CONN_ERROR_QUERY_NONFATAL
	,DB_CONN_ERROR_QUERY_FATAL
	,DB_CONN_ERROR_QUERY_FAILED
	,DB_CONN_ERROR_UNKNOW
}
DbConnError;

/**
 * DbConnStatus:
 * @DB_CONN_CLOSED: The connection is closed
 * @DB_CONN_OPENING: The connection is opening
 * @DB_CONN_IDLE: The connection is open but it's idle
 * @DB_CONN_TRANSACTION: A transatcion has been started
 * @DB_CONN_LOADING: The connection is making a query
 * @DB_CONN_CLOSE_REQUESTED: Waiting for a query to close the connection
 * @DB_CONN_CLOSING: The connection is closing
 * @DB_CONN_LOST: The connection is closed because it has been lost
 *
 * Identifies the status of the connection.
 **/
typedef enum
{
	 DB_CONN_CLOSED				= 0
	,DB_CONN_OPEN				= 1 << 0
	,DB_CONN_LOADING			= 1 << 1
	,DB_CONN_LOST				= 1 << 2
	,DB_CONN_TRANSACTION		= 1 << 3
	,DB_CONN_CLOSING			= 1 << 4
	,DB_CONN_OPENING			= 1 << 5
}
DbConnStatus;

GType			db_conn_get_type				();
DbConn *		db_conn_new						();
gboolean		db_conn_load_plugin				(DbConn * obj, const gchar * plugin, GError ** err);
void			db_conn_set_query_path			(DbConn * obj, const gchar * path);
gchar *			db_conn_get_query_path			(DbConn * obj);
gboolean		db_conn_open					(DbConn * obj
												,const gchar * host
												,const gchar * schema
												,const gchar * user
												,const gchar * pass
												,GError ** err);
void			db_conn_close					(DbConn * obj, gboolean wait);
void			db_conn_set_ssl					(DbConn * obj, const gchar * ca);
gboolean		db_conn_reconnect				(DbConn * obj, GError ** err);

DbResultSet *	db_conn_exec					(DbConn * obj, const gchar * sql, GError ** err);

DbRequest *		db_conn_query					(DbConn * obj, const gchar * sql, SqlBatch * batch);
DbRequest *		db_conn_query_async				(DbConn * obj
												,const gchar * sql
												,SqlBatch * batch
												,DbRequestDoneCallback callback
												,gpointer user_data
												,GDestroyNotify notify);

DbRequest *		db_conn_query_with_stmt			(DbConn * obj, SqlStmt * stmt, SqlBatch * batch);
DbRequest *		db_conn_query_with_stmt_async	(DbConn * obj
												,SqlStmt * stmt
												,SqlBatch * batch
												,DbRequestDoneCallback callback
												,gpointer user_data
												,GDestroyNotify notify);

gboolean		db_conn_query_value				(DbConn * obj, const gchar * sql, SqlBatch * batch, GValue * value, GError ** err);

void			db_conn_retry					(DbConn * obj);
void			db_conn_kill_query				(DbConn * obj);

SqlStmt *		db_conn_parse					(DbConn * obj, gchar * sql);
gchar *			db_conn_render					(DbConn * obj, gpointer object, SqlBatch * batch, GError ** err);
guchar *		db_conn_escape_binary			(DbConn * obj, const guchar * from, gsize from_size, gsize * to_size);

void			db_conn_start_transaction		(DbConn * obj);
void			db_conn_commit					(DbConn * obj);
void			db_conn_rollback				(DbConn * obj);

gchar *			db_conn_get_user				(DbConn * obj);
gchar *			db_conn_get_host				(DbConn * obj);
gchar *			db_conn_get_schema				(DbConn * obj);

SqlObject *		db_conn_create_stmt_from_file	(DbConn * obj, const gchar * query_file);

#endif