/*
 * Copyright (C) ID TECH.
 *
 * Author: Eric
 *
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "demo_common.h"
#ifndef WIN32
# include <dlfcn.h>
#endif
#include "libIDT_Device.h"
#include <pthread.h>

// void process_device_select();
// void process_exit();
// void display_main_menu();
void
display_rs232_menu();
void
process_rs232_device_select();

extern void
MSR_callBack(int type, IDTMSRData cardData1);
extern void
MSR_callBackp(int type, IDTMSRData * cardData1);
extern void
PIN_callBack(int type, IDTPINData * pinData);
extern void
RKI_callBack(int resultCode, char * macValue);
extern void
LCD_callBack(int type, IDTLCDItem * lcdItem);
// extern char* getDeviceType(int deviceType);
extern int
inputSelection();
extern void
process_exit();
// extern int level;
extern IDT_COMMON_PROCESS Demo_Common_Process;
extern IDT_DEMO_LIB_DISPLAY_MENU idtech_display_menu_from_lib;

// IDT_COMMON_PROCESS Demo_Common_Process;

// IDT_DEMO_LIB_DISPLAY_MENU idtech_display_menu_from_lib;

typedef void (* Demo_Init)(IDT_COMMON_PROCESS pCommonProcess, 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_Init demo_init;
extern Demo_getMenuFn demo_getMenuFn;

int deviceType     = IDT_DEVICE_UNKNOWN;
int comport_number = 0;
int baudrate       = 0;
int rc = 0;

void
init_rs232_demo_lib(int deviceType) {
    Demo_Common_Process.main_display_device_list   = display_rs232_menu;
    Demo_Common_Process.main_process_device_select = process_rs232_device_select;
    Demo_Common_Process.PIN_callBack  = PIN_callBack;
    Demo_Common_Process.LCD_callBack  = LCD_callBack;
    Demo_Common_Process.FW_callBack   = FW_callBack;
    Demo_Common_Process.RKI_callBack  = RKI_callBack;
    Demo_Common_Process.CMR_callBack  = CMR_callBack;
    Demo_Common_Process.CSFS_callBack = CSFS_callBack;
    Demo_Common_Process.SendDataLog   = SendDataLog;
    Demo_Common_Process.ReadDataLog   = ReadDataLog;

    // MSR
    Demo_Common_Process.printMSRData  = printMSRData;
    Demo_Common_Process.MSR_callBack  = MSR_callBack;
    Demo_Common_Process.MSR_callBackp = MSR_callBackp;

    // EMV
    Demo_Common_Process.printBytes = printBytes;
    Demo_Common_Process.printTLV   = printTLV;
    Demo_Common_Process.convertBytesIntoHexStr = convertBytesIntoHexStr;
    Demo_Common_Process.convertHStrIntoHex     = convertHStrIntoHex;
    Demo_Common_Process.EMV_callBack = EMV_callBack;

    Demo_Common_Process.set_emv_Finished = set_emv_Finished;
    Demo_Common_Process.get_emv_Finished = get_emv_Finished;

    Demo_Common_Process.set_pin_Finished = set_pin_Finished;
    Demo_Common_Process.get_pin_Finished = get_pin_Finished;

    Demo_Common_Process.getDUKPT = getDUKPT;
    Demo_Common_Process.inputSelection = inputSelection;
    Demo_Common_Process.printAIDList = printAIDList;

    char libname[256] = { 0 };

    switch (deviceType) {
        #ifdef WIN32
        case IDT_DEVICE_SPECTRUM_PRO_COM:
            sprintf(libname, "libSpectrumPro.dll");
            break;
        case IDT_DEVICE_KIOSK_III_COM:
        case IDT_DEVICE_KIOSK_III_S_COM:
            sprintf(libname, "libKioskIII.dll");
            break;
        case IDT_DEVICE_MINISMART_II_COM:
            sprintf(libname, "libMiniSmartII.dll");
            break;
        case IDT_DEVICE_NEO2_COM:
        case IDT_DEVICE_NEO2_COM + 1:
        case IDT_DEVICE_NEO2_COM + 2:
        case IDT_DEVICE_NEO2_COM + 3:
        case IDT_DEVICE_NEO2_COM + 4:
            sprintf(libname, "libNEO2.dll");
            break;
        case IDT_DEVICE_VP3300_COM:
            sprintf(libname, "libVP3300.dll");
            break;
        #endif /* ifdef WIN32 */
        #ifdef __linux
        case IDT_DEVICE_SPECTRUM_PRO_COM:
            sprintf(libname, "libSpectrumPro.so");
            break;
        case IDT_DEVICE_KIOSK_III_COM:
        case IDT_DEVICE_KIOSK_III_S_COM:
            sprintf(libname, "libKioskIII.so");
            break;
        case IDT_DEVICE_MINISMART_II_COM:
            sprintf(libname, "libMiniSmartII.so");
            break;
        case IDT_DEVICE_NEO2_COM:
        case IDT_DEVICE_NEO2_COM + 1:
        case IDT_DEVICE_NEO2_COM + 2:
        case IDT_DEVICE_NEO2_COM + 3:
        case IDT_DEVICE_NEO2_COM + 4:
            sprintf(libname, "libNEO2.so");
            break;
        case IDT_DEVICE_VP3300_COM:
            sprintf(libname, "libVP3300.so");
            break;
        #endif /* ifdef __linux */
        #ifdef __MACH__
        case IDT_DEVICE_SPECTRUM_PRO_COM:
            sprintf(libname, "libSpectrumPro.dylib");
            break;
        case IDT_DEVICE_KIOSK_III_COM:
        case IDT_DEVICE_KIOSK_III_S_COM:
            sprintf(libname, "libKioskIII.dylib");
            break;
        case IDT_DEVICE_MINISMART_II_COM:
            sprintf(libname, "libMiniSmartII.dylib");
            break;
        case IDT_DEVICE_NEO2_COM:
        case IDT_DEVICE_NEO2_COM + 1:
        case IDT_DEVICE_NEO2_COM + 2:
        case IDT_DEVICE_NEO2_COM + 3:
        case IDT_DEVICE_NEO2_COM + 4:
            sprintf(libname, "libNEO2.dylib");
            break;
        case IDT_DEVICE_VP3300_COM:
            sprintf(libname, "libVP3300.dylib");
            break;
        #endif /* ifdef __MACH__ */
        default:
            break;
    }

    #ifdef WIN32
    void * h = LoadLibrary(libname);
    if (h == NULL) {
        fprintf(stderr, "fail to load %s\n", libname);
        fflush(stdout);
        return;
    }
    #else
    void * h = dlopen(libname, RTLD_LAZY);
    if (h == NULL) {
        fprintf(stderr, "fail to load %s\n", libname);
        fflush(stdout);
        return;
    }
    #endif /* ifdef WIN32 */

    #ifdef WIN32
    demo_init      = (Demo_Init) GetProcAddress(h, "libDemo_init");
    demo_getMenuFn = (Demo_getMenuFn) GetProcAddress(h, "libDemo_getMenuFn");
    demo_init(Demo_Common_Process, &idtech_display_menu_from_lib);
    #else
    demo_init      = (Demo_Init) dlsym(h, "libDemo_init");
    demo_getMenuFn = (Demo_getMenuFn) dlsym(h, "libDemo_getMenuFn");
    #endif
    demo_init(Demo_Common_Process, &idtech_display_menu_from_lib);
} /* init_rs232_demo_lib */

