#include "CDBResultSet.h"
#include <string.h>

namespace YADB
{
	CDBResultSet::CDBResultSet()
	{
		__pQueryRes  = 0;
		__CurRow     = 0;
		__FieldCount = 0;
	}

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

	void CDBResultSet::__BuildFNameIdxLst()
	{
		if (0 == __pQueryRes)
		{
			return;
		}

		for ( int i = 0; i < __FieldCount; i++ )
		{
			MYSQL_FIELD *pField = mysql_fetch_field_direct( __pQueryRes, i );
			if ( pField == NULL )
			{
				continue;
			}

			__FNameIndexList.insert( std::make_pair( pField->name, i ) );
		}
	}

	bool CDBResultSet::Bind( MYSQL_RES *pQueryRes, std::string& Error )
	{
		Close();

		__pQueryRes = pQueryRes;
		if ( __pQueryRes != 0 )
		{
			__FieldCount = mysql_num_fields( pQueryRes );
		}
		else
		{
			Error = "Error,pQueryRes is null!";
			__FieldCount = 0;
			return false;
		}

		__BuildFNameIdxLst();

		return true;
	}

	void CDBResultSet::Close()
	{
		if ( 0 == __pQueryRes )
		{
			return;
		}

		mysql_free_result( __pQueryRes );
		__pQueryRes  = 0;
		__CurRow     = 0;
		__FieldCount = 0;
		__FNameIndexList.clear();
	}

	bool CDBResultSet::SeekData( my_ulonglong Offset, std::string& Error )
	{
		if ( 0 == __pQueryRes )
		{
			Error = "Error,__pQueryRes is not initialized!";
			return false;
		}

		mysql_data_seek( __pQueryRes, Offset );

		return true;
	}

	bool CDBResultSet::GetNextRecod( std::string & Error )
	{
		if ( 0 == __pQueryRes )
		{
			Error = "Error,__pQueryRes is not initialized!";
			return false;
		}

		if ( ( __CurRow = mysql_fetch_row( __pQueryRes ) ) != NULL )
		{
			return true;
		}
		else
		{
			Error = "Error, failed to mysql_fetch_row!";
			return false;
		}

		return true;
	}

	my_ulonglong CDBResultSet::GetRecordCount( std::string & Error )
	{
		if ( 0 == __pQueryRes )
		{
			Error = "Error,__pQueryRes is not initialized!";
			return DB_ERR_QUERY_RES_NOT_INITED;
		}

		return mysql_num_rows( __pQueryRes );
	}

	bool CDBResultSet::__GetField( int fdIndex, char*& szValue, bool& IsNull, std::string& Error )
	{
		IsNull = false;

		if ( 0 == __CurRow )
		{
			Error = "Error,__CurRow is not initialized!";
			return false;
		}

		if ( fdIndex < 0 || fdIndex >= __FieldCount )
		{
			Error = "fdIndex is invalid!";
			return false;
		}

		szValue = __CurRow[fdIndex];
		if ( szValue == NULL || szValue[0] == 0)
		{
			IsNull = true;
		}

		return true;
	}

	bool CDBResultSet::GetField( int fdIndex, int & value, std::string & Error )
	{
		value = 0;
		char* pField = 0;
		bool IsNull = false;
        if ( !__GetField( fdIndex, pField, IsNull, Error ) )
        {
            return false;
        }

        if ( !IsNull )
        {
        	value = atoi( pField );
        }

		return true;
	}

	bool CDBResultSet::GetField( int fdIndex, unsigned int & value, std::string & Error )
	{
		value = 0;
		char* pField = 0;
		bool IsNull = false;
		if ( !__GetField( fdIndex, pField, IsNull, Error ) )
		{
			return false;
		}

		if ( !IsNull )
		{
			value = atoi( pField );
		}

		return true;
	}

	bool CDBResultSet::GetField( int fdIndex, long long & value, std::string & Error )
	{
		value = 0;
		char* pField = 0;
		bool IsNull = false;
		if ( !__GetField( fdIndex, pField, IsNull, Error ) )
		{
			return false;
		}

		if ( !IsNull )
		{
			value = atoll(pField);
		}

		return true;
	}

	bool CDBResultSet::GetField( int fdIndex, std::string & value, std::string & Error )
	{
		value = "";

		char* pField = 0;
		bool IsNull = false;
		if ( !__GetField( fdIndex, pField, IsNull, Error ) )
		{
			return false;
		}

		if ( !IsNull )
		{
			value = pField;
		}

		return true;
	}

	bool CDBResultSet::GetField( int fdIndex, char * value, int Length, std::string & Error )
	{
		memset( value, 0, Length );

		char* pField = 0;
		bool IsNull = false;
		if ( !__GetField( fdIndex, pField, IsNull, Error ) )
		{
			return false;
		}

		if ( !IsNull )
		{
			strncpy( value, pField, Length );
		}

		return true;
	}

