/*
 * 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/ColumnData.h"

namespace apache {
	namespace das {
		namespace rdb {

ColumnData::ColumnData(const Column& column, ResultSetPtr resultSet) {
	this->column = &column;

	if (column.getContainerTable() == 0) {
		throw std::invalid_argument("Column table not set");
	}

	/*if (resultSet->isNull(column.getContainerTable()->getTableName(), column.getName())) {
		data = 0;

	} else {*/

		switch (column.getSQLType()) {

			case SQL_INTEGER :
				{
					SQLINTEGER sqlInteger = resultSet->getSQLInteger(
						column.getContainerTable()->getTableName(), column.getName());
					
					data = new SQLINTEGER;
					SQLINTEGER* aux = (SQLINTEGER*) data;
					*aux = sqlInteger;

				}

				break;

			case SQL_SMALLINT :
				{
					SQLSMALLINT sqlSmallInt = resultSet->getSQLSmallInt(
						column.getContainerTable()->getTableName(), column.getName());
					
					data = new SQLSMALLINT;
					SQLSMALLINT* aux = (SQLSMALLINT*) data;
					*aux = sqlSmallInt;

				}

				break;

			/*case SQL_BIGINT :
				{
					SQL_BIGINT sqlInteger = resultSet->getSQLInteger(
						column.getContainerTable()->getTableName(), column.getName());
					
					data = new SQL_BIGINT;
					SQL_BIGINT* aux = (SQL_BIGINT*) data;
					*aux = sqlInteger;

				}

				break;*/

			case SQL_CHAR :	
				{
					SQLCHAR sqlChar = resultSet->getSQLChar(column.getContainerTable()->getTableName(), 
						column.getName());

					data = new SQLCHAR;
					SQLCHAR* aux = (SQLCHAR*) data;
					*aux= sqlChar;
				}

				break;

			case SQL_WCHAR :	
				{
					SQLWCHAR sqlWChar = resultSet->getSQLWChar(column.getContainerTable()->getTableName(), 
						column.getName());

					data = new SQLWCHAR;
					SQLWCHAR* aux = (SQLWCHAR*) data;
					*aux= sqlWChar;
				}

				break;

			case SQL_DOUBLE :
				{
					SQLDOUBLE sqlDouble = resultSet->getSQLDouble(column.getContainerTable()->getTableName(), 
						column.getName());

					data = new SQLDOUBLE;
					SQLDOUBLE* aux = (SQLDOUBLE*) data;
					*aux = sqlDouble;
				}

				break;

			case SQL_FLOAT :
				{
					SQLFLOAT sqlFloat = resultSet->getSQLFloat(column.getContainerTable()->getTableName(), 
						column.getName());

					data = new SQLFLOAT;
					SQLFLOAT* aux = (SQLFLOAT*) data;
					*aux = sqlFloat;
				}

				break;

			case SQL_REAL :
				{
					SQLREAL sqlReal = resultSet->getSQLReal(column.getContainerTable()->getTableName(), 
					column.getName());

					data = new SQLREAL;
					SQLREAL* aux = (SQLREAL*) data;
					*aux = sqlReal;
				}

				break;

			case SQL_VARCHAR :
				{
					std::string varchar = resultSet->getSQLVarchar(column.getContainerTable()->getTableName(),
						column.getName());

					data = new std::string(varchar.begin(), varchar.end());
					std::string* aux = (std::string*) data;
					(*aux).assign(varchar.begin(), varchar.end());
				}

				break;

			case SQL_WVARCHAR :
				{
					std::wstring wvarchar = resultSet->getSQLWVarchar(column.getContainerTable()->getTableName(),
						column.getName());

					std::wstring* aux = new std::wstring();
					*aux = wvarchar;
					data = aux;
					
				}

				break;

			default :
				throw DASInvalidSQLTypeException();

		}

	//}

}

