//
// $Id: DBInterface.cpp,v 1.1 2004/06/01 17:05:20 bakerj Exp $
//
//************************** Property of the MITRE Corporation ***************************//
//
// Copyright (c) 2003 - The MITRE Corporation
//
// This file is part of the OVAL Query Interpreter.
//
// The OVAL Query Interpreter 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.
//
// The OVAL Query Interpreter 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 the OVAL
// Query Interpreter; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA
//
//****************************************************************************************//

#include "DBInterface.h"

//****************************************************************************************//
//								DBInterface Class										  //	
//****************************************************************************************//

DBInterface::DBInterface(string dbLocation, bool reuseDB)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Create a new DBInterface object. If a database already exists at
	//	the specified location delete it. Then create and open a new database.
	//	
	// -----------------------------------------------------------------------
	
	//	Ensure that any existing database is removed
	if(!reuseDB)
		RemoveExistingDatabase(dbLocation);

	//	Open a new database in the specified location
	Open(dbLocation);
}

DBInterface::~DBInterface()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Close the database.
	//
	// -----------------------------------------------------------------------

	Close();
}

//****************************************************************************************//
//							DBInterface Public members									  //	
//****************************************************************************************//
bool DBInterface::ClearTable(string tableIn)
{
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//  Delete any old data from this table.
	//
	//------------------------------------------------------------------------------------//

	string sqlStmt = "";
	sqlStmt.append("DELETE FROM ");
	sqlStmt.append(tableIn);

	stringVector *svTmp = NULL;

	return ExecSQL(sqlStmt, svTmp);
}

bool DBInterface::ExecSQL(string stmt)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Ececute the specified sql statment. This method should be used only 
	//	when no results are expected from the statment
	//
	// -----------------------------------------------------------------------

	bool retval = false;
	int nrow = 0;
	int ncolumn = 0;

	// The sqlite_get_table() function allocates space for the results of an SQL query and
	// also for any error message through a call to malloc().  This data must be freed by
	// calling sqlite_free_table() and sqlite_freemem.
	char** tempData;
	char* tempError = NULL;

	// Run the SQL query.
	int retError = sqlite_get_table(db, stmt.c_str(), &tempData, &nrow, &ncolumn, &tempError);
	if (retError == SQLITE_OK) {

		// Free the space that was allocated during the sqlite_get_table() call.
		sqlite_free_table(tempData);

		retval = true;
	
	}else {

		if (Log::verboseMode == true) {
			string errorMessage = "";

			errorMessage.append("\nERROR: [SQLite - sqlite_get_table] ");
			errorMessage.append(tempError);
			errorMessage.append("\n\n");
			
			cerr << errorMessage;
			Log::WriteLog(errorMessage);
		}

		// Free the space that was allocated to hold the error message.
		sqlite_freemem(tempError);

		retval = false;
	}

	return retval;
}

bool DBInterface::ExecSQL(string stmt, vDBRecord *dbvResults)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Ececute the specified sql statment. dbvResultsults will return the
	//	results of a query. Use this method when a query expects to return
	//	multiple columns.
	//
	// -----------------------------------------------------------------------

	bool retval = false;
	int nrow = 0;
	int ncolumn = 0;
	int index = 0;

	// The sqlite_get_table() function allocates space for the results of an SQL query and
	// also for any error message through a call to malloc().  This data must be freed by
	// calling sqlite_free_table() and sqlite_freemem.
	char** tempData;
	char* tempError = NULL;

	// Run the SQL query.
	int retError = sqlite_get_table(db, stmt.c_str(), &tempData, &nrow, &ncolumn, &tempError);
	if (retError == SQLITE_OK) {

		// Check to see if we are expecting return information and if there was info
		// returned.
		if ((nrow > 0) && (dbvResults != NULL)) {

			// Loop through the results and populate the resultVector.
			// The records are stored in an array of strings the first
			// ncolumn records are the coulnm names. Then the values
			// are inorder lowest col to highest col one row after the other			  
			index = ncolumn;
			while(index < (nrow+1)*ncolumn) {
			  
			  	stringVector *svTmp = new stringVector;
				for (int j=0; j<ncolumn; j++) {
				  	svTmp->push_back(tempData[index]);
					index++;
				}
				dbvResults->push_back((*svTmp));
			}
		}

		// Free the space that was allocated during the sqlite_get_table() call.
		sqlite_free_table(tempData);

		retval = true;
	
	}else {

		if (Log::verboseMode == true) {
			string errorMessage = "";

			errorMessage.append("\nERROR: [SQLite - sqlite_get_table] ");
			errorMessage.append(tempError);
			errorMessage.append("\n\n");

			cerr << errorMessage;
			Log::WriteLog(errorMessage);
		}

		// Free the space that was allocated to hold the error message.
		sqlite_freemem(tempError);

		retval = false;
	}

	return retval;
}

