#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "IDTDef.h"
#include "libIDT_Device.h"
#include "LanguageInfo.h"
#include "Terminal_LCD.h"
#include "Terminal_PINPad.h"
#include "demo_common.h"

#define _BUF_LEN 1024

#if defined(WIN32) || defined(__MACH__)
SHARED_SYMBOLS int emv_canceled;
SHARED_SYMBOLS int emv_start;
SHARED_SYMBOLS int isDeviceTransaction;
SHARED_SYMBOLS int isFromEMVMenu;
SHARED_SYMBOLS int ctls_language;
#else
EXPORT_SYMBOLS int emv_canceled        = 0;
EXPORT_SYMBOLS int emv_start           = 0;
EXPORT_SYMBOLS int isDeviceTransaction = 0;
EXPORT_SYMBOLS int isFromEMVMenu       = 0;
EXPORT_SYMBOLS int ctls_language       = 0;
#endif /* if defined(WIN32) || defined(__MACH__) */

extern IDT_DEMO_LIB_DISPLAY_MENU idtech_display_menu_from_lib;
typedef void (* Demo_getMenuFn)(IDT_DEMO_LIB_DISPLAY_MENU * idtech_display_menu_from_lib);
extern Demo_getMenuFn demo_getMenuFn;

int noMessage = 0;

void
clearDisplay() {
    int i = 0;
    for (i = 0; i < 256; i++) {
        printf("\b");
    }
}

void
processEMVCallback(EMV_Callback * emvCallback);
void
processEMVData(IDTTransactionData * cardData);
void
emvCompleted();
void
controlLED();
void
printEMVResult(int emv_resultCode);
void
printBytes(BYTE * data, int len) {
    int m = 0;

    for (m = 0; m < len; m++) {
        printf("%02X ", data[m]);
    }
    printf("\n");
    fflush(stdout);
}

void
printTLV(BYTE * data, int len) {
    IDT_LOG_MESSAGE(LOG_LEVEL_INFORMATION, "\nprintTLV:\n", 0, NULL, PRINTF_FORMAT, __FILE_NAME__, __LINE__, __func__);

    int m             = 0;
    int pos           = 0;
    int length        = 0;
    int lengthCounter = 0;

    for (m = 0; m < len; m++) {
        if (pos == 0) {
            if ((data[m] & 0x1F) == 0x1f) {
                if ((data[m + 1] & 0x80) == 0x80 && (data[m] != 0xFF || !isAIDTag(data[m + 1]))) {
                    printf("  %02X%02X%02X: ", data[m], data[m + 1], data[m + 2]);
                    pos = pos + 3;
                } else {
                    printf("  %02X%02X:   ", data[m], data[m + 1]);
                    pos = pos + 2;
                }
            } else {
                printf("  %02X:     ", data[m]);
                pos = pos + 1;
            }

            if ((data[m + pos] & 0x80) != 0x80) {
                length = data[m + pos];
                if (length > 0) {
                    pos = pos + 1;
                }
                m = m + pos;
            } else if (data[m + pos] == 0x81) {
                length = data[m + pos + 1];
                pos    = pos + 2;
                m      = m + pos;
            } else {
                length = ((data[m + pos + 1] * 0x100) + data[m + pos + 2]);
                pos    = pos + 3;
                m      = m + pos;
            }
        }
        if (length == 0) {
            pos = 0;
            lengthCounter = 0;
            printf("\n");
        } else {
            printf("%02X", data[m]);
            lengthCounter++;
            if (lengthCounter == length) {
                pos = 0;
                lengthCounter = 0;
                printf("\n");
            }
        }
    }
    printf("\n");
    fflush(stdout);
} /* printTLV */

int
convertBytesIntoHexStr(IN BYTE * hexData, IN int datalen, IN int withChar_LineFeed, OUT char * str) {
    int i   = 0;
    int end = 0;

    for (i = 0; i < datalen; i++) {
        sprintf(str, "%s%02X ", str, hexData[i]);
        end += 3;
        if (1 == withChar_LineFeed) {
            if (0 == ((i + 1) % 16)) {
                sprintf(str, "%s\n", str);
                end += 1;
            }
        }
    }
    str[end] = 0;
    return RETURN_CODE_DO_SUCCESS;
}