ColumnData::ColumnData(const Column& column, const commonj::sdo::Setting& setting) {
	this->column = &column;

	if (column.getContainerTable() == 0) {
		throw std::invalid_argument("Column table not set");
	}

	if (!setting.isSet() || setting.isNull()) {
		data = 0;
	} else {

		switch (column.getSQLType()) {

			case SQL_INTEGER :
				{
					SQLINTEGER sqlInteger = setting.getIntValue();
					
					data = new SQLINTEGER;
					SQLINTEGER* aux = (SQLINTEGER*) data;
					*aux = sqlInteger;

				}

				break;

			case SQL_SMALLINT :
				{
					SQLSMALLINT sqlSmallInt = setting.getIntValue();
					
					data = new SQLSMALLINT;
					SQLSMALLINT* aux = (SQLSMALLINT*) data;
					*aux = sqlSmallInt;

				}

				break;

			case SQL_CHAR :	
				{
					SQLCHAR sqlChar = setting.getCharacterValue();

					data = new SQLCHAR;
					SQLCHAR* aux = (SQLCHAR*) data;
					*aux= sqlChar;
				}

				break;

			case SQL_WCHAR :	
				{
					SQLWCHAR sqlWChar = setting.getCharacterValue();

					data = new SQLWCHAR;
					SQLWCHAR* aux = (SQLWCHAR*) data;
					*aux= sqlWChar;
				}

				break;

			case SQL_DOUBLE :
				{
					SQLDOUBLE sqlDouble = setting.getDoubleValue();

					data = new SQLDOUBLE;
					SQLDOUBLE* aux = (SQLDOUBLE*) data;
					*aux = sqlDouble;
				}

				break;

			case SQL_FLOAT :
				{
					SQLFLOAT sqlFloat = setting.getDoubleValue();

					data = new SQLFLOAT;
					SQLFLOAT* aux = (SQLFLOAT*) data;
					*aux = sqlFloat;
				}

				break;

			case SQL_REAL :
				{
					SQLREAL sqlReal = setting.getFloatValue();

					data = new SQLREAL;
					SQLREAL* aux = (SQLREAL*) data;
					*aux = sqlReal;
				}

				break;

			case SQL_VARCHAR :
				{
					unsigned int length = setting.getLength();
					wchar_t* buffer = new wchar_t[length];
					setting.getStringValue(buffer, length);
					//buffer[length] = 0;

					std::wstring wstr(buffer, 0, length);
					std::string* str = new std::string(wstr.begin(), wstr.end());
					str->assign(wstr.begin(), wstr.end());

					data = str;

					delete [] buffer;

				}

				break;

			case SQL_WVARCHAR :
				{
					unsigned int length = setting.getLength();
					wchar_t* buffer = new wchar_t[length];
					setting.getStringValue(buffer, length);
					//buffer[length] = 0;

					data = new std::wstring(buffer, 0, length);
					
					delete [] buffer;

				}

				break;
			
			default :
				throw DASInvalidSQLTypeException();

		}

	}

}

