#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <unistd.h>

#include "pcie_dev.h"

#define MAX_DEVICES 4

typedef enum {
    PNIO_SLAVE_STATION  = 0,
    PNIO_MASTER_STATION = 1,
    EIP_SLAVE_STATION   = 2,
    OTH_STATION         = 3
} PRODUCT_TYPE;

static int g_index = -1;

// 全局变量
static int g_open_devices[MAX_DEVICES] = {0};  // 记录已打开的设备

/**
 * @brief 清空输入缓冲区
 */
void clear_input_buffer() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

/**
 * @brief 获取用户输入的整数
 * @param prompt 提示信息
 * @return 输入的整数值
 */
int get_user_int(const char* prompt) {
    int value;
    printf("%s", prompt);
    if (scanf("%d", &value) != 1) {
        clear_input_buffer();
        return -1;
    }
    clear_input_buffer();
    return value;
}

/**
 * @brief 获取用户输入的字符串
 * @param prompt 提示信息
 * @param buffer 存储缓冲区
 * @param size 缓冲区大小
 * @return 成功返回 0，失败返回 -1
 */
int get_user_string(const char* prompt, char* buffer, int size) {
    printf("%s", prompt);
    if (fgets(buffer, size, stdin) == NULL) {
        return -1;
    }
    // 移除换行符
    buffer[strcspn(buffer, "\n")] = 0;
    return 0;
}

/**
 * @brief 显示主菜单
 */
void show_main_menu() {
    printf("\n");
    printf("===========================================\n");
    printf("       PCIe Device Demo Program\n");
    printf("===========================================\n");
    printf("1. Initialize Devices (初始化设备)\n");
    printf("2. Open Device (打开设备)\n");
    printf("3. Close Device (关闭设备)\n");
    printf("4. Deinitialize Devices (反初始化设备)\n");
    printf("5. Get Device Network Info (获取设备网络信息)\n");
    printf("6. Set Device Network Info (设置设备网络信息)\n");
    printf("7. Get EIP Slave Info (获取EIP从站信息)\n");
    printf("8. Get Module Data (获取模块数据)\n");
    printf("9. Set Module Data (设置模块数据)\n");
    printf("0. Exit (退出)\n");
    printf("===========================================\n");
    printf("Please choose: ");
}

/**
 * @brief 初始化所有 PCIe 设备
 */
void demo_init_devices() {
    int ret;
    printf("\n>>> Initializing PCIe devices...\n");
    
    ret = device_init();
    if (ret < 0) {
        printf("ERROR: Failed to initialize devices (ret=%d)\n", ret);
        return;
    }
    
    printf("SUCCESS: Found %d PCIe EIP device(s)\n", ret);
}

/**
 * @brief 打开指定设备
 */
void demo_open_device() {
    int index;
    int res;
    
    index = get_user_int("Enter device index (0-3): ");
    if (index < 0 || index >= MAX_DEVICES) {
        printf("ERROR: Invalid device index\n");
        return;
    }
    
    // EIP slave type : 2
    res = device_open(index, EIP_SLAVE_STATION);
    if (res) {
        g_index = index;
        printf("SUCCESS: Device %d opened as EIP slave %d\n", index, res);
    } else {
        printf("ERROR: Failed to open device %d\n", index);
    }
}

/**
 * @brief 关闭指定设备
 */
void demo_close_device() {
    int index;
    
    index = get_user_int("Enter device index to close (0-3): ");
    if (index < 0 || index >= MAX_DEVICES) {
        printf("ERROR: Invalid device index\n");
        return;
    }
    
    if (g_index < 0) {
        printf("WARNING: Device %d is not open\n", index);
        return;
    }
    
    printf("Closing device %d...\n", index);
    if (device_close(index)) {
        g_open_devices[index] = 0;
        printf("SUCCESS: Device %d closed\n", index);
    } else {
        printf("ERROR: Failed to close device %d\n", index);
    }
}

/**
 * @brief 反初始化所有设备
 */
