package com.example;

import static com.example.mtnlib.nmc_lib20_err.*;
import static com.example.mtnlib.nmc_lib20_oem.*;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import com.example.mtnlib.nmc_lib20;
import com.example.mtnlib.nmc_lib20.TDevInfo;
import com.example.mtnlib.nmc_lib20.TSearchMode;
import com.example.mtnlib.nmc_lib20_com.HAND;
import com.example.mtnlib.nmc_lib20_com.PHAND;
import com.example.mtnlib.nmc_lib20_ext.TCollectCfg;
import com.example.mtnlib.nmc_lib20_ext.TCollectTrig;

import static com.example.mtnlib.nmc_lib20_ext.*;
import static com.example.mtnlib.nmc_lib20.*;
import static com.example.mtnlib.nmc_lib20_com.*;
import com.sun.jna.*;
import com.sun.jna.ptr.*;

/**
 * Java 示例：使用 JNA 调用 NMC 库进行数据采集
 * 仿照 C++ "数据采集" 测试用例
 */
public class Main {
    /**
     * 检查函数调用结果，处理错误
     */
    public static void checkResult(short result, String operation) {
        if (result != RTN_CMD_SUCCESS) {
            System.err.printf("操作 %s 时发生错误 错误代码: %d%n", operation, result);
        }
    }
 /**
     * 数据采集示例主函数
     */
    public static short gc_example() {
        short rtn = 0;// 指令返回值
        short devNum = 0;// 设备序号，从0开始
        short axisNum = 0;// 轴号，从0开始

        // 句柄
        HAND devHandle = new HAND();// 设备句柄
        HAND axisHandle = new HAND();// 轴句柄
        HAND crdHandle = new HAND();// 坐标系句柄
        PHAND pDevHandle = new PHAND();//设备句柄指针
        PHAND pAxisHandle = new PHAND();//轴句柄指针
        PHAND pCrdHandle = new PHAND();// 坐标系句柄指针

        try {
            // 1. 打开设备
            rtn = NMC_DevOpen(devNum, pDevHandle);
            checkResult(rtn, "NMC_DevOpen");
            devHandle = pDevHandle.getHandle();

            // 2. 打开轴
            rtn = NMC_MtOpen(devHandle, axisNum, pAxisHandle);
            checkResult(rtn, "NMC_MtOpen");
            axisHandle = pAxisHandle.getHandle();

            // 3. 轴使能
            rtn = NMC_MtSetSvOn(axisHandle);
            checkResult(rtn, "NMC_MtSetSvOn");

            // --- 数据采集配置 ---

            // 4. 停止并清除采集状态
            rtn = NMC_CollectOnOff(devHandle, (short) 0);
            checkResult(rtn, "NMC_CollectOnOff");
            NMC_ClearCollectSts(devHandle);
            checkResult(rtn, "NMC_ClearCollectSts");

            // 5. 获取采集变量地址
            //规划位置
            NativeLongByReference pAddr0 = new NativeLongByReference();
            ShortByReference pLen0 = new ShortByReference();
            rtn = NMC_GetCollectDataAddr(devHandle, (short) 0, COLLECT_ADDRESS_PRF_POS, pAddr0, pLen0);
            checkResult(rtn, "NMC_GetCollectDataAddr (PRF_POS)");
            NativeLong addr0 = pAddr0.getValue();
            short len0 = pLen0.getValue();

            //规划速度
            NativeLongByReference pAddr1 = new NativeLongByReference();
            ShortByReference pLen1 = new ShortByReference();
            rtn = NMC_GetCollectDataAddr(devHandle, (short) 0, COLLECT_ADDRESS_CMD_VEL, pAddr1, pLen1);
            checkResult(rtn, "NMC_GetCollectDataAddr (CMD_VEL)");
            NativeLong addr1 = pAddr1.getValue();
            short len1 = pLen1.getValue();

            // 6. 配置采集参数 TCollectCfg
            TCollectCfg cltCfg = new TCollectCfg();
            cltCfg.count = 2;
            cltCfg.interval = 0;
            // ✅ 正确设置结构体中的数组字段（固定长度8）
            cltCfg.address[0].setValue(addr0.longValue());
            cltCfg.address[1].setValue(addr1.longValue());
            cltCfg.length[0] = len0;
            cltCfg.length[1] = len1;

            // 7. 配置触发模式
            TCollectTrig cltTrig = new TCollectTrig();
            cltTrig.mode = COLLECT_MODE_NONE;
            // 其他字段可保持默认

            // 8. 应用采集配置
            rtn = NMC_ConfigCollect(devHandle, cltCfg, cltTrig);
            checkResult(rtn, "NMC_ConfigCollect");

            // 9. 执行 PTP 运动
            rtn = NMC_CollectOnOff(devHandle, (short) 1);
            checkResult(rtn, "NMC_CollectOnOff (Start)");

            // 10. 启动运动（采集已启动）
            rtn = NMC_MtMovePtpRel(axisHandle, 1.0, 1.0, 0.0, 0.0, 10.0, (short) 0, new NativeLong(10000));
            checkResult(rtn, "NMC_MtMovePtpRel");


            double[] data = new double[8192];

            // 11. 等待运动完成
            ShortByReference pAxisSts = new ShortByReference();
            while (true) {
                rtn = NMC_MtGetSts(axisHandle, pAxisSts);
                checkResult(rtn, "NMC_MtGetSts");
                if ((pAxisSts.getValue() & BIT_AXIS_BUSY) != BIT_AXIS_BUSY) {
                    break;
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.err.println("Motion wait interrupted.");
                    break;
                }
            }

            // 12. 停止采集
            rtn = NMC_CollectOnOff(devHandle, (short) 0);
            checkResult(rtn, "NMC_CollectOnOff(stop)");

            // 13. 获取采集状态
            ShortByReference pCltSts = new ShortByReference();
            NativeLongByReference pDataLen = new NativeLongByReference();
            rtn = NMC_GetCollectSts(devHandle, pCltSts, pDataLen);
            checkResult(rtn, "NMC_GetCollectSts");

            NativeLong dataLen = pDataLen.getValue();
            System.out.println("Collected data length: " + dataLen + " bytes");
            
            // 14. 读取采集数据
            //a.定义相关变量
            int blockSize = 1440;       // 每次最多读 1440 字节
            int doublesPerBlock = 180;     // 1440 字节 = 180 个 double (1440 / 8)
            
            // 临时字节缓冲区，用于接收数据
            byte[] buffer = new byte[blockSize];

            // 计算分多少块
            int count = (int) dataLen.longValue() / blockSize;        // 完整块数
            int remainder = (int) dataLen.longValue() % blockSize;    // 剩余字节数

            // a. 读取完整块（每块 1440 字节 → 180 个 double）一次最多读取1440个字节超过需要分次读取
            for (int i = 0; i < count; i++) {
                rtn = NMC_GetCollectData(devHandle, (short)blockSize, buffer);
                System.out.println("devHandle: " + devHandle);
                System.out.println("blockSize: " + blockSize);
                System.out.println("buffer.length: " + buffer.length);
                checkResult(rtn, "NMC_GetCollectData");

                // 将 buffer 中的字节转换为 double[]，写入 data 的第 i*180 位置
                ByteBuffer.wrap(buffer)
                        .order(ByteOrder.LITTLE_ENDIAN)  // 注意：根据设备字节序选择，可能是 BIG_ENDIAN
                        .asDoubleBuffer()
                        .get(data, i * doublesPerBlock, doublesPerBlock);
            }

            // b. 读取剩余部分（如果有）
            if (remainder > 0) {
                rtn = NMC_GetCollectData(devHandle, (short)remainder, buffer);
                checkResult(rtn, "NMC_GetCollectData");
                System.out.println("devHandle: " + devHandle);
                System.out.println("blockSize: " + blockSize);
                System.out.println("buffer.length: " + buffer.length);
                // 只取前 remainder 字节，转换为对应的 double 数量
                int remainingDoubles = remainder / 8;
                if (remainingDoubles > 0) {
                    ByteBuffer.wrap(buffer, 0, remainder)
                            .order(ByteOrder.LITTLE_ENDIAN)
                            .asDoubleBuffer()
                            .get(data, count * doublesPerBlock, remainingDoubles);
                }
                // 如果 remainder 不是 8 的倍数，可能需要处理对齐问题（通常假设是）
            }

        } catch (Exception e) {
            System.err.println("Exception occurred: " + e.getMessage());
            e.printStackTrace();
            return -1;
        } finally {
            // 如果有 Close 接口，应在此释放句柄
            NMC_MtClose(pAxisHandle);
            NMC_DevClose(pDevHandle);
        }

        return 0;
    }


    public static void main(String[] args) {
        try {
            short result = gc_example();
            if (result == 0) {
                System.out.println("Data collection example completed successfully.");
            } else {
                 System.out.println("Data collection example completed with errors (code: " + result + ").");
            }
        } catch (Exception e) {
             System.err.println("An unexpected error occurred: " + e.getMessage());
             e.printStackTrace();
        }
    }
}