ColumnData::ColumnData(const Column& column, commonj::sdo::DataObjectPtr dataObject) {
	this->column = &column;

	if (column.getContainerTable() == 0) {
		throw std::invalid_argument("Column table not set");
	}

	if (!dataObject->isSet(column.getPropertyName().c_str()) || dataObject->isNull(column.getPropertyName().c_str())) {
		data = 0;

	} else {
	
		switch (column.getSQLType()) {

			case SQL_INTEGER :
				{
					SQLINTEGER sqlInteger = dataObject->getInt(column.getPropertyName().c_str());
					
					data = new SQLINTEGER;
					SQLINTEGER* aux = (SQLINTEGER*) data;
					*aux = sqlInteger;

				}

				break;

			case SQL_SMALLINT :
				{
					SQLSMALLINT sqlSmallInt = dataObject->getInt(column.getPropertyName().c_str());
					
					data = new SQLSMALLINT;
					SQLSMALLINT* aux = (SQLSMALLINT*) data;
					*aux = sqlSmallInt;

				}

				break;

			case SQL_CHAR :
				{
					SQLCHAR sqlChar = dataObject->getCharacter(column.getPropertyName().c_str());

					data = new SQLCHAR;
					SQLCHAR* aux = (SQLCHAR*) data;
					*aux= sqlChar;
				}

				break;

			case SQL_WCHAR :
				{
					SQLWCHAR sqlWChar = dataObject->getCharacter(column.getPropertyName().c_str());

					data = new SQLWCHAR;
					SQLWCHAR* aux = (SQLWCHAR*) data;
					*aux= sqlWChar;
				}

				break;

			case SQL_DOUBLE :
				{
					SQLDOUBLE sqlDouble = dataObject->getDouble(column.getPropertyName().c_str());

					data = new SQLDOUBLE;
					SQLDOUBLE* aux = (SQLDOUBLE*) data;
					*aux = sqlDouble;
				}

				break;

			case SQL_FLOAT :
				{
					SQLFLOAT sqlFloat = dataObject->getDouble(column.getPropertyName().c_str());

					data = new SQLFLOAT;
					SQLFLOAT* aux = (SQLFLOAT*) data;
					*aux = sqlFloat;
				}

				break;

			case SQL_REAL :
				{
					SQLREAL sqlReal = dataObject->getFloat(column.getPropertyName().c_str());

					data = new SQLREAL;
					SQLREAL* aux = (SQLREAL*) data;
					*aux = sqlReal;
				}

				break;

			case SQL_VARCHAR :
				{
					unsigned int length = dataObject->getLength(column.getPropertyName().c_str());
					wchar_t* buffer = new wchar_t[length];
					dataObject->getString(column.getPropertyName().c_str(), buffer, length);

					std::wstring wstr(buffer, 0, length);
					std::string* str = new std::string(wstr.begin(), wstr.end());
					str->assign(wstr.begin(), wstr.end());

					data = str;

					delete [] buffer;

				}

				break;

			case SQL_WVARCHAR :
				{
					unsigned int length = dataObject->getLength(column.getPropertyName().c_str());
					wchar_t* buffer = new wchar_t[length];
					dataObject->getString(column.getPropertyName().c_str(), buffer, length);

					data = new std::wstring(buffer, 0, length);

					delete [] buffer;

				}

				break;
			
			default :
				throw DASInvalidSQLTypeException();

		}

	}

}

ColumnData::~ColumnData(void) {
	delete data;
}

std::string ColumnData::toSQL(void) const {

	if (data == 0) {
		return "NULL";
	} else {

		switch (column->getSQLType()) {

			case SQL_INTEGER :
				return StringWrapper::toString(*((SQLINTEGER*) data));

			case SQL_SMALLINT :
				return StringWrapper::toString(*((SQLSMALLINT*) data));

			case SQL_CHAR :	
				return '\'' + StringWrapper::toString(*((SQLCHAR*) data)) + '\'';

			case SQL_WCHAR :	
				return '\'' + StringWrapper::toString(*((SQLWCHAR*) data)) + '\'';
				
			case SQL_DOUBLE :
				return StringWrapper::toString(*((SQLDOUBLE*) data));

			case SQL_FLOAT :
				return StringWrapper::toString(*((SQLFLOAT*) data));
				
			case SQL_REAL :
				return StringWrapper::toString(*((SQLREAL*) data));

			case SQL_VARCHAR :
				{
					std::string str = *((std::string*) data);
					return '\'' + str + '\'';

				}

			case SQL_WVARCHAR :
				{
					std::wstring wstr = *((std::wstring*) data);
					std::string str(wstr.begin(), wstr.end());
					str.assign(wstr.begin(), wstr.end());
					return '\'' + str + '\'';

				}
			
			default :
				throw DASInvalidSQLTypeException();

		}

	}

}

