/*
	CVSNT Generic API
    Copyright (C) 2004 Tony Hoyle and March-Hare Software Ltd

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#endif
#include <config.h>
#include "../lib/api_system.h"

#ifdef HAVE_SQLITE3_H
#include <sqlite3.h>
#else
// else what??
#endif

#include "../cvs_string.h"
#include "../FileAccess.h"
#include "../ServerIO.h"
#include "SQLiteConnection.h"
#include "SQLiteRecordset.h"

extern "C" CSqlConnection *SQLite_Alloc()
{
        return new CSQLiteConnection;
}

CSQLiteConnection::CSQLiteConnection()
{
	m_pDb=NULL;
}

CSQLiteConnection::~CSQLiteConnection()
{
	Close();
}

bool CSQLiteConnection::Create(const char *host, const char *database, const char *username, const char *password)
{
	if(CFileAccess::exists(database))
		return false;

#ifdef _WIN32
	__try
	{
#endif
		if(sqlite3_open(database, &m_pDb))
			return false;
#ifdef _WIN32
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return false;
	}
#endif
	return true;
}

bool CSQLiteConnection::Open(const char *host, const char *database, const char *username, const char *password)
{
	if(!CFileAccess::exists(database))
		return false;
#ifdef _WIN32
	__try
	{
#endif
	if(sqlite3_open(database, &m_pDb))
		return false;
#ifdef _WIN32
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return false;
	}
#endif
	return true;
}

bool CSQLiteConnection::Close()
{
	if(m_pDb)
		sqlite3_close(m_pDb);

	m_pDb=NULL;
	return true;
}

bool CSQLiteConnection::IsOpen()
{
	if(m_pDb)
		return true;
	return false;
}

CSqlRecordsetPtr CSQLiteConnection::Execute(const char *string, ...)
{
	cvs::string str;
	va_list va;
	va_start(va,string);
	cvs::vsprintf(str,4096,string,va);
	va_end(va);

	CSQLiteRecordset *rs = new CSQLiteRecordset();

	CServerIo::trace(3,"%s",str.c_str());

	sqlite3_stmt *pStmt;
	const char *zTail = NULL;

	if(sqlite3_prepare(m_pDb,str.c_str(),(int)str.length(),&pStmt,&zTail))
		return rs;

	for(std::map<int,CSqlVariant>::iterator i = m_bindVars.begin(); i!=m_bindVars.end(); ++i)
	{
		switch(i->second.type())
		{
		case CSqlVariant::vtNull:
			sqlite3_bind_null(pStmt,i->first+1);
			break;
		case CSqlVariant::vtChar:
		case CSqlVariant::vtShort:
		case CSqlVariant::vtInt:
		case CSqlVariant::vtLong:
		case CSqlVariant::vtUChar:
		case CSqlVariant::vtUShort:
		case CSqlVariant::vtUInt:
		case CSqlVariant::vtULong:
			sqlite3_bind_int(pStmt,i->first+1,(int)i->second);
			break;
		case CSqlVariant::vtLongLong:
		case CSqlVariant::vtULongLong:
#ifdef _WIN32
			sqlite3_bind_int64(pStmt,i->first+1,(__int64)i->second);
#else
			sqlite3_bind_int64(pStmt,i->first+1,(long long)i->second);
#endif
			break;
		case CSqlVariant::vtString:
			sqlite3_bind_text(pStmt,i->first+1,(const char *)i->second,-1,SQLITE_STATIC);
			break;
		case CSqlVariant::vtWString:
			sqlite3_bind_text16(pStmt,i->first+1,(const wchar_t *)i->second,-1,SQLITE_STATIC);
			break;
		}
	}

	rs->Init(m_pDb,pStmt);
	
	m_bindVars.clear();

	return rs;
}

bool CSQLiteConnection::Error() const
{
	int err = sqlite3_errcode(m_pDb);
	if(err && err<100)
		return true;
	return false;
}

const char *CSQLiteConnection::ErrorString() 
{
	if(!m_pDb)
		return "Open failed";
	return sqlite3_errmsg(m_pDb);
}

unsigned CSQLiteConnection::GetInsertIdentity(const char *table_hint) 
{
	return (unsigned)sqlite3_last_insert_rowid(m_pDb);
}

bool CSQLiteConnection::BeginTrans()
{
	if(sqlite3_exec(m_pDb,"BEGIN",NULL,NULL,NULL)==SQLITE_OK)
		return true;
	return false;
}

bool CSQLiteConnection::CommitTrans()
{
	if(sqlite3_exec(m_pDb,"COMMIT",NULL,NULL,NULL)==SQLITE_OK)
		return true;
	return false;
}

bool CSQLiteConnection::RollbackTrans()
{
	if(sqlite3_exec(m_pDb,"ROLLBACK",NULL,NULL,NULL)==SQLITE_OK)
		return true;
	return false;
}

bool CSQLiteConnection::Bind(int variable, CSqlVariant value)
{
	m_bindVars[variable]=value;
	return true;
}


syntax highlighted by Code2HTML, v. 0.9.1