int
printAIDList(IN BYTE * hexData, IN int datalen) {
    if (hexData == NULL || datalen == 0) {
        return RETURN_CODE_FAILED;
    }
    int i        = 0;
    int j        = 0;
    int idx      = 2;
    int AIDCount = (hexData[1] << 8) | hexData[0];
    for (i = 0; i < AIDCount; i++) {
        int AIDLen = (hexData[idx + 1] << 8) | hexData[idx];
        idx += 2;
        for (j = 0; j < AIDLen; j++) {
            printf("%02X", hexData[idx + j]);
        }
        printf("\n");
        idx += AIDLen;
    }
    fflush(stdout);
    return RETURN_CODE_DO_SUCCESS;
}

int
convertHStrIntoHex(const char * srcStr, BYTE * hexData, int * datalen) {
    if (NULL == srcStr) {
        return RETURN_CODE_ERR_INVALID_PARAMETER;
    }
    if (NULL == hexData) {
        return RETURN_CODE_ERR_INVALID_PARAMETER;
    }
    char src[_BUF_LEN * 8];
    memset(src, 0, _BUF_LEN * 8);
    int lenT = strlen(srcStr);

    int k = 0;
    int i = 0;
    for (i = 0; i < lenT; i++) {
        if ((' ' == srcStr[i]) || (',' == srcStr[i]) || ('\n' == srcStr[i]) || ('\r' == srcStr[i])) {
            continue;
        }
        src[k++] = srcStr[i];
    }
    src[k] = 0;

    int realLen = k;
    if (0 != (k % 2)) {
        return RETURN_CODE_ERR_INVALID_PARAMETER;
    }
    int len = realLen / 2;
    if (len > *datalen) {
        return RETURN_CODE_ERR_INVALID_PARAMETER;
    }
    *datalen = len;

    char * asc_string = (char *) malloc(len * 2 + 1);
    strcpy(asc_string, src);
    char c = 0x00;
    for (i = 0; i < len * 2; i++) {
        c = asc_string[i];
        if ((c >= 0x30) && (c <= 0x39)) {
            asc_string[i] -= 0x30;
        } else if ((c >= 0x41) && (c <= 0x46)) {
            asc_string[i] -= 0x37;
        } else {
            asc_string[i] -= 0x57;
        }
    }
    int m = 0;
    for (m = 0; m < len; m++) {
        hexData[m] = 16 * asc_string[2 * m] + asc_string[2 * m + 1];
    }
    free(asc_string);
    return RETURN_CODE_DO_SUCCESS;
} /* convertHStrIntoHex */

void
EMV_callBack(int device_type, int device_state, BYTE * data, int dataLen, IDTTransactionData * cardData,
  EMV_Callback * emvCallback, int transactionResultCode) {
    IDT_LOG_MESSAGE(LOG_LEVEL_INFORMATION, ">>>>>Device State>>>>  %d\n", 0, NULL, PRINTF_FORMAT, __FILE_NAME__,
      __LINE__, __func__, device_state);
    char strErr[200] = { 0 };
    switch (device_state) {
        case EMVCallback:
            IDT_LOG_MESSAGE(LOG_LEVEL_INFORMATION, ">>>>>processEMVCallback>>>>>\n", 0, NULL, PRINTF_FORMAT,
              __FILE_NAME__, __LINE__, __func__);
            processEMVCallback(emvCallback);
            break;
        case TransactionData:
            processEMVData(cardData);
            break;
        case TransactionFailed:
            memset(strErr, 0, 200);
            if (isNGA(device_type)) {
                device_getResponseCodeString(transactionResultCode, strErr);
            } else {
                device_getIDGStatusCodeString(transactionResultCode, strErr);
            }
            printf("Transaction Failed: %s;\n", strErr);
            fflush(stdout);
            emvCompleted();
            controlLED();
            break;
        case Notification:
            if (transactionResultCode == EVENT_NOTIFICATION_ICC_Card_Not_Seated) {
                printf("Card Removed\n");
            } else if (transactionResultCode == EVENT_NOTIFICATION_ICC_Card_Seated) {
                printf("Card Inserted\n");
            }
            break;
    }

    if ((isFromEMVMenu == 0 || isDeviceTransaction == 1) && cardData != NULL &&
      cardData->emv_resultCode != EMV_RESULT_CODE_GO_ONLINE &&
      cardData->emv_resultCode != EMV_RESULT_CODE_AUTHENTICATE_TRANSACTION) {
        noMessage = 1;
        demo_getMenuFn(&idtech_display_menu_from_lib);
        if (idtech_display_menu_from_lib.pDisplay_Menu_current) {
            idtech_display_menu_from_lib.pDisplay_Menu_current();
            printf("Please Input your Selection. (0 - exit current menu)\n");
        }
        isDeviceTransaction = 0;
        isFromEMVMenu       = 0;
    }
} /* EMV_callBack */

