#include "ODBCRead.h"

// Constructor
ODBCRead::ODBCRead(CString strFile, CString strTable, CString strColumn, CString strCondition) {
    // Initial values
    fail = false;
    n = m = -1;
    data = NULL;
    m_strTable = _T(strTable);
    m_strColumn = _T(strColumn);
    bool where = false;
    if (strCondition != "") {
        m_strCondition = _T(strCondition);
        where = true;
    } else {
        m_strCondition.Empty();
    }
    // SQL count records statement
    m_strCountRecords.Format(_T("SELECT COUNT(*) FROM [%s]"), m_strTable);
    // SQL data statement
    m_strSQL.Format(_T("SELECT %s FROM [%s]"), m_strColumn, strTable);
    // Add conditions on the rows returned
    if (where) {
        m_strCountRecords += _T(" WHERE ") + m_strCondition;
        m_strSQL += _T(" WHERE ") + m_strCondition;
    }
    // Error codes
    NUM_ERRS = 2;
    ERR_DATA_TYPE = 0; ERR_NUM_RECORDS = 1; // Indexes in the ErrorMessage string array
    // Error messages
    m_ErrorMessage = new CString [NUM_ERRS];
    m_ErrorMessage[ERR_DATA_TYPE]   = _T("The data base contains an unsupported data type");
    m_ErrorMessage[ERR_NUM_RECORDS] = _T("An error occurred reading the number of records");
}

// Destructor
ODBCRead::~ODBCRead(void) {
    if (data) {
        delete [] data; data = NULL;
    }
    delete [] m_ErrorMessage;
    m_database.Close();
}

// Get the number of records
long ODBCRead::countRecords(void) {
    CRecordset countRecordset(&m_database);
    countRecordset.Open(CRecordset::forwardOnly,m_strCountRecords,CRecordset::executeDirect);
    CString strValue;
    if (!countRecordset.IsEOF()) countRecordset.GetFieldValue((short)0,strValue);
    countRecordset.Close();
    return (atol(strValue));
}

void ODBCRead::read(void) {    
    // Connect to the database
    try {
        // Open the database
        if (m_strConnect.IsEmpty()) {
            m_database.Open(NULL); // User can select a DSN connection from dialog box
        } else {
            m_database.Open(NULL,false,false,m_strConnect,false); // Use file information
        }

        if (m_database.IsOpen()) {
   	
            // Attach a recordset
            CRecordset recordset(&m_database);

            // Execute the SQL query
            recordset.Open(CRecordset::forwardOnly,m_strSQL,CRecordset::readOnly);

            // Set public data members
            n = countRecords();
            m = recordset.GetODBCFieldCount();
            data = new double [n * m];
	
            CDBVariant  datavalue;
            long        i = 0, k = 0;
            while (!recordset.IsEOF()) {
                for (short j = 0; j < (short)m; j++) {
                    recordset.GetFieldValue(j,datavalue);

                    switch(datavalue.m_dwType) {
                    case(DBVT_BOOL):
                        data[k + j] = (double)datavalue.m_boolVal;
                        break;
                    case(DBVT_SHORT):
                        data[k + j] = (double)datavalue.m_iVal;
                        break;
                    case(DBVT_LONG):
                        data[k + j] = (double)datavalue.m_lVal;
                        break;
                    case(DBVT_SINGLE):
                        data[k + j] = (double)datavalue.m_fltVal;
                        break;
                    case(DBVT_DOUBLE):
                        data[k + j] = (double)datavalue.m_dblVal;
                        break;
                    default:
                        // No support for non-numeric types
                        throw ERR_DATA_TYPE;
                        break;
                    }
                }
                recordset.MoveNext();
                i++;
                k += m;
            }
            
            // Close the recordset
            recordset.Close();

            // Check that all records have been processed
            if (i != n) {
                throw ERR_NUM_RECORDS;
            }
        }
    }
    catch (CDBException* e) {
        AfxMessageBox(e->m_strError); // Present user with ODBC Error in a message box
        e->Delete();                  // Return memory
        ODBCRead::~ODBCRead();
        fail = true;                  // Set fail flag
    }
    catch (unsigned int e) {
        AfxMessageBox(m_ErrorMessage[e]);
        ODBCRead::~ODBCRead();
        fail = true;
    }
}

void ODBCRead::info(bool always) {
    if (always || fail) {
        CString strInfo = (m_strConnect.IsEmpty() ? _T("DSN Connection") : _T("Connection string:\n")+ m_strConnect);
        strInfo += _T("\n\nCount records statement:\n") + m_strCountRecords + _T("\n\nSQL statement:\n") + m_strSQL;
        AfxMessageBox(strInfo);
    }
}