void demo_deinit_devices() {
    printf("\n>>> Deinitializing all devices...\n");
    
    // 先关闭所有打开的设备
    for (int i = 0; i < MAX_DEVICES; i++) {
        if (g_open_devices[i]) {
            printf("Closing device %d...\n", i);
            device_close(i);
            g_open_devices[i] = 0;
        }
    }
    
    if (device_deinit()) {
        printf("SUCCESS: All devices deinitialized\n");
    } else {
        printf("ERROR: Failed to deinitialize devices\n");
    }
}

/**
 * @brief 获取设备网络信息
 */
void demo_get_network_info() {
    DEVICE_NET_T net;
    
    if (g_index < 0) {
        printf("ERROR: Invalid device index\n");
        return;
    }
    
    sprintf(net.name, "eth0");
    if (device_net_get(g_index, &net) == true) {
        printf("--- Network Information (Interface %s) ---\n", net.name);
        printf("  MAC: %s\n", net.mac);
        printf("  IP: %s\n", net.ip);
        printf("  Mask: %s\n", net.mask);
        printf("  GW: %s\n", net.gw);

    } else {
        printf("ERROR: Failed to get network information\n");
    }
}

/**
 * @brief 设置设备网络信息
 */
void demo_set_network_info() {
    DEVICE_NET_T net_info;
    
    if (g_index < 0) {
        printf("ERROR: Invalid device index\n");
        return;
    }
    
    printf("\nEnter network configuration:\n");
    
    if (get_user_string("  Name: ", net_info.name, sizeof(net_info.name))) return;
    if (get_user_string("  MAC: ", net_info.mac, sizeof(net_info.mac))) return;
    if (get_user_string("  IP: ", net_info.ip, sizeof(net_info.ip))) return;
    if (get_user_string("  Mask: ", net_info.mask, sizeof(net_info.mask))) return;
    if (get_user_string("  GW: ", net_info.gw, sizeof(net_info.gw))) return;
    
    printf("\nApplying configuration...\n");
    if (device_net_set(g_index, &net_info)) {
        printf("SUCCESS: Network configuration updated\n");
    } else {
        printf("ERROR: Failed to set network configuration\n");
    }
}

/**
 * @brief 获取 EIP 从站信息
 */
void demo_get_eip_slave_info() {
    EIP_SLAVE_INFO_T eip_info;
    
    if (g_index < 0) {
        printf("ERROR: Invalid device index\n");
        return;
    }
    
    if (eip_s_info_get(g_index, &eip_info)) {
        printf("\n--- EIP Slave Information (Device %d) ---\n", g_index);
        printf("  App Version: %s\n", eip_info.app_ver);
        printf("  FW Version: %s\n", eip_info.fw_ver);
        
        printf("\n  Input/Output Buffer Size:\n");
        printf("    Input Size: %d bytes\n", eip_info.in_size);
        printf("    Output Size: %d bytes\n", eip_info.out_size);
        
        printf("\n  Network Interfaces:\n");
        for (int i = 0; i < 2; i++) {
            printf("    [%d] %s - IP: %s, MAC: %s\n", 
                   i, eip_info.net[i].name, 
                   eip_info.net[i].ip, 
                   eip_info.net[i].mac);
        }
    } else {
        printf("ERROR: Failed to get EIP slave information\n");
    }
}

/**
 * @brief 获取模块数据
 */