int auto_emv_authenticate = 1;
int auto_emv_complete     = 1;
int emvFinished = 0;


#ifdef WIN32
static pthread_t threadRunControlLED;
#else
static pthread_t threadRunControlLED = NULL;
#endif

void *
threadDemoControlLED() {
    // check card status
    BYTE status;
    int flash = 0;

    while (1) {
        mssleep(100);
        if (emv_start == 1) {
            emv_start = 0;
            break;
        }
        if (emv_canceled == 1) {
            emv_canceled = 0;
            // turn off the light
            device_controlLED_ICC(0, 0);
            break;
        }
        status = 0;
        icc_getICCReaderStatus(&status);
        BYTE bit1 = (BYTE) ((status & 0x02) >> 1);
        if (bit1 == 1) {
            // flash light
            if (!flash) {
                flash = 1;
                device_controlLED_ICC(2, 500);
            }
        } else {
            // turn off the light
            device_controlLED_ICC(0, 0);
            break;
        }
    }
} /* threadDemoControlLED */

void
emvCompleted() {
    printf("=== EMV completed=== \n");
    fflush(stdout);
    emvFinished = 1;
}

int
EMV_complete() {
    printf("Complete Transaction ");
    fflush(stdout);
    BYTE data1[20];
    int dataLen1 = 20;

    const char * str1 = "30 30";
    int r = convertHStrIntoHex(str1, data1, &dataLen1);
    r = emv_completeTransaction(0, data1, dataLen1, NULL, 0, NULL, 0, NULL, 0);
    if (r != RETURN_CODE_DO_SUCCESS) {
        printf("  Do completeTransaction(), failed!\n");
    } else {
        if (noMessage == 0) {
            printf(" apply host  OK.\n");
        } else {
            noMessage = 0;
        }
    }
    fflush(stdout);
    return r;
}

void *
threadDemoGoOnline() {
    int r = 0;

    IDT_LOG_MESSAGE(LOG_LEVEL_INFORMATION, "\tGO ONLINE PROCESSING;\n", 0, NULL, PRINTF_FORMAT, __FILE_NAME__, __LINE__,
      __func__);

    printf("\tGO ONLINE PROCESSING\n");
    fflush(stdout);
    r = EMV_complete();
    if (r != RETURN_CODE_DO_SUCCESS) {
        char strErr[200] = { 0 };
        memset(strErr, 0, 200);
        if (isNGA(device_getCurrentDeviceType())) {
            device_getResponseCodeString(r, strErr);
        } else {
            device_getIDGStatusCodeString(r, strErr);
        }
        printf(
            ">>>>>>>>>>>>FAIL<<<<<<<<<<<<< \n   ----- Complete EMV Transaction failed!! ErrorCode:0x%02x ,Info: %s ----- \n", r,
            strErr);
        fflush(stdout);

        if (r == RETURN_CODE_P2_DECLINED) {
            emvCompleted();

            if (isDeviceTransaction == 1) {
                noMessage = 1;
                demo_getMenuFn(&idtech_display_menu_from_lib);
                if (idtech_display_menu_from_lib.pDisplay_Menu_current) {
                    idtech_display_menu_from_lib.pDisplay_Menu_current();
                    printf("Please Input your Selection. (0 - exit current menu)\n");
                }
                isDeviceTransaction = 0;
            }
        }

        return 0;
    }
} /* threadDemoGoOnline */

int
EMV_authenticate() {
    printf("Authenticate Transaction ");
    fflush(stdout);
    int r = emv_authenticateTransaction(NULL, 0);
    if (r != RETURN_CODE_DO_SUCCESS) {
        printf("  Do authenticateTransaction(), failed!\n");
    } else {
        printf(" authenticate  OK.\n");
    }
    fflush(stdout);
    return r;
}

void *
threadDemoAuthenticate() {
    int r = 0;

    IDT_LOG_MESSAGE(LOG_LEVEL_INFORMATION, "AUTHENTICATE PROCESSING;\n", 0, NULL, PRINTF_FORMAT, __FILE_NAME__,
      __LINE__, __func__);

    printf("AUTHENTICATE PROCESSING\n");
    fflush(stdout);
    r = EMV_authenticate();
    if (r != RETURN_CODE_DO_SUCCESS) {
        printf(">>Authenticate EMV Trans failed!.");
        fflush(stdout);
        return 0;
    }
}