void ColumnData::populateDataGraph(TableData& tableData) const {
	try {
		tableData.getGraphObject()->getType().getPropertyIndex(column->getPropertyName().c_str());		

	} catch (commonj::sdo::SDOPropertyNotFoundException&) {
		return;
	}

	if (data == 0) {
		tableData.getGraphObject()->setNull(column->getPropertyName().c_str());

	} else {

		switch (column->getSQLType()) {

			case SQL_INTEGER :
				tableData.getGraphObject()->setInt(column->getPropertyName().c_str(), (long) *((SQLINTEGER*) data));

				break;

			case SQL_SMALLINT :
				tableData.getGraphObject()->setInt(column->getPropertyName().c_str(), (long) *((SQLSMALLINT*) data));

				break;

			case SQL_CHAR :	
				tableData.getGraphObject()->setCharacter(column->getPropertyName().c_str(), (wchar_t) *((SQLCHAR*) data));

				break;

			case SQL_WCHAR :	
				tableData.getGraphObject()->setCharacter(column->getPropertyName().c_str(), (wchar_t) *((SQLWCHAR*) data));

				break;

			case SQL_FLOAT :
				tableData.getGraphObject()->setDouble(column->getPropertyName().c_str(), (long double) *((SQLFLOAT*) data));

			case SQL_DOUBLE :
				tableData.getGraphObject()->setDouble(column->getPropertyName().c_str(), (long double) *((SQLDOUBLE*) data));
				
				break;

			case SQL_REAL :
				tableData.getGraphObject()->setFloat(column->getPropertyName().c_str(), (float) *((SQLREAL*) data));
				
				break;

			case SQL_VARCHAR :
				{
					std::string* varchar = (std::string*) data;
					std::wstring wstr(varchar->begin(), varchar->end());
					wstr.assign(varchar->begin(), varchar->end());

					tableData.getGraphObject()->setString(column->getPropertyName().c_str(), 
						wstr.c_str(), wstr.size());
				}

				break;

			case SQL_WVARCHAR :
				{
					std::wstring* wvarchar = (std::wstring*) data;
					
					tableData.getGraphObject()->setString(column->getPropertyName().c_str(), 
						(*wvarchar).c_str(), (*wvarchar).size());
				}

				break;
			
			default :
				throw DASInvalidSQLTypeException();

		}

	}

}

bool ColumnData::operator==(const ColumnData& columnData) const {

	if (column->getSQLType() != columnData.column->getSQLType()) {
		throw DASInvalidSQLTypeException("Different sql types!");
	}

	if (data == 0) {
		return false;
	}

	switch (column->getSQLType()) {

		case SQL_INTEGER :
			
			if (*((SQLINTEGER*) columnData.data) == *((SQLINTEGER*) data)) {
				return true;
			}

			break;

		case SQL_SMALLINT :
			
			if (*((SQLSMALLINT*) columnData.data) == *((SQLSMALLINT*) data)) {
				return true;
			}

			break;

		case SQL_CHAR :	
			
			if (*((SQLCHAR*) columnData.data) == *((SQLCHAR*) data)) {
				return true;
			}

			break;

		case SQL_WCHAR :	
			
			if (*((SQLWCHAR*) columnData.data) == *((SQLWCHAR*) data)) {
				return true;
			}

			break;

		case SQL_DOUBLE :
			if (*((SQLDOUBLE*) columnData.data) == *((SQLDOUBLE*) data)) {
				return true;
			}

		case SQL_FLOAT :
			if (*((SQLFLOAT*) columnData.data) == *((SQLFLOAT*) data)) {
				return true;
			}

			break;

		case SQL_REAL :
			
			if (*((SQLREAL*) columnData.data) == *((SQLREAL*) data)) {
				return true;
			}

			break;

		case SQL_VARCHAR :
			if (*((std::string*) columnData.data) == *((std::string*) data)) {
				return true;
			}

			break;

		case SQL_WVARCHAR :
			if (*((std::wstring*) columnData.data) == *((std::wstring*) data)) {
				return true;
			}

			break;
		
		default :
			throw DASInvalidSQLTypeException();

	}

	return false;

}

