#include <stdio.h>
#include <emscripten/emscripten.h>
#include <xbase.h>

extern "C" {
    EMSCRIPTEN_KEEPALIVE int execute(int fdHeader, int fdRows, int fdMeta) {
        xb::xbXBase x;
        x.SetMultiUser(xbOff);

        std::shared_ptr<xb::xbDbf> DBTable(new xb::xbDbf4(&x), [](xb::xbDbf *table) {
            fprintf(stdout, "cleanup\n");
            if (table) {
                table->Close();
                delete table;
            }
        });

        xbInt16 iRc = 0;
        if((iRc = DBTable->Open("/input.dat")) != XB_NO_ERROR){
            fprintf(stderr, "ERROR cannot open file\n");
            return 1;
        }

        // STEP1: extract metadata
        xbUInt32 ulRecCnt;
        if((iRc = DBTable->GetRecordCnt(ulRecCnt)) != XB_NO_ERROR){
            fprintf(stderr, "ERROR cannot get record count\n");
            return 1;
        }
        xbInt16 version = DBTable->GetVersion();
        dprintf(fdMeta, "number rows: %d\n", ulRecCnt);
        dprintf(fdMeta, "filetype   : dbf\n");
        switch (version) {
        case 3:
            dprintf(fdMeta, "version    : dBASE III");
            break;
        case 4:
            dprintf(fdMeta, "version    : dBASE IV");
            break;
        case 5:
            dprintf(fdMeta, "version    : dBASE V");
            break;
        case 7:
            dprintf(fdMeta, "version    : dBASE VII");
            break;
        default:
            dprintf(fdMeta, "version    : %d", version);
            break;
        }

        // STEP2: extract headers
        xbInt32 iNoOfFields = DBTable->GetFieldCnt();
        xb::xbString sTemp("NA");
        for(int i = 0; i < iNoOfFields; i++){
            DBTable->GetFieldName(i, sTemp);
            dprintf(fdHeader, "%s", sTemp.Str());
            if (i < iNoOfFields - 1) dprintf(fdHeader, ",");
        }
        fprintf(stdout, "record count rec=%d fields=%d\n", ulRecCnt, DBTable->GetFieldCnt());

        // STEP3: extract rows
        xb::xbString fieldValue("NA");
        for (int i=1; i<=ulRecCnt; i++) {
            if(( iRc = DBTable->GetRecord(i)) != XB_NO_ERROR ){
                return 1;
            }
            for (int j=0; j<iNoOfFields; j++) {
                if(( iRc = DBTable->GetField(j, fieldValue)) < 0 ){
                    return 1;
                }
                dprintf(fdRows, "%s,", fieldValue.Trim().Str());
            }
            dprintf(fdRows, "\n");
        }

        return 0;
    }
}