void
controlLED() {
    switch (device_getCurrentDeviceType()) {
        case IDT_DEVICE_AUGUSTA_HID:
        case IDT_DEVICE_AUGUSTA_KB:
        case IDT_DEVICE_AUGUSTA_S_HID:
        case IDT_DEVICE_AUGUSTA_S_KB:
        case IDT_DEVICE_AUGUSTA_S_TTK_HID:
            break;
        default:
            return;
    }
    mssleep(100);
    int rc = pthread_create(&threadRunControlLED, NULL, threadDemoControlLED, NULL);
    if (rc != 0) {
        IDT_LOG_MESSAGE(LOG_LEVEL_INFORMATION, "create thread, %s\n", 0, NULL, PRINTF_FORMAT, __FILE_NAME__, __LINE__,
          __func__, strerror(rc));
    }
    pthread_detach(threadRunControlLED);
}

#ifdef WIN32
static pthread_t threadRunGoOnline;
static pthread_t threadRunAuthenticate;
#else
static pthread_t threadRunGoOnline     = NULL;
static pthread_t threadRunAuthenticate = NULL;
#endif

void
processEMVData(IDTTransactionData * cardData) {
    printf("EMV Result Code %04X\n", cardData->emv_resultCode);
    printf("Has Reversal %d\n", cardData->emv_hasReversal);
    if (cardData->emv_resultCode == EMV_RESULT_CODE_FALLBACK_TO_MSR) {
        printTransactionData(cardData);
    } else if (cardData->emv_resultCode == EMV_RESULT_CODE_SWIPE_NON_ICC) {
        printTransactionData(cardData);
    } else {
        if (cardData->emv_resultCode == EMV_RESULT_CODE_GO_ONLINE_CTLS) {
            printf("cardData Len: %d\ncardData:\n", cardData->msr_rawDataLen);
            printData(cardData->msr_rawData, cardData->msr_rawDataLen, 0);
        }
        printf("\nUnencrypted Tags\n");
        printTLV(cardData->emv_unencryptedTags, cardData->emv_unencryptedTagsLen);
        printf("\nEncrypted Tags\n");
        printTLV(cardData->emv_encryptedTags, cardData->emv_encryptedTagsLen);
        printf("\nMasked Tags\n");
        printTLV(cardData->emv_maskedTags, cardData->emv_maskedTagsLen);
    }
    switch (cardData->emv_resultCode) {
        case EMV_RESULT_CODE_APPROVED_OFFLINE:
            printEMVResult(EMV_RESULT_CODE_APPROVED_OFFLINE);
            emvCompleted();
            controlLED();
            break;
        case EMV_RESULT_CODE_DECLINED_OFFLINE:
            printEMVResult(EMV_RESULT_CODE_DECLINED_OFFLINE);
            emvCompleted();
            controlLED();
            break;
        case EMV_RESULT_CODE_APPROVED:
            printEMVResult(EMV_RESULT_CODE_APPROVED);
            emvCompleted();
            controlLED();
            break;
        case EMV_RESULT_CODE_DECLINED:
            printEMVResult(EMV_RESULT_CODE_DECLINED);
            emvCompleted();
            controlLED();
            break;
        case EMV_RESULT_CODE_GO_ONLINE:
            printEMVResult(EMV_RESULT_CODE_GO_ONLINE);
            if (emv_getAutoCompleteTransaction() == 0) {
                emvCompleted();
            }
            break;
        case EMV_RESULT_CODE_CALL_YOUR_BANK:
            printEMVResult(EMV_RESULT_CODE_CALL_YOUR_BANK);
            emvCompleted();
            controlLED();
            break;
        case EMV_RESULT_CODE_NOT_ACCEPTED:
            printEMVResult(EMV_RESULT_CODE_NOT_ACCEPTED);
            emvCompleted();
            controlLED();
            break;
        case EMV_RESULT_CODE_FALLBACK_TO_MSR:
            printEMVResult(EMV_RESULT_CODE_FALLBACK_TO_MSR);
            emvCompleted();
            controlLED();
            break;
        case EMV_RESULT_CODE_TIMEOUT:
            printEMVResult(EMV_RESULT_CODE_TIMEOUT);
            emvCompleted();
            controlLED();
            break;
        case EMV_RESULT_CODE_GO_ONLINE_CTLS:
            printEMVResult(EMV_RESULT_CODE_GO_ONLINE_CTLS);
            emvCompleted();
            break;
        case EMV_RESULT_CODE_AUTHENTICATE_TRANSACTION:
            printEMVResult(EMV_RESULT_CODE_AUTHENTICATE_TRANSACTION);
            if (emv_getAutoAuthenticateTransaction() == 0) {
                emvCompleted();
            }
            break;
        case EMV_RESULT_CODE_TRANSACTION_CANCELED:
            printEMVResult(EMV_RESULT_CODE_TRANSACTION_CANCELED);
            emvCompleted();
            controlLED();
            break;
        case  EMV_RESULT_CODE_SWIPE_NON_ICC:
            printEMVResult(EMV_RESULT_CODE_SWIPE_NON_ICC);
            emvCompleted();
            controlLED();
            break;
        case EMV_RESULT_CODE_CTLS_TWO_CARDS:
            printEMVResult(EMV_RESULT_CODE_CTLS_TWO_CARDS);
            emvCompleted();
            break;
        case EMV_RESULT_CODE_CTLS_TERMINATE:
            printEMVResult(EMV_RESULT_CODE_CTLS_TERMINATE);
            emvCompleted();
            break;
        case EMV_RESULT_CODE_CARD_COM_ERROR:
            printEMVResult(EMV_RESULT_CODE_CARD_COM_ERROR);
            emvCompleted();
            controlLED();
            break;
        default:
            printEMVResult(cardData->emv_resultCode);
            emvCompleted();
            controlLED();
            break;
    }

    fflush(stdout);
} /* processEMVData */

