/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.    
 */
#include "apache/das/rdb/ResultSet.h"

namespace apache {
	namespace das {
		namespace rdb {

ResultSet::ResultSet(StatementPtr aStmt) {
	stmt = aStmt;
	metaData = new ResultSetMetaData(*this);

}

ResultSet::~ResultSet(void) {
	ResultSetObject::free();
	delete metaData;

}

const ResultSetMetaData& ResultSet::getResultSetMetaData(void) const {
	return *metaData;
}

StatementPtr ResultSet::getStatement(void) const {
	return stmt;
}

SQLINTEGER ResultSet::getSQLInteger(unsigned int columnIndex) const {
	SQLINTEGER sqlPtr = 0;
	SQLSMALLINT length = 0;
	SQLINTEGER aux = 0;

	if (metaData->getSQLType(columnIndex) == SQL_INTEGER) {
		SQLRETURN result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_LONG, &sqlPtr, 0, &aux);
SQLINTEGER error;
		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)){
SQLCHAR sqlStat;

SQLCHAR * message = new SQLCHAR[100];
	SQLSMALLINT messageLength;
			SQLGetDiagRec(SQL_HANDLE_DBC, stmt->getConnection().getODBCConnection(),1, 
		              &sqlStat, &error,message,100,&messageLength);

		

		string error("Error to establish the connection.\nSQLSTATE: ");
		error += reinterpret_cast<char*>(&sqlStat);
		throw SQLException(result, error);
	}

		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
			throw SQLException(result, "Error on getting database data!");

	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not integer!");
	}
		
	return sqlPtr;

}

SQLINTEGER ResultSet::getSQLInteger(std::string tableName, std::string columnName) const {
	return getSQLInteger(metaData->getColumnIndex(tableName, columnName));
}

SQLSMALLINT ResultSet::getSQLSmallInt(unsigned int columnIndex) const {
	SQLSMALLINT sqlPtr = 0;
	SQLSMALLINT length = 0;
	SQLINTEGER aux = 0;

	if (metaData->getSQLType(columnIndex) == SQL_SMALLINT) {
		SQLRETURN result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_SHORT, &sqlPtr, 0, &aux);

		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
			throw SQLException(result, "Error on getting database data!");

	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not integer!");
	}
		
	return sqlPtr;

}

SQLSMALLINT ResultSet::getSQLSmallInt(std::string tableName, std::string columnName) const {
	return getSQLSmallInt(metaData->getColumnIndex(tableName, columnName));
}


SQLWCHAR ResultSet::getSQLWChar(unsigned int columnIndex) const {
	SQLWCHAR strAux = 0;
	
	if (metaData->getSQLType(columnIndex) == SQL_WCHAR) {
		SQLINTEGER length = 0;
		SQLRETURN result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_WCHAR, &strAux, 2, &length);
		
		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
			throw SQLException(result, "Error on getting database data!");
		
	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not char!");
	}

	return strAux;

}

SQLWCHAR ResultSet::getSQLWChar(std::string tableName, std::string columnName) const {
	return getSQLWChar(metaData->getColumnIndex(tableName, columnName));
}

SQLCHAR ResultSet::getSQLChar(unsigned int columnIndex) const {
	SQLCHAR strAux = 0;
		
	if (metaData->getSQLType(columnIndex) == SQL_CHAR) {
		SQLINTEGER length = 0;
		SQLRETURN result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_CHAR, &strAux, 2, &length);
		
		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
			throw SQLException(result, "Error on getting database data!");

	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not char!");
	}

	return strAux;

}

SQLCHAR ResultSet::getSQLChar(std::string tableName, std::string columnName) const {
	return getSQLChar(metaData->getColumnIndex(tableName, columnName));
}

SQLREAL ResultSet::getSQLReal(unsigned int columnIndex) const {
	SQLREAL ret = 0;

	if (metaData->getSQLType(columnIndex) == SQL_REAL) {
		SQLREAL real = 0;
		SQLINTEGER length = 0;
		SQLRETURN result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_FLOAT, &real, 1, &length);
		
		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
			throw SQLException(result, "Error on getting database data!");

		ret = (SQLREAL) real;
		
	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not real!");
	}

	return ret;

}

SQLREAL ResultSet::getSQLReal(std::string tableName, std::string columnName) const {
	return getSQLReal(metaData->getColumnIndex(tableName, columnName));
}

SQLFLOAT ResultSet::getSQLFloat(unsigned int columnIndex) const {
	SQLFLOAT ret = 0;

	if (metaData->getSQLType(columnIndex) == SQL_FLOAT) {
		SQLDOUBLE data = 0;
		SQLINTEGER length = 0;
		SQLRETURN result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_DOUBLE, &data, 1, &length);
		
		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
			throw SQLException(result, "error on getting database data!");

		ret = (SQLFLOAT) data;
		
	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not float!");
	}

	return ret;

}