	bool CDBResultSet::GetField( int fdIndex, bool & value, std::string & Error )
	{
		value = false;
		char* pField = 0;
		bool IsNull = false;
		if ( !__GetField( fdIndex, pField, IsNull, Error ) )
		{
			return false;
		}

		if ( !IsNull )
		{
			value = atoi( pField );
		}

		return true;
	}

	bool CDBResultSet::GetField( int fdIndex, float & value, std::string & Error )
	{
		value = 0.0;
		char* pField = 0;
		bool IsNull = false;
		if ( !__GetField( fdIndex, pField, IsNull, Error ) )
		{
			return false;
		}

		if ( !IsNull )
		{
			value = atof( pField );
		}

		return true;
    }

	bool CDBResultSet::GetField( int fdIndex, double & value, std::string & Error )
	{
		value = 0.0;
		char* pField = 0;
		bool IsNull = false;
		if (!__GetField( fdIndex, pField, IsNull, Error ) )
		{
			return false;
		}

		if ( !IsNull )
		{
			value = std::stod( pField );
		}

		return true;
	}

	bool CDBResultSet::GetField( int fdIndex, MYSQL_TIME & value, std::string & Error )
	{
		__DBHelper.InitMySQLTime( value );
		char* pField = 0;
		bool IsNull = false;
		if ( !__GetField( fdIndex, pField, IsNull, Error ) )
		{
			return false;
		}

		if ( !IsNull )
		{
			__DBHelper.String2DateTime( pField, value );
		}

		return true;
	}

	int CDBResultSet::GetFdIndexByName( const char * fdName, std::string & Error )
	{
		std::map<std::string,int>::iterator mit_fi;
		mit_fi = __FNameIndexList.find( fdName );
		if ( mit_fi != __FNameIndexList.end() )
		{
			return mit_fi->second;
		}

		Error = "Failed to find field: ";
		Error += fdName;

		return -1;
	}

	bool CDBResultSet::GetField( const char * fdName, int & value, std::string & Error )
	{
		int fdIndex = GetFdIndexByName( fdName, Error );

		if ( fdIndex >= 0 )
		{
			return GetField( fdIndex, value, Error );
		}

		return false;
	}

	bool CDBResultSet::GetField( const char * fdName, long long & value, std::string & Error )
	{
		int fdIndex = GetFdIndexByName( fdName, Error );

		if ( fdIndex >= 0 )
		{
			return GetField( fdIndex, value, Error );
		}

		return false;
	}

	bool CDBResultSet::GetField( const char * fdName, unsigned int & value, std::string & Error )
	{
		int fdIndex = GetFdIndexByName( fdName, Error );

		if ( fdIndex >= 0 )
		{
			return GetField( fdIndex, value, Error );
		}

		return false;
	}

	bool CDBResultSet::GetField( const char * fdName, std::string & value, std::string & Error )
	{
		int fdIndex = GetFdIndexByName( fdName, Error );

		if ( fdIndex >= 0 )
		{
			return GetField( fdIndex, value, Error );
		}

		return false;
	}

	bool CDBResultSet::GetField( const char * fdName, char * value, int Length, std::string & Error )
	{
		int fdIndex = GetFdIndexByName( fdName, Error );

		if ( fdIndex >= 0 )
		{
			return GetField( fdIndex, value, Length, Error );
		}

		return false;
	}

	bool CDBResultSet::GetField( const char * fdName, bool & value, std::string & Error )
	{
		int fdIndex = GetFdIndexByName( fdName, Error );

		if ( fdIndex >= 0 )
		{
			return GetField( fdIndex, value, Error );
		}

		return false;
	}

	bool CDBResultSet::GetField( const char * fdName, float & value, std::string & Error )
	{
		int fdIndex = GetFdIndexByName( fdName, Error );

		if ( fdIndex >= 0 )
		{
			return GetField( fdIndex, value, Error );
		}

		return false;
	}

	bool CDBResultSet::GetField( const char * fdName, double & value, std::string & Error )
	{
		int fdIndex = GetFdIndexByName( fdName, Error );

		if ( fdIndex >= 0 )
		{
			return GetField( fdIndex, value, Error );
		}

		return false;
	}

	bool CDBResultSet::GetField( const char * fdName, MYSQL_TIME & value, std::string & Error )
	{
		int fdIndex = GetFdIndexByName( fdName, Error );

		if ( fdIndex >= 0 )
		{
			return GetField( fdIndex, value, Error );
		}

		return false;
	}

	int CDBResultSet::IsNull( int fdIndex, std::string& Error )
	{
		if (0 == __CurRow)
		{
			Error = "Error,__CurRow is not initialized!";
			return -1;
		}

		if ( fdIndex < 0 || fdIndex >= __FieldCount )
		{
			Error = "fdIndex is invalid!";
			return -1;
		}

		char* pField = __CurRow[fdIndex];
		if ( pField == NULL || pField[0] == 0 )
		{
			return 1;
		}

		return 0;
	}
}