bool ColumnData::operator!=(const ColumnData& columnData) const {
	return !(*this == columnData);
}

const Column& ColumnData::getColumn(void) const {
	return *column;
}

bool ColumnData::operator<(const ColumnData& columnData) const {

	if (column->getSQLType() != columnData.column->getSQLType()) {
		throw DASInvalidSQLTypeException("Different sql types!");
	}

	if (data == 0) {
		return false;
	}

	switch (column->getSQLType()) {

		case SQL_SMALLINT :
			
			if (*((SQLSMALLINT*) columnData.data) > *((SQLSMALLINT*) data)) {
				return true;
			}

			break;

		case SQL_INTEGER :
			
			if (*((SQLINTEGER*) columnData.data) > *((SQLINTEGER*) data)) {
				return true;
			}

			break;

		case SQL_CHAR :	
			
			if (*((SQLCHAR*) columnData.data) > *((SQLCHAR*) data)) {
				return true;
			}

			break;

		case SQL_WCHAR :	
			
			if (*((SQLWCHAR*) columnData.data) > *((SQLWCHAR*) data)) {
				return true;
			}

			break;

		case SQL_DOUBLE :
			if (*((SQLDOUBLE*) columnData.data) > *((SQLDOUBLE*) data)) {
				return true;
			}

		case SQL_FLOAT :
			if (*((SQLFLOAT*) columnData.data) > *((SQLFLOAT*) data)) {
				return true;
			}

			break;

		case SQL_REAL :
			
			if (*((SQLREAL*) columnData.data) > *((SQLREAL*) data)) {
				return true;
			}

			break;

		case SQL_VARCHAR :
			if (*((std::string*) columnData.data) > *((std::string*) data)) {
				return true;
			}

			break;

		case SQL_WVARCHAR :
			if (*((std::wstring*) columnData.data) > *((std::wstring*) data)) {
				return true;
			}

			break;
		
		default :
			throw DASInvalidSQLTypeException();

	}

	return false;

}

bool ColumnData::operator>(const ColumnData& columnData) const {

	if (column->getSQLType() != columnData.column->getSQLType()) {
		throw DASInvalidSQLTypeException("Different sql types!");
	}

	if (data == 0) {
		return false;
	}

	switch (column->getSQLType()) {

		case SQL_INTEGER :
			
			if (*((SQLINTEGER*) columnData.data) < *((SQLINTEGER*) data)) {
				return true;
			}

			break;

		case SQL_SMALLINT :
			
			if (*((SQLSMALLINT*) columnData.data) < *((SQLSMALLINT*) data)) {
				return true;
			}

			break;

		case SQL_CHAR :	
			
			if (*((SQLCHAR*) columnData.data) < *((SQLCHAR*) data)) {
				return true;
			}

			break;

		case SQL_WCHAR :	
			
			if (*((SQLWCHAR*) columnData.data) < *((SQLWCHAR*) data)) {
				return true;
			}

			break;

		case SQL_DOUBLE :
			if (*((SQLDOUBLE*) columnData.data) < *((SQLDOUBLE*) data)) {
				return true;
			}

		case SQL_FLOAT :
			if (*((SQLFLOAT*) columnData.data) < *((SQLFLOAT*) data)) {
				return true;
			}

			break;

		case SQL_REAL :
			
			if (*((SQLREAL*) columnData.data) < *((SQLREAL*) data)) {
				return true;
			}

			break;

		case SQL_VARCHAR :
			if (*((std::string*) columnData.data) < *((std::string*) data)) {
				return true;
			}

			break;

		case SQL_WVARCHAR :
			if (*((std::wstring*) columnData.data) < *((std::wstring*) data)) {
				return true;
			}

			break;
		
		default :
			throw DASInvalidSQLTypeException();

	}

	return false;

}

		};
	};
};