bool DBInterface::ExecSQL(string stmt, stringVector *svResults)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Ececute the specified sql statment. svResdbvResultsults will return the
	//	results of a query. Use this method when a query expects to reurn a 
	//	single column.
	//
	// -----------------------------------------------------------------------

	bool retval = false;
	int nrow = 0;
	int ncolumn = 0;

	// The sqlite_get_table() function allocates space for the results of an SQL query and
	// also for any error message through a call to malloc().  This data must be freed by
	// calling sqlite_free_table() and sqlite_freemem.
	char** tempData;
	char* tempError = NULL;

	// Run the SQL query.
	int retError = sqlite_get_table(db, stmt.c_str(), &tempData, &nrow, &ncolumn, &tempError);
	if (retError == SQLITE_OK) {

		// Check to see if we are expecting return information and if there was info
		// returned.
		if ((nrow > 0) && (svResults != NULL)) {

			// Loop through the results and populate the resultVector.
			for (int i=1; i<=nrow; i++) {

				for (int j=0; j<ncolumn; j++) {
					
					svResults->push_back(tempData[i+j]);
				}
			}
		}

		// Free the space that was allocated during the sqlite_get_table() call.
		sqlite_free_table(tempData);

		retval = true;
	
	}else {

		if (Log::verboseMode == true) {
			string errorMessage = "";

			errorMessage.append("\nERROR: [SQLite - sqlite_get_table] ");
			errorMessage.append(tempError);
			errorMessage.append("\n\n");
		
			cerr << errorMessage;
			Log::WriteLog(errorMessage);
		}

		// Free the space that was allocated to hold the error message.
		sqlite_freemem(tempError);

		retval = false;
	}

	return retval;
}

//****************************************************************************************//
//							DBInterface Private members									  //	
//****************************************************************************************//
void DBInterface::Close()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Close the database.
	//
	// -----------------------------------------------------------------------

	sqlite_close(this->db);
}

void DBInterface::Open(string dbLocation)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Open a databasse at the specified location with thr specified name.
	//
	// -----------------------------------------------------------------------

	char *dbErrMsg = NULL;
	db = NULL;

	db = sqlite_open(dbLocation.c_str(), 0, &dbErrMsg);

	if(db == NULL) 	{
		string errMsg = "Error: Unable to open database: ";
		errMsg.append(dbLocation);
		errMsg.append("\n");
		errMsg.append("SQL message:");
		errMsg.append(dbErrMsg);

		sqlite_freemem(dbErrMsg);

		throw DBInterfaceException(errMsg, ERROR_FATAL);
	}
}

void DBInterface::RemoveExistingDatabase(string dbLocation)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	If a file exists with the specified name delete it.
	//
	// -----------------------------------------------------------------------

	FILE* fp = NULL;
	fp = fopen(dbLocation.c_str(), "w+"); 
	if (fp != NULL) {
		fclose(fp);
		
		int result = remove(dbLocation.c_str());
		if(result != 0)
			throw DBInterfaceException("Error: Unable to delete existing database file.");

	}else {
		throw DBInterfaceException("Error: Unable to delete existing database file.");
	}		
}

//****************************************************************************************//
//								ProbeException Class									  //	
//****************************************************************************************//
DBInterfaceException::DBInterfaceException() : Exception()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Default constructor simply set the severity to ERROR_FATAL. This is 
	//	done with the explicit call to the Exception class default constructor.
	//
	// -----------------------------------------------------------------------

}

DBInterfaceException::DBInterfaceException(string errMsgIn) : Exception(errMsgIn)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the error message and then set the severity to ERROR_FATAL. This is 
	//	done with the explicit call to the Exception class constructor that 
	//	takes a single string param.
	//
	// -----------------------------------------------------------------------

}

DBInterfaceException::DBInterfaceException(string errMsgIn, int severity) : Exception(errMsgIn, severity)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the error message and the severity to to the specified values. This is 
	//	done with the explicit call to the Exception class constructor that 
	//	takes a string and an int param.
	//
	// -----------------------------------------------------------------------

}

DBInterfaceException::~DBInterfaceException()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothing for now
	//
	// -----------------------------------------------------------------------

}