void demo_get_module_data() {
    int type, offset, size;
    unsigned char buffer[MAX_BUFF_SIZE];
    
    if (g_index < 0) {
        printf("ERROR: Invalid device index\n");
        return;
    }
    
    type = get_user_int("Enter type (0=Input, 1=Output): ");
    if (type < 0 || type > 1) {
        printf("ERROR: Invalid type\n");
        return;
    }
    
    offset = get_user_int("Enter offset: ");
    if (offset < 0) {
        printf("ERROR: Invalid offset\n");
        return;
    }
    
    size = get_user_int("Enter size (max 128): ");
    if (size <= 0 || size > 128) {
        printf("ERROR: Invalid size\n");
        return;
    }
    
    memset(buffer, 0, sizeof(buffer));
    printf("Reading %d bytes from type %d, offset %d...\n", 
           size, type, offset);
    
    if (eip_s_module_data_get(g_index, type, offset, size, buffer)) {
        printf("\n--- Module Data ---\n");
        printf("  Hex dump: ");
        for (int i = 0; i < size; i++) {
            printf("%02X ", buffer[i]);
            if ((i + 1) % 16 == 0) printf("\n            ");
        }
        printf("\n");
        
        printf("  ASCII: ");
        for (int i = 0; i < size; i++) {
            printf("%c", (buffer[i] >= 32 && buffer[i] <= 126) ? buffer[i] : '.');
        }
        printf("\n");
    } else {
        printf("ERROR: Failed to read module data\n");
    }
}

/**
 * @brief 设置模块数据
 */
void demo_set_module_data() {
    int type, offset, size;
    unsigned char buffer[MAX_BUFF_SIZE];
    char input[256];
    
    if (g_index < 0) {
        printf("ERROR: Invalid device index\n");
        return;
    }
    
    type = get_user_int("Enter type (0=Input, 1=Output): ");
    if (type < 0 || type > 1) {
        printf("ERROR: Invalid type\n");
        return;
    }
    
    offset = get_user_int("Enter offset: ");
    if (offset < 0) {
        printf("ERROR: Invalid offset\n");
        return;
    }
    
    size = get_user_int("Enter size (max 128): ");
    if (size <= 0 || size > 128) {
        printf("ERROR: Invalid size\n");
        return;
    }
    
    printf("Enter %d bytes of data (hex format, e.g., '01 02 03 FF'): ", size);
    if (fgets(input, sizeof(input), stdin) == NULL) {
        printf("ERROR: Failed to read input\n");
        return;
    }
    
    // 解析十六进制数据
    memset(buffer, 0, sizeof(buffer));
    char* token = strtok(input, " \t\n");
    int count = 0;
    while (token && count < size) {
        buffer[count++] = (unsigned char)strtoul(token, NULL, 16);
        token = strtok(NULL, " \t\n");
    }
    
    if (count != size) {
        printf("WARNING: Expected %d bytes, got %d bytes\n", size, count);
    }
    
    printf("Writing %d bytes to type %d, offset %d...\n", 
           count, type, offset);
    
    if (eip_s_module_data_set(g_index, type, offset, count, buffer)) {
        printf("SUCCESS: Module data updated\n");
    } else {
        printf("ERROR: Failed to write module data\n");
    }
}



/**
 * @brief 主函数
 */
int main()
{
    int choice;
    
    printf("\n");
    printf("===========================================\n");
    printf("         EtherNet/IP 从站demo示例\n");
    printf("===========================================\n");
    printf("\n");
    
    // 初始化设备状态数组
    memset(g_open_devices, 0, sizeof(g_open_devices));
    
    // 主循环
    while (1) {
        show_main_menu();
        
        choice = get_user_int("");
        if (choice < 0) {
            printf("Invalid input. Please enter a number.\n");
            continue;
        }
        
        switch (choice) {
            case 1:
                demo_init_devices();
                break;
            case 2:
                demo_open_device();
                break;
            case 3:
                demo_close_device();
                break;
            case 4:
                demo_deinit_devices();
                break;
            case 5:
                demo_get_network_info();
                break;
            case 6:
                demo_set_network_info();
                break;
            case 7:
                demo_get_eip_slave_info();
                break;
            case 8:
                demo_get_module_data();
                break;
            case 9:
                demo_set_module_data();
                break;
            case 0:
                printf("\nExiting program...\n");
                // 清理资源
                demo_deinit_devices();
                printf("Goodbye!\n");
                return 0;
            default:
                printf("Invalid choice. Please try again.\n");
                break;
        }
        
        // 短暂延时，让用户看清输出
        usleep(100000);
    }
    
    return 0;
}