int
rs232_init() {
    int r = RETURN_CODE_ERR_DISCONNECT;
    int i = 0;

    while (r != RETURN_CODE_DO_SUCCESS) {
        process_rs232_device_select();
        if (rc) {
            return 0;
        }
        r = rs232_device_init(deviceType, comport_number, baudrate);
        if (r != RETURN_CODE_DO_SUCCESS) {
            printf("  Fail to init RS232!\n");
            fflush(stdout);
        }
    }
    init_rs232_demo_lib(deviceType);
    return 0;
}

void
process_rs232_device_select() {
    int choice;

    process_exit();

    // Get The Device Type
    deviceType = IDT_DEVICE_UNKNOWN;
    do {
        display_rs232_menu();

        choice = inputSelection();
        if (choice > 0 && choice < 7) {
            switch (choice) {
                case 1:
                    deviceType = IDT_DEVICE_MINISMART_II_COM;
                    break;
                case 2:
                    deviceType = IDT_DEVICE_SPECTRUM_PRO_COM;
                    break;
                case 3:
                    deviceType = IDT_DEVICE_KIOSK_III_COM;
                    break;
                case 4:
                    deviceType = IDT_DEVICE_KIOSK_III_S_COM;
                    break;
                case 5:
                    deviceType = IDT_DEVICE_NEO2_COM;
                    break;
                case 6:
                    deviceType = IDT_DEVICE_VP3300_COM;
                    break;
            }
            char port[5], rate[10];
            printf(
                "Please enter the port number (refer to the port mapping table in the document \"80144504-001_USDK_C_C++_JAVA.pdf\" for the function rs232_device_init())\n");
            fflush(stdout);
            fgets(port, 5, stdin);
            comport_number = atoi(port);
            printf("Please enter baud rate\n");
            fflush(stdout);
            fgets(rate, 10, stdin);
            baudrate = atoi(rate);
            rc       = 0;
            return;
        } else if (choice == 0) {
            //			process_exit();
            rc = 1;
            return;
        }
    } while (choice != 0);
} /* process_rs232_device_select */

void
display_rs232_menu() {
    idtech_display_menu_from_lib.pDisplay_Menu_current = display_rs232_menu;
    int i = 0;
    //	deviceConnectedCount = 0;
    printf("\t\t************************************************\n");
    printf("\t\t*********** IDT Universal SDK ******************\n");
    printf("\t\t****** RS 232 Device Select Options ************\n");
    printf("\t\t0.  Back To Interface Menu\n");
    printf("\t\t1.  MiniSmart II\n");
    printf("\t\t2.  Spectrum Pro\n");
    printf("\t\t3.  Kiosk III/IV\n");
    printf("\t\t4.  Kiosk III S\n");
    printf("\t\t5.  NEO2\n");
    printf("\t\t6.  VP3300\n");
    printf("\t\t************************************************\n");
    fflush(stdout);
}

// void process_exit()
// {
//	device_close();
//
//	printf("Application Exit.\n");
//	fflush(stdout);
// }