void
processEMVCallback(EMV_Callback * emvCallback) {
    IDT_LOG_MESSAGE(LOG_LEVEL_INFORMATION, "In Callback\n", 0, NULL, PRINTF_FORMAT, __FILE_NAME__, __LINE__, __func__);
    char str2[_BUF_LEN * 2];
    memset(str2, 0, _BUF_LEN * 2);
    convertBytesIntoHexStr(emvCallback->lcd_messages, strlen(emvCallback->lcd_messages), 1, str2);
    IDT_LOG_MESSAGE(LOG_LEVEL_INFORMATION, "processEMVCallback:  LCD Display = %s;\n", 0, NULL, PRINTF_FORMAT,
      __FILE_NAME__, __LINE__, __func__, str2);

    if (emvCallback->callbackType == EMV_CALLBACK_TYPE_LCD) { // LCD Callback Type
        if (emvCallback->lcd_displayMode == EMV_LCD_DISPLAY_MODE_CLEAR_SCREEN) {
            clearDisplay();

            return;
        } else if (emvCallback->lcd_displayMode ==
          EMV_LCD_DISPLAY_MODE_MESSAGE /*|| emvCallback->lcd_displayMode == EMV_LCD_DISPLAY_MODE_PAUSE*/) {
            if (emvCallback->lcd_messageMode == EMV_LCD_DISPLAY_MESSAGE_MODE_4) {
                showMessageOnLCD(emvCallback, emvCallback->language, emvCallback->lcd_messages);
                emv_callbackResponseLCD(EMV_LCD_DISPLAY_MODE_PAUSE, 0);
            } else {
                showMessageOnLCD(emvCallback, emvCallback->language, emvCallback->lcd_messages);
            }
        } else {
            // Display message with menu/language or prompt, and return result to emv_callbackResponseLCD
            // Kernel will not proceed until this step is complete
            processLCDMenuSelect(emvCallback);
        }
    }
    if (emvCallback->callbackType == EMV_CALLBACK_TYPE_PINPAD) { // PIN Callback Type
        // Provide PIN information to emv_callbackResponsePIN
        // Kernel will not proceed until this step is complete
        processLCDMenuSelect(emvCallback);
    }
    if (emvCallback->callbackType == EMV_CALLBACK_MSR) { // MSR Callback Type
        // Provide MSR Swipe information to emv_callbackResponseMSR
        // Kernel will not proceed until this step is complete
        showMessageOnLCD(emvCallback, emvCallback->language, emvCallback->lcd_messages);
    }
} /* processEMVCallback */