SQLFLOAT ResultSet::getSQLFloat(std::string tableName, std::string columnName) const {
	return getSQLFloat(metaData->getColumnIndex(tableName, columnName));
}

SQLDOUBLE ResultSet::getSQLDouble(unsigned int columnIndex) const {
	double ret = 0;

	if (metaData->getSQLType(columnIndex) == SQL_DOUBLE) {
		SQLDOUBLE data = 0;
		SQLINTEGER length = 0;
		SQLRETURN result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_DOUBLE, &data, 1, &length);
		
		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
			throw SQLException(result, "error on getting database data!");

		ret = (SQLDOUBLE) data;
		
	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not double!");
	}

	return ret;

}

SQLDOUBLE ResultSet::getSQLDouble(std::string tableName, std::string columnName) const {
	return getSQLDouble(metaData->getColumnIndex(tableName, columnName));
}

std::string ResultSet::getSQLDecimal(unsigned int columnIndex) const {

	if (metaData->getSQLType(columnIndex) == SQL_DECIMAL) {
		return getSQLString(columnIndex);
	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not decimal!");
	}

}

std::string ResultSet::getSQLDecimal(std::string tableName, std::string columnName) const {
	return getSQLDecimal(metaData->getColumnIndex(tableName, columnName));
}

bool ResultSet::isNull(unsigned int columnIndex) const { 
	SQLINTEGER sqlPtr = 0;
	SQLSMALLINT length = 0;
	SQLINTEGER aux = 0;

	if (metaData->getSQLType(columnIndex) == SQL_INTEGER) {
		SQLRETURN result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_DEFAULT, &sqlPtr, 0, &aux);

		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
			throw SQLException(result, "Error on getting database data!");

	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not integer!");
	}

	return aux == SQL_NULL_DATA;
		
}

bool ResultSet::isNull(std::string tableName, std::string columnName) const {
	return isNull(metaData->getColumnIndex(tableName, columnName));
}

bool ResultSet::next(void) {
	return (SQL_SUCCESS == SQLFetch(stmt->getODBCStatement()));
}

unsigned int ResultSet::getRowCount(void) const {
	SQLINTEGER rowCount = 0;
	SQLRETURN result = SQLRowCount(stmt->getODBCStatement(), &rowCount);
		
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
			throw SQLException(result, "error on getting row count!");

	return (unsigned int) rowCount;

}

std::string ResultSet::getSQLString(unsigned int columnIndex) const {
	SQLPOINTER sqlPtr = 0;
	SQLCHAR strAux[1];
	SQLINTEGER length = 0;
	SQLRETURN result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_CHAR, &strAux, 1, &length);

	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
		throw SQLException(result, "error on getting database data!");

	length++;
	sqlPtr = new SQLCHAR[length];
	SQLINTEGER aux = 0;
	result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_CHAR, sqlPtr, length, &aux);

	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
		throw SQLException(result, "error on getting database data!");
		
	std::string ret = (char*) sqlPtr;
	delete [] ((SQLCHAR*) sqlPtr);

	return ret;

}

std::wstring ResultSet::getSQLWString(unsigned int columnIndex) const {
	SQLPOINTER sqlPtr = 0;
	SQLWCHAR strAux[1];
	SQLINTEGER length = 0;
	SQLRETURN result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_WCHAR, &strAux, 1, &length);

	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
		throw SQLException(result, "error on getting database data!");

	length++;
	sqlPtr = new SQLWCHAR[length];
	SQLINTEGER aux = 0;
	result = SQLGetData(stmt->getODBCStatement(), columnIndex + 1, SQL_C_WCHAR, sqlPtr, length, &aux);

	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
		throw SQLException(result, "error on getting database data!");
		
	std::wstring ret = (wchar_t*) sqlPtr;
	delete [] ((SQLWCHAR*) sqlPtr);

	return ret;

}

std::string ResultSet::getSQLVarchar(unsigned int columnIndex) const {

	if (metaData->getSQLType(columnIndex) == SQL_VARCHAR) {
		return getSQLString(columnIndex);
	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not varchar!");
	}

}

std::string ResultSet::getSQLVarchar(std::string tableName, std::string columnName) const {
	return getSQLVarchar(metaData->getColumnIndex(tableName, columnName));
}

std::wstring ResultSet::getSQLWVarchar(unsigned int columnIndex) const {

	if (metaData->getSQLType(columnIndex) == SQL_WVARCHAR) {
		return getSQLWString(columnIndex);
	} else {
		throw DASInvalidSQLTypeException("Column sql type on index " + columnIndex + (std::string) " is not varchar!");
	}

}

std::wstring ResultSet::getSQLWVarchar(std::string tableName, std::string columnName) const {
	return getSQLWVarchar(metaData->getColumnIndex(tableName, columnName));
}

		};
	};
};