void
printEMVResult(int emv_resultCode) {
    switch (emv_resultCode) {
        case EMV_RESULT_CODE_APPROVED_OFFLINE:
            printf("EMV_RESULT_CODE_APPROVED_OFFLINE\n");
            return;

        case EMV_RESULT_CODE_DECLINED_OFFLINE:
            printf("EMV_RESULT_CODE_DECLINED_OFFLINE\n");
            return;

        case EMV_RESULT_CODE_APPROVED:
            printf("EMV_RESULT_CODE_APPROVED\n");
            return;

        case EMV_RESULT_CODE_DECLINED:
            printf("EMV_RESULT_CODE_DECLINED\n");
            return;

        case EMV_RESULT_CODE_GO_ONLINE:
            printf("EMV_RESULT_CODE_GO_ONLINE\n");
            return;

        case EMV_RESULT_CODE_CALL_YOUR_BANK:
            printf("EMV_RESULT_CODE_CALL_YOUR_BANK\n");
            return;

        case EMV_RESULT_CODE_NOT_ACCEPTED:
            printf("EMV_RESULT_CODE_NOT_ACCEPTED\n");
            return;

        case EMV_RESULT_CODE_FALLBACK_TO_MSR:
            printf("EMV_RESULT_CODE_FALLBACK_TO_MSR\n");
            return;

        case EMV_RESULT_CODE_TIMEOUT:
            printf("EMV_RESULT_CODE_TIMEOUT\n");
            return;

        case EMV_RESULT_CODE_GO_ONLINE_CTLS:
            printf("EMV_RESULT_CODE_GO_ONLINE_CTLS\n");
            return;

        case EMV_RESULT_CODE_AUTHENTICATE_TRANSACTION:
            printf("EMV_RESULT_CODE_AUTHENTICATE_TRANSACTION\n");
            return;

        case EMV_RESULT_CODE_TRANSACTION_CANCELED:
            printf("EMV_RESULT_CODE_TRANSACTION_CANCELED\n");
            return;

        case EMV_RESULT_CODE_SWIPE_NON_ICC:
            printf("EMV_RESULT_CODE_SWIPE_NON_ICC\n");
            return;

        case EMV_RESULT_CODE_CTLS_TWO_CARDS:
            printf("EMV_RESULT_CODE_CTLS_TWO_CARDS\n");
            return;

        case EMV_RESULT_CODE_CTLS_TERMINATE:
            printf("EMV_RESULT_CODE_CTLS_TERMINATE\n");
            return;

        case EMV_RESULT_CODE_CTLS_TERMINATE_TRY_ANOTHER:
            printf("EMV_RESULT_CODE_CTLS_TERMINATE_TRY_ANOTHER\n");
            return;

        case EMV_RESULT_CODE_UNABLE_TO_REACH_HOST:
            printf("EMV_RESULT_CODE_UNABLE_TO_REACH_HOST\n");
            return;

        case EMV_RESULT_CODE_PROCESS_CANCELLED:
            printf("EMV_RESULT_CODE_PROCESS_CANCELLED\n");
            return;

        case EMV_RESULT_CODE_FILE_ARG_INVALID:
            printf("EMV_RESULT_CODE_FILE_ARG_INVALID\n");
            return;

        case EMV_RESULT_CODE_FILE_OPEN_FAILED:
            printf("EMV_RESULT_CODE_FILE_OPEN_FAILED\n");
            return;

        case EMV_RESULT_CODE_FILE_OPERATION_FAILED:
            printf("EMV_RESULT_CODE_FILE_OPERATION_FAILED\n");
            return;

        case EMV_RESULT_CODE_MEMORY_NOT_ENOUGH:
            printf("EMV_RESULT_CODE_MEMORY_NOT_ENOUGH\n");
            return;

        case EMV_RESULT_CODE_SMARTCARD_OK:
            printf("EMV_RESULT_CODE_SMARTCARD_OK\n");
            return;

        case EMV_RESULT_CODE_SMARTCARD_FAIL:
            printf("EMV_RESULT_CODE_SMARTCARD_FAIL\n");
            return;

        case EMV_RESULT_CODE_SMARTCARD_INIT_FAILED:
            printf("EMV_RESULT_CODE_SMARTCARD_INIT_FAILED\n");
            return;

        case EMV_RESULT_CODE_FALLBACK_SITUATION:
            printf("EMV_RESULT_CODE_FALLBACK_SITUATION\n");
            return;

        case EMV_RESULT_CODE_SMARTCARD_ABSENT:
            printf("EMV_RESULT_CODE_SMARTCARD_ABSENT\n");
            return;

        case EMV_RESULT_CODE_SMARTCARD_TIMEOUT:
            printf("EMV_RESULT_CODE_SMARTCARD_TIMEOUT\n");
            return;

        case EMV_RESULT_CODE_MSR_CARD_ERROR:
            printf("EMV_RESULT_CODE_MSR_CARD_ERROR\n");
            return;

        case EMV_RESULT_CODE_PARSING_TAGS_FAILED:
            printf("EMV_RESULT_CODE_PARSING_TAGS_FAILED\n");
            return;

        case EMV_RESULT_CODE_CARD_DATA_ELEMENT_DUPLICATE:
            printf("EMV_RESULT_CODE_CARD_DATA_ELEMENT_DUPLICATE\n");
            return;

        case EMV_RESULT_CODE_DATA_FORMAT_INCORRECT:
            printf("EMV_RESULT_CODE_DATA_FORMAT_INCORRECT\n");
            return;

        case EMV_RESULT_CODE_APP_NO_TERM:
            printf("EMV_RESULT_CODE_APP_NO_TERM\n");
            return;

        case EMV_RESULT_CODE_APP_NO_MATCHING:
            printf("EMV_RESULT_CODE_APP_NO_MATCHING\n");
            return;

        case EMV_RESULT_CODE_MANDATORY_OBJECT_MISSING:
            printf("EMV_RESULT_CODE_MANDATORY_OBJECT_MISSING\n");
            return;

        case EMV_RESULT_CODE_APP_SELECTION_RETRY:
            printf("EMV_RESULT_CODE_APP_SELECTION_RETRY\n");
            return;

        case EMV_RESULT_CODE_AMOUNT_ERROR_GET:
            printf("EMV_RESULT_CODE_AMOUNT_ERROR_GET\n");
            return;

        case EMV_RESULT_CODE_CARD_REJECTED:
            printf("EMV_RESULT_CODE_CARD_REJECTED\n");
            return;

        case EMV_RESULT_CODE_AIP_NOT_RECEIVED:
            printf("EMV_RESULT_CODE_AIP_NOT_RECEIVED\n");
            return;

        case EMV_RESULT_CODE_AFL_NOT_RECEIVED:
            printf("EMV_RESULT_CODE_AFL_NOT_RECEIVED\n");
            return;

        case EMV_RESULT_CODE_AFL_LEN_OUT_OF_RANGE:
            printf("EMV_RESULT_CODE_AFL_LEN_OUT_OF_RANGE\n");
            return;

        case EMV_RESULT_CODE_SFI_OUT_OF_RANGE:
            printf("EMV_RESULT_CODE_SFI_OUT_OF_RANGE\n");
            return;

        case EMV_RESULT_CODE_AFL_INCORRECT:
            printf("EMV_RESULT_CODE_AFL_INCORRECT\n");
            return;

        case EMV_RESULT_CODE_EXP_DATE_INCORRECT:
            printf("EMV_RESULT_CODE_EXP_DATE_INCORRECT\n");
            return;

        case EMV_RESULT_CODE_EFF_DATE_INCORRECT:
            printf("EMV_RESULT_CODE_EFF_DATE_INCORRECT\n");
            return;

        case EMV_RESULT_CODE_ISS_COD_TBL_OUT_OF_RANGE:
            printf("EMV_RESULT_CODE_ISS_COD_TBL_OUT_OF_RANGE\n");
            return;

        case EMV_RESULT_CODE_CRYPTOGRAM_TYPE_INCORRECT:
            printf("EMV_RESULT_CODE_CRYPTOGRAM_TYPE_INCORRECT\n");
            return;

        case EMV_RESULT_CODE_PSE_BY_CARD_NOT_SUPPORTED:
            printf("EMV_RESULT_CODE_PSE_BY_CARD_NOT_SUPPORTED\n");
            return;

        case EMV_RESULT_CODE_USER_LANGUAGE_SELECTED:
            printf("EMV_RESULT_CODE_USER_LANGUAGE_SELECTED\n");
            return;

        case EMV_RESULT_CODE_SERVICE_NOT_ALLOWED:
            printf("EMV_RESULT_CODE_SERVICE_NOT_ALLOWED\n");
            return;

        case EMV_RESULT_CODE_NO_TAG_FOUND:
            printf("EMV_RESULT_CODE_NO_TAG_FOUND\n");
            return;

        case EMV_RESULT_CODE_CARD_BLOCKED:
            printf("EMV_RESULT_CODE_CARD_BLOCKED\n");
            return;

        case EMV_RESULT_CODE_LEN_INCORRECT:
            printf("EMV_RESULT_CODE_LEN_INCORRECT\n");
            return;

        case EMV_RESULT_CODE_CARD_COM_ERROR:
            printf("EMV_RESULT_CODE_CARD_COM_ERROR\n");
            return;

        case EMV_RESULT_CODE_TSC_NOT_INCREASED:
            printf("EMV_RESULT_CODE_TSC_NOT_INCREASED\n");
            return;

        case EMV_RESULT_CODE_HASH_INCORRECT:
            printf("EMV_RESULT_CODE_HASH_INCORRECT\n");
            return;

        case EMV_RESULT_CODE_ARC_NOT_PRESENCED:
            printf("EMV_RESULT_CODE_ARC_NOT_PRESENCED\n");
            return;

        case EMV_RESULT_CODE_ARC_INVALID:
            printf("EMV_RESULT_CODE_ARC_INVALID\n");
            return;

        case EMV_RESULT_CODE_COMM_NO_ONLINE:
            printf("EMV_RESULT_CODE_COMM_NO_ONLINE\n");
            return;

        case EMV_RESULT_CODE_TRAN_TYPE_INCORRECT:
            printf("EMV_RESULT_CODE_TRAN_TYPE_INCORRECT\n");
            return;

        case EMV_RESULT_CODE_APP_NO_SUPPORT:
            printf("EMV_RESULT_CODE_APP_NO_SUPPORT\n");
            return;

        case EMV_RESULT_CODE_APP_NOT_SELECT:
            printf("EMV_RESULT_CODE_APP_NOT_SELECT\n");
            return;

        case EMV_RESULT_CODE_LANG_NOT_SELECT:
            printf("EMV_RESULT_CODE_LANG_NOT_SELECT\n");
            return;

        case EMV_RESULT_CODE_TERM_DATA_NOT_PRESENCED:
            printf("EMV_RESULT_CODE_TERM_DATA_NOT_PRESENCED\n");
            return;

        case EMV_RESULT_CODE_APP_BLOCK_AID:
            printf("EMV_RESULT_CODE_APP_BLOCK_AID\n");
            return;

        case EMV_RESULT_CODE_PAN_INVALID:
            printf("EMV_RESULT_CODE_PAN_INVALID\n");
            return;

        case EMV_RESULT_CODE_TRANS_TYPE_NO_SUPPORT:
            printf("EMV_RESULT_CODE_TRANS_TYPE_NO_SUPPORT\n");
            return;

        case EMV_RESULT_CODE_CVM_TYPE_UNKNOWN:
            printf("EMV_RESULT_CODE_CVM_TYPE_UNKNOWN\n");
            return;

        case EMV_RESULT_CODE_CVM_AIP_NOT_SUPPORTED:
            printf("EMV_RESULT_CODE_CVM_AIP_NOT_SUPPORTED\n");
            return;

        case EMV_RESULT_CODE_CVM_TAG_8E_MISSING:
            printf("EMV_RESULT_CODE_CVM_TAG_8E_MISSING\n");
            return;

        case EMV_RESULT_CODE_CVM_TAG_8E_FORMAT_ERROR:
            printf("EMV_RESULT_CODE_CVM_TAG_8E_FORMAT_ERROR\n");
            return;

        case EMV_RESULT_CODE_CVM_CODE_IS_NOT_SUPPORTED:
            printf("EMV_RESULT_CODE_CVM_CODE_IS_NOT_SUPPORTED\n");
            return;

        case EMV_RESULT_CODE_CVM_COND_CODE_IS_NOT_SUPPORTED:
            printf("EMV_RESULT_CODE_CVM_COND_CODE_IS_NOT_SUPPORTED\n");
            return;

        case EMV_RESULT_CODE_CVM_NO_MORE:
            printf("EMV_RESULT_CODE_CVM_NO_MORE\n");
            return;

        case EMV_RESULT_CODE_PIN_BYPASSED_BEFORE:
            printf("EMV_RESULT_CODE_PIN_BYPASSED_BEFORE\n");
            return;

        default:
            printf("EMV_RESULT_CODE_UNKONWN\n");
            return;
    }
} /* printEMVResult */

// void set_auto_emv_authenticate(int auto_authenticate){auto_emv_authenticate = auto_authenticate;}
// int get_auto_emv_authenticate(){return auto_emv_authenticate;};
//
// void set_auto_emv_complete (int auto_complete){auto_emv_complete = auto_complete;}
// int get_auto_emv_complete(){return auto_emv_complete;}

void
set_emv_Finished(int auto_Finished) {
    emvFinished = auto_Finished;
}

int
get_emv_Finished() {
    return emvFinished;
